Nytro Posted April 6, 2011 Report Share 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 Link to comment Share on other sites More sharing options...