Nytro Posted April 6, 2011 Report Posted April 6, 2011 Simple PE CryptorDemonstrate how to encrypt code and data section of any PE file. Full source code included. This is a very rough beta.include w32.incinclude console.incinclude message.incinclude imghdr.incextrn GetSystemTime:procextrn VirtualAlloc:procextrn VirtualFree:proc.DATAfile_hnd dd 0 ; handle to opened filemem_offset dd 0 ; address of allocated memoryobj_offset dd 0 ; address of import tablepeh_offset dd 0 ; address of pe headercurr_disp dd 0 ; displacementrsrc_count dd 0 ; number of resource typesnum_rsrc dd 0 ; total number of resourcesrsrc_head dd 0 ; size of resourse headersys_time SYSTEMTIME <0> ; used in getsystimepe_h IMAGE_NT_HEADERS <0> ; pe header strucobj_table IMAGE_SECTION_HEADER 0Fh dup (<0>) ; section table strucheader_len equ size pe_h + size obj_table ; length of headerdecryptor_len equ decryptor_end - decryptor_start ; lenght of decryptorit_len equ it_end - k32_original ; length of import table inside decryptorcrypt_flag db 00,10,13 ; for stat displaynew_section:obj_name db '.hayras',0 ; section namevirt_size dd 0 ; virtual sizevirt_addr dd 0 ; rvaraw_size dd 0 ; size of fileraw_offset dd 0 ; offset in fileunused dd 0,0,0 ; othersobj_flags dd 0E0000020h ; flag (r/w/c/x).CODEstart:; ----- 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_fileno_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 counternext_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 eaxsection_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 eaxfile_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 eaxsect_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 eaximage_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_hndnot_valid_pe: push not_pe_l push offset not_pe call write_console jmp close_hndfile_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 CloseHandlequit: 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 retendp;------------------------------------------------------------------------------ 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 retendp;------------------------------------------------------------------------------ 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 proceedset_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 rootnext_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, 10hnext_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 ecxnot_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, keyres_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 keyencrypt: 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 displayno_encrypt: popa retencrypt_objects endp.DATA;------------------------------------------------------------------------------decryptor_start: db '[SPEC]' call delta ; get delta offsetdelta: 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 deltanext_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 tablenext_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_loadedexit_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 ExitProcessdll_loaded: mov [dll_hnd+ebp], eax ; save handle mov [func_disp+ebp], 0 ; initialize displacementnext_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 thunkhint_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 ordinalfunc_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_functionfunction_end: add esi, 14h ; next import descriptor mov edx, [image_base+ebp] ; image base again jmp next_dlldll_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 4k32_original dd func_k32-k32_original ; original first thunk dd 0,0 ; time/date, forwarderk32_dll dd k32-k32_original ; rva to dll namek32_first dd getproc-k32_original ; first thunku32_original dd func_u32-k32_original ; same as above, for user32 dd 0,0u32_dll dd u32-k32_originalu32_first dd msgbox-k32_original dd 5 dup (0) ; terminate import descriptork32 db 'KERNEL32.DLL',0 ; dll to loadfunc_k32 dd function1-k32_original ; rva's to function names dd function2-k32_original dd function3-k32_original dd function4-k32_original,0u32 db 'USER32.DLL',0func_u32 dd function5-k32_original,0getproc dd 0 ; the iatgetmod dd 0 ; the loader patchesloadlib dd 0 ; this areaexitproc dd 0 ;msgbox dd 0 dd 0 ; terminatorfunction1 db 0,0,'GetProcAddress',0 ; function namesfunction2 db 0,0,'GetModuleHandleA',0function3 db 0,0,'LoadLibraryA',0function4 db 0,0,'ExitProcess',0function5 db 0,0,'MessageBoxA',0 align 4it_end:cap_addr dd caption-k32_original ; offset to captionmsg_addr dd message-k32_original ; offset to messagecaption db 'error',0 ; generic messagemessage db 'loader failed', 0key db 0dll_hnd dd 0 ; handle to loaded dllfunc_disp dd 0 ; displacement in function name & iatit_address dd 0 ; rva of original import sectiondecr_rva dd 0 ; rva of the decryptorimage_base dd 0 ; image basenum_objects db 0 ; number of encrypted sectionsoriginal_erva dd 0 ; entry point rvaobject_rva dd 0 ; rva/size of encrypted sectionsobject_size dd 0 dd 20h dup (0)decryptor_end:;------------------------------------------------------------------------------end startDownload:http://win32assembly.online.fr/files/spec.zip Quote