Jump to content
Nytro

[ASM] Simple PE Cryptor

Recommended Posts

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

Link to comment
Share on other sites

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...