Jump to content
Nytro

[ASM] Simple PE Cryptor

Recommended Posts

Posted

Simple PE Cryptor

Demonstrate how to encrypt code and data section of any PE file. Full source code included. This is a very rough beta.

include w32.inc

include console.inc

include message.inc

include imghdr.inc



extrn GetSystemTime:proc

extrn VirtualAlloc:proc

extrn VirtualFree:proc



.DATA



file_hnd dd 0 ; handle to opened file

mem_offset dd 0 ; address of allocated memory

obj_offset dd 0 ; address of import table

peh_offset dd 0 ; address of pe header

curr_disp dd 0 ; displacement

rsrc_count dd 0 ; number of resource types

num_rsrc dd 0 ; total number of resources

rsrc_head dd 0 ; size of resourse header



sys_time SYSTEMTIME <0> ; used in getsystime

pe_h IMAGE_NT_HEADERS <0> ; pe header struc

obj_table IMAGE_SECTION_HEADER 0Fh dup (<0>) ; section table struc



header_len equ size pe_h + size obj_table ; length of header

decryptor_len equ decryptor_end - decryptor_start ; lenght of decryptor

it_len equ it_end - k32_original ; length of import table inside decryptor



crypt_flag db 00,10,13 ; for stat display



new_section:



obj_name db '.hayras',0 ; section name

virt_size dd 0 ; virtual size

virt_addr dd 0 ; rva

raw_size dd 0 ; size of file

raw_offset dd 0 ; offset in file

unused dd 0,0,0 ; others

obj_flags dd 0E0000020h ; flag (r/w/c/x)



.CODE

start:



; ----- show intro ------------------------------------------------------------



call init_console ; initialize console



push logo_l ; show this message

push offset logo ;

call write_console ; write to screen



; ----- get command line ------------------------------------------------------



call GetCommandLineA

mov edi,eax ; address of name

mov ecx, -1 ; counter

mov al, 0 ; search byte

push edi ; save for later

repnz scasb ; search for end of name

not ecx ; number of bytes read

pop edi ; address of name

mov al, 20h ; search byte

repnz scasb ; get length of file name

dec ecx ; skip extra space

test ecx,ecx ; something there

jnz open_file



no_commandline:



push no_cmd_l

push offset no_cmd

call write_console



jmp quit



; ----- open file -------------------------------------------------------------



open_file:



push 0 ; hTemplateFile

push FILE_ATTRIBUTE_NORMAL ; dwFlagsAndAttribute

push OPEN_EXISTING ; dwCreationDistribution

push 0 ; lpSecurityAttribtes

push 0 ; dwShareMode

push GENERIC_READ + GENERIC_WRITE ; dwDesiredAccess

push edi ; lpFileName

call CreateFile



cmp eax, INVALID_HANDLE_VALUE ; returned file handle

jz file_not_found



mov file_hnd, eax ; save file handle



; ----- get offset of pe header -----------------------------------------------



push FILE_BEGIN ; start of file

push 0 ; lpDistanceToMoveHigh

push 3Ch ; number of bytes to move (location of offset to pe header)

push file_hnd ; handle of file

call SetFilePointer



push 0 ; lpOverlapped

push offset bytes_read ; address of number of bytes read

push 4 ; number of bytes to read

push offset peh_offset ; address to store bytes read (offset to pe header)

push file_hnd ; handle of file

call ReadFile



; ----- read header to pe struc -----------------------------------------------



push 0

push 0

push peh_offset

push file_hnd

call SetFilePointer



push 0

push offset bytes_read

push header_len

push offset pe_h

push file_hnd

call ReadFile



; ----- check pe signature ----------------------------------------------------



cmp [pe_h.Signature], IMAGE_NT_SIGNATURE ; check for 'PE'

jnz not_valid_pe



call show_some_info ; display some stats



; ----- get offset to object table --------------------------------------------



movzx eax, [pe_h.SizeOfOptionalHeader] ; size of optional header

add eax, 18h ; offset to object table

mov obj_offset, eax



; ----- check for space in object table ---------------------------------------



movzx eax, [pe_h.NumberOfSections] ; number of sections

inc eax ; add 1 for new section

mov ecx, 28h ; size of section

mul ecx ; num sections * 28h

add eax, obj_offset ; offset of object table

add eax, peh_offset ; offset to pe header

cmp eax, [pe_h.SizeOfHeaders]

jg no_space



; ----- store rva of import section -------------------------------------------



mov eax, [pe_h.DataDirectory.(8).VirtualAddress]

mov it_address, eax



; ----- generate encryption key -----------------------------------------------



push offset sys_time ; SYSTEMTIME struc

call GetSystemTime



movzx ax, [sys_time.st_wMilliseconds] ; get millisecond

mov key, al ; save as encryption key



; ----- encrypt objects -------------------------------------------------------



push sec_label_l ; header for section display

push offset sec_label

call write_console



mov esi, offset obj_table ; start of section table

movzx ecx, [pe_h.NumberOfSections] ; number of section as counter



next_obj:



call encrypt_objects ; encrypt each section

call show_stats ; display some stats



add esi, 28h ; next section in table



loop next_obj



; ----- locate/add decryptor object in table ----------------------------------



mov esi, offset obj_table ; start of section table

movzx eax, [pe_h.NumberOfSections] ; number of sections

mov ecx, 28h ; size of section header

mul ecx ; number of section * 28h

add esi, eax ; end of section header

inc [pe_h.NumberOfSections] ; add our section

mov edi, offset new_section

xchg edi, esi



; ----- calculate rva (aligned) -----------------------------------------------



mov eax, [edi-28h+8] ; (rva+size)/align

add eax, [edi-28h+0Ch]

mov ecx, [pe_h.SectionAlignment]

cdq

div ecx

test edx, edx

jz section_aligned

inc eax



section_aligned:



mul ecx

mov virt_addr, eax

mov decr_rva, eax



; ----- calculate raw data size (aligned) -------------------------------------



mov eax, decryptor_len

mov ecx, [pe_h.FileAlignment]

div ecx

test edx, edx

jz file_aligned

inc eax



file_aligned:



mul ecx

mov [raw_size], eax



; ----- calculate virtual size (aligned) --------------------------------------



mov eax, decryptor_len

mov ecx, [pe_h.SectionAlignment]

div ecx

test edx, edx

jz sect_aligned

inc eax



sect_aligned:



mul ecx

mov virt_size, eax



; ----- calculate file offset -------------------------------------------------



mov eax, [edi-28h+14h]

add eax, [edi-28h+10h]

mov raw_offset, eax



; ----- calculate rva/size of import section ----------------------------------



mov eax, k32_original-decryptor_start

add eax, decr_rva ; add rva or decryptor

mov [pe_h.DataDirectory.(8).VirtualAddress], eax ; it rva in data dir

mov [pe_h.DataDirectory.(8).Size], it_len ; it size



add dword ptr k32_original, eax ; convert to rva

add dword ptr k32_dll, eax ;

add dword ptr k32_first, eax ;

add dword ptr func_k32, eax ;

add dword ptr [func_k32+4], eax ;

add dword ptr [func_k32+8], eax ;

add dword ptr [func_k32+0Ch], eax ;

add dword ptr getproc, eax ;

add dword ptr getmod, eax ;

add dword ptr loadlib, eax ;

add dword ptr u32_original, eax ;

add dword ptr u32_dll, eax ;

add dword ptr u32_first, eax ;

add dword ptr func_u32, eax ;

add dword ptr msgbox, eax ;

add dword ptr cap_addr, eax ;

add dword ptr msg_addr, eax ;



; ----- adjust size of image (aligned) ----------------------------------------



mov eax, virt_size

add eax, [pe_h.SizeOfImage]

mov ecx, [pe_h.SectionAlignment]

div ecx

test edx, edx

jz image_aligned

inc eax



image_aligned:



mul ecx

mov [pe_h.SizeOfImage], eax



; ----- copy data to decryptor section ----------------------------------------



mov ecx, 28h

rep movsb



; ----- store new entry point rva ---------------------------------------------



mov eax, dword ptr virt_addr

mov ebx, dword ptr [pe_h.AddressOfEntryPoint]

mov [pe_h.AddressOfEntryPoint], eax

mov original_erva, ebx



; ----- rewrite header -------------------------------------------------------



push 0

push 0

push peh_offset

push file_hnd

call SetFilePointer



push 0

push offset bytes_read

push header_len

push offset pe_h file_hnd

call WriteFile



; ----- write decryptor ------------------------------------------------------



push 0

push 0

push raw_offset

push file_hnd

call SetFilePointer



push 0

push offset bytes_read

push raw_size

push offset decryptor_start

push file_hnd

call WriteFile



push done_l

push offset done

call write_console



jmp close_hnd



; ----- some error messages --------------------------------------------------



no_space:



push no_o_space_l

push offset no_o_space

call write_console

jmp close_hnd



not_valid_pe:



push not_pe_l

push offset not_pe

call write_console

jmp close_hnd



file_not_found:



push file_nf_l

push offset file_nf

call write_console

jmp quit



; ----- finished, lets close -------------------------------------------------



close_hnd:



push file_hnd ; handle of file

call CloseHandle



quit:



push 0

call ExitProcess



;------------------------------------------------------------------------------

show_some_info proc

;------------------------------------------------------------------------------



mov eax, [pe_h.SizeOfCode]

push eax eax

movzx eax, [pe_h.NumberOfSections]

push eax offset num_secs

call write_hex



mov eax, [pe_h.SizeOfInitializedData]

push eax eax

mov eax, [pe_h.ImageBase]

push eax offset img_base

call write_hex



mov eax, [pe_h.SizeOfUninitializedData]

push eax eax

mov eax, [pe_h.AddressOfEntryPoint]

push eax offset ep_rva

call write_hex



mov eax, [pe_h.SectionAlignment]

push eax eax

mov eax, [pe_h.SizeOfImage]

push eax offset size_img

call write_hex



mov eax, [pe_h.FileAlignment]

push eax eax

mov eax, [pe_h.SizeOfHeaders]

push eax offset size_head

call write_hex



movzx eax, [pe_h.MinorLinkerVersion]

push eax

movzx eax, [pe_h.MajorLinkerVersion]

push eax

mov eax, [pe_h.BaseOfCode]

push eax offset base_code

call write_hex



movzx eax, [pe_h.DllCharacteristics]

push eax eax

mov eax, [pe_h.BaseOfData]

push eax offset base_data

call write_hex



ret

endp



;------------------------------------------------------------------------------

show_stats proc

;------------------------------------------------------------------------------



push 8 esi

call write_console



push dword ptr [esi.SVirtualSize]

push dword ptr [esi.SVirtualAddress]

push dword ptr [esi.SizeOfRawData]

push dword ptr [esi.PointerToRawData]

push dword ptr [esi.SFlags]

push offset sec_status

call write_stat



push 3 offset crypt_flag

call write_console



ret

endp



;------------------------------------------------------------------------------

encrypt_objects proc

;------------------------------------------------------------------------------



pusha



cmp [esi], 'adr.' ; skip .rdata

jz set_flag

cmp [esi], 'ade.' ; skip .edata

jz set_flag

cmp [esi], 'ler.' ; skip .reloc

jz set_flag

cmp [esi], 'slt.' ; skip .tls

jz set_flag

cmp dword ptr [esi.SizeOfRawData], 0

jz set_flag



jmp proceed



set_flag:



mov crypt_flag, ' '

jmp no_encrypt



; ----- allocate memory -------------------------------------------------------



proceed:



push PAGE_READWRITE

push MEM_COMMIT

push [esi.SizeOfRawData]

push 0

call VirtualAlloc



mov mem_offset, eax



; ----- read section to encrypt -----------------------------------------------



push 0

push 0

push [esi.PointerToRawData]

push file_hnd

call SetFilePointer



push 0

push offset bytes_read

push [esi.SizeOfRawData]

push mem_offset

push file_hnd

call ReadFile



cmp [esi], 'rsr.'

jnz not_rsrc



; ----- resource routine ------------------------------------------------------



mov edi, mem_offset ; start of rsrc buffer

mov edx, mem_offset



movzx ecx, word ptr [edi.IRD_NumberOfNamedEntries] ; rsrc with names

add cx, [edi.IRD_NumberOfIdEntries] ; rsrc with id

mov rsrc_count, ecx ; number or rsrc type

add edx, 10h ; skip root



next_resource: ; num rsrc type as counter



mov eax, [edx+4] ; offset to subdir

and eax, 0FFFFFFFh ; mask offset

add eax, edi ; address of subdir

movzx ebx, word ptr [eax.IRD_NumberOfNamedEntries]

add bx, [eax.IRD_NumberOfIdEntries]

add num_rsrc, ebx

cmp [eax.IRD_NumberOfNamedEntries], 0

jz not_named

push ecx eax

movzx ecx, [eax.IRD_NumberOfNamedEntries]

add eax, 10h



next_entry:



movzx ebx, word ptr [eax]

add ebx, edi

movzx ebx, word ptr [ebx]

imul ebx, 2

add ebx, 2

add rsrc_head, ebx

add eax, 8

loop next_entry

pop eax ecx



not_named:



add edx, 8 ; next resource type

loop next_resource



mov ecx, 30h

mov eax, num_rsrc ; total number of resources

mul ecx ; 30h * num of res

add rsrc_head, eax

mov ecx, 18h

mov eax, rsrc_count ; 18h * number of res type

mul ecx

add rsrc_head, eax ; add em both

add rsrc_head, 10h ; add size of main struc

mov eax, rsrc_head ; length of resource header

add mem_offset, eax ; skip the res header



mov edi, mem_offset

mov ecx, [esi.SizeOfRawData] ; size as counter

sub ecx, [rsrc_head]



mov al, key



res_encrypt:



sub byte ptr [edi], al ; encrypt

inc al

inc edi ; next byte

loop res_encrypt



mov eax, [esi.PointerToRawData] ; get file offset

add eax, rsrc_head ; skip resource header



push 0

push 0

push eax

push file_hnd

call SetFilePointer



mov eax, [esi.SizeOfRawData]

sub eax, rsrc_head ; skip resource header



push 0

push offset bytes_read

push eax

push mem_offset

push file_hnd

call WriteFile ; write it



mov edi, [curr_disp]

mov eax, [esi+SVirtualAddress]

add eax, rsrc_head ; skip resource header

mov [object_rva+edi], eax ; save rva to decryptor



mov eax, [esi.SizeOfRawData]

sub eax, rsrc_head ; dont include rsrc header

mov [object_size+edi], eax ; save size to decryptor



jmp release_mem



; ----- store rva/size to decryptor -------------------------------------------



not_rsrc:





mov edi, [curr_disp]

mov eax, [esi+SVirtualAddress]

mov [object_rva+edi], eax ; save rva to decryptor



mov eax, [esi.SizeOfRawData]

mov [object_size+edi], eax ; save size to decryptor



mov edi, mem_offset ; start of buffer

mov ecx, [esi.SizeOfRawData] ; size as counter

mov al, key ; get key



encrypt:



sub byte ptr [edi], al ; encrypt

inc al

inc edi ; next byte

loop encrypt



; ----- write encrypted section -----------------------------------------------



push 0

push 0

push [esi.PointerToRawData] ; point to

push file_hnd

call SetFilePointer



push 0

push offset bytes_read

push [esi.SizeOfRawData] ; size

push mem_offset ; start here

push file_hnd

call WriteFile



; ----- deallocate memory -----------------------------------------------------



release_mem:



push MEM_DECOMMIT ; fdwFreeType

push [esi.SizeOfRawData] ; cbSize

push mem_offset ; lpvAddress

call VirtualFree



;----- update flags/number of objects -----------------------------------------



add [curr_disp], 8 ; update displacement

inc byte ptr num_objects ; update counter

or [esi.SFlags], 80000000h ; enable write bit

mov crypt_flag, 0FBh ; for stat display



no_encrypt:



popa



ret



encrypt_objects endp



.DATA

;------------------------------------------------------------------------------



decryptor_start:



db '[SPEC]'



call delta ; get delta offset



delta:

pop ebp



mov eax, ebp ; save for imagebase calculation

sub ebp, offset delta ; ebp = delta offset



sub eax, [decr_rva+ebp] ; decryptor rva

sub eax, offset delta-decryptor_start ; calculate current imagebase

mov [image_base+ebp], eax ; store for later

movzx esi, [num_objects+ebp] ; number of sections (use as counter)

mov edi, ebp ; save delta



next_object:



mov ebx, [image_base+ebp] ; imagebase

mov eax, [object_rva+edi] ; rva of encrypted section

add ebx, eax ; imagebase+rva=address of section

mov ecx, [object_size+edi] ; size of section (use as counter)

mov al, [key+ebp]



decrypt:



add byte ptr [ebx], al ; decrypt

inc al

inc ebx ; next byte

loop decrypt

add edi, 8 ; next section

dec esi ; dec section count

jnz next_object ; until no more sections



; ----- fix import section ----------------------------------------------------



mov edx, [image_base+ebp] ; get image base

mov esi, [it_address+ebp] ; rva of original import table

add esi, edx ; address of import table



next_dll:



mov eax, [esi+0Ch] ; rva of dll name

or eax, eax ; dll name present?

jz dll_end

add eax, edx ; address of dll name

mov ebx, eax ; save for loadlibrary

push eax ; push dll name

call [getmod+ebp] ; call GetModuleHandleA

or eax, eax ; loaded?

jnz dll_loaded

push ebx ; push dll name

call [loadlib+ebp] ; call LoadLibrary

or eax, eax ; success?

jnz dll_loaded



exit_loader:



mov edx, [image_base+ebp] ; get imagebase

add [cap_addr+ebp], edx ; add to offset

add [msg_addr+ebp], edx

push 0 ; null

push [cap_addr+ebp] ; caption

push [msg_addr+ebp] ; message

push 0 ; mb ok

call [msgbox+ebp] ; call MessageBoxA

push 0

call [exitproc+ebp] ; call ExitProcess



dll_loaded:



mov [dll_hnd+ebp], eax ; save handle

mov [func_disp+ebp], 0 ; initialize displacement



next_function:



mov edx, [ebp+image_base] ; imagebase

mov eax, [esi] ; original first thunk (rva)

or eax, eax ; is it there?

jnz hint_ok

mov eax, [esi+10h] ; no, then check out first thunk



hint_ok:



add eax, edx ; offset to function name

add eax, [func_disp+ebp] ; displacement (first thunk)

mov ebx, [eax] ; rva to function name

mov edi, [esi+10h] ; first thunk (iat)

add edi, edx ; address of iat

add edi, [func_disp+ebp] ; displacement (iat)

test ebx, ebx ; function present?

jz function_end

test ebx, 80000000h ; test for ordinal bit

jnz func_ordinal ; if present, then function is ordinal only

add ebx, edx ; address of function name

add ebx, 2 ; skip ordinal



func_ordinal:



and ebx, 0FFFFFFFh

push ebx ; offset of function name or ordinal

push dword ptr [ebp+dll_hnd] ; handle of dll

call [getproc+ebp] ; call GetpProcAddress

or eax, eax

jz exit_loader

mov [edi], eax ; store address to iat

add [func_disp+ebp], 4 ; update displacement

jmp next_function



function_end:



add esi, 14h ; next import descriptor

mov edx, [image_base+ebp] ; image base again

jmp next_dll



dll_end:



mov eax, [original_erva+ebp] ; original entry point rva

add eax, [image_base+ebp] ; add imagebase



jmp eax ; jump to original entry point



;------------------------------------------------------------------------------

align 4



k32_original dd func_k32-k32_original ; original first thunk

dd 0,0 ; time/date, forwarder

k32_dll dd k32-k32_original ; rva to dll name

k32_first dd getproc-k32_original ; first thunk

u32_original dd func_u32-k32_original ; same as above, for user32

dd 0,0

u32_dll dd u32-k32_original

u32_first dd msgbox-k32_original

dd 5 dup (0) ; terminate import descriptor

k32 db 'KERNEL32.DLL',0 ; dll to load

func_k32 dd function1-k32_original ; rva's to function names

dd function2-k32_original

dd function3-k32_original

dd function4-k32_original,0

u32 db 'USER32.DLL',0

func_u32 dd function5-k32_original,0

getproc dd 0 ; the iat

getmod dd 0 ; the loader patches

loadlib dd 0 ; this area

exitproc dd 0 ;

msgbox dd 0

dd 0 ; terminator

function1 db 0,0,'GetProcAddress',0 ; function names

function2 db 0,0,'GetModuleHandleA',0

function3 db 0,0,'LoadLibraryA',0

function4 db 0,0,'ExitProcess',0

function5 db 0,0,'MessageBoxA',0



align 4

it_end:

cap_addr dd caption-k32_original ; offset to caption

msg_addr dd message-k32_original ; offset to message

caption db 'error',0 ; generic message

message db 'loader failed', 0

key db 0

dll_hnd dd 0 ; handle to loaded dll

func_disp dd 0 ; displacement in function name & iat

it_address dd 0 ; rva of original import section

decr_rva dd 0 ; rva of the decryptor

image_base dd 0 ; image base

num_objects db 0 ; number of encrypted sections

original_erva dd 0 ; entry point rva

object_rva dd 0 ; rva/size of encrypted sections

object_size dd 0

dd 20h dup (0)



decryptor_end:



;------------------------------------------------------------------------------

end start



Download:

http://win32assembly.online.fr/files/spec.zip

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...