diff --git a/Encrypter.cpp b/Encrypter.cpp index 4ecb145..31c6d83 100644 --- a/Encrypter.cpp +++ b/Encrypter.cpp @@ -9,7 +9,7 @@ void encrypt_file(PIMAGE_NT_HEADERS nt_headers, pfile_info target_file, const ch for(int j = 0; j < sizeof(excluded_sections)/sizeof(excluded_sections[0]); ++j) excluded &= strcmp(excluded_sections[j], (char *)current_section->Name); if(excluded != 0) { - unsigned char *section_start = + unsigned char *section_start = (unsigned char *)target_file->file_mem_buffer + current_section->PointerToRawData; unsigned char *section_end = section_start + current_section->SizeOfRawData; const unsigned int num_rounds = 32; @@ -38,8 +38,8 @@ void encrypt(unsigned int num_rounds, unsigned int blocks[2], unsigned int const blocks[1] += (((blocks[0] << 4) ^ (blocks[0] >> 5)) + blocks[0]) ^ (sum + key[(sum >> 11) & 3]); } } - -//Unused, kept for testing/verification + +//For debug use void decrypt(unsigned int num_rounds, unsigned int blocks[2], unsigned int const key[4]) { const unsigned int delta = 0x9E3779B9; unsigned int sum = delta * num_rounds; diff --git a/Injector.cpp b/Injector.cpp index 0df4090..ecbdfcd 100644 --- a/Injector.cpp +++ b/Injector.cpp @@ -84,7 +84,7 @@ PIMAGE_SECTION_HEADER add_section(const char *section_name, unsigned int section PIMAGE_SECTION_HEADER last_section = IMAGE_FIRST_SECTION(nt_headers) + (nt_headers->FileHeader.NumberOfSections - 1); PIMAGE_SECTION_HEADER new_section = IMAGE_FIRST_SECTION(nt_headers) + (nt_headers->FileHeader.NumberOfSections); memset(new_section, 0, sizeof(IMAGE_SECTION_HEADER)); - new_section->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; + new_section->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_WRITE; memcpy(new_section->Name, section_name, name_max_length); new_section->Misc.VirtualSize = section_size; new_section->PointerToRawData = align_to_boundary(last_section->PointerToRawData + last_section->SizeOfRawData, diff --git a/README.md b/README.md index 913c857..b76049d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,10 @@ -# pe_infector -PE Infector/Cryptor source code - -From April 2011 - -http://www.codereversing.com/blog/archives/86 - -http://www.codereversing.com/blog/archives/92 - -http://www.codereversing.com/blog/archives/94 - -http://www.codereversing.com/blog/archives/95 - +# PEZEncrypt +A simple x86 PE packer + +## Features +* Easy and Simple +* Using SEH to detect hardware breakpoint +* Using SetUnhandledExceptionFilter to detect debugger +* Stub code checksum +* Using VirtualProtect to disable memory breakpoint +* Many small tricks to obfuscate the code \ No newline at end of file diff --git a/main.cpp b/main.cpp index 5ad564e..aaa856a 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include "Injector.h" @@ -15,51 +17,157 @@ __asm push eax \ __asm call strings_equal -#pragma code_seg(".inject") +#pragma code_seg(".pediy") + void __declspec(naked) injection_stub(void) { - __asm { //Prologue, stub entry point - pushad //Save context of entry point - push ebp //Set up stack frame - mov ebp, esp - sub esp, 0x200 //Space for local variables + //Fake pushad + BB(0x60) BB(0xE8) BB(0x03) BB(0x00) BB(0x00) BB(0x00) BB(0xE9) BB(0xEB) BB(0x05) BB(0x5D) BB(0x90) BB(0x45) BB(0x55) BB(0xC3) BB(0xE8) BB(0x01) BB(0x00) BB(0x00) + BB(0x00) BB(0xEB) BB(0xF8) BB(0x73) BB(0x01) BB(0xEB) BB(0x58) BB(0x8B) BB(0xC8) BB(0x83) BB(0xC0) BB(0x0F) BB(0x50) BB(0x51) BB(0xC3) BB(0xEB) BB(0x61) + __asm { //Prologue, stub entry point + sub esp, 0x30 //Save stack place for esp law + push ecx + push edi + push esi + call ExpHandle + mov edi, fs:[0] + pushad //Save context of entry point + push ebp + mov fs : [0], esp + add fs : [0], 0x4 + mov ebp, esp + sub esp, 0x200 //Space for local variables - } - PIMAGE_DOS_HEADER target_image_base; - PIMAGE_DOS_HEADER kernel32_image_base; - __asm { - call get_module_list //Get PEB - mov ebx, eax - push 0 - push ebx - call get_dll_base //Get image base of process - mov [target_image_base], eax - push 2 - push ebx - call get_dll_base //Get kernel32.dll image base - mov [kernel32_image_base], eax - } - __asm { //Decrypt all sections + } + PIMAGE_DOS_HEADER target_image_base; + PIMAGE_DOS_HEADER kernel32_image_base; + __asm { + call get_module_list //Get PEB + mov ebx, eax + push 0 + push ebx + call get_dll_base //Get image base of process + mov[target_image_base], eax + push 2 + push ebx + call get_dll_base //Get kernel32.dll image base + mov[kernel32_image_base], eax + } + __asm { + jmp stubback + push eax + push fs : [0] + mov fs : [0], esp + } + BB(0xEB) + stub: + __asm { + push ebp + mov ebp, esp + sub esp, 0x20 + fldz + fnstenv[esp - 0xC] + pop eax + mov esp, ebp + pop ebp + pop ebx + inc ebx + inc ebx + jmp ebx //ret addr+2 + } + //eax + 0xF + BB(0x6A) BB(0xAC) BB(0x8E) + BB(0xAA) BB(0xCD) BB(0x0D) BB(0x2C) BB(0xCD) BB(0x8C) BB(0x8D) BB(0xAC) BB(0x8C) + BB(0xA8) BB(0x0F) BB(0x6C) BB(0xAC) BB(0x0E) BB(0x8E) BB(0x2D) BB(0xED) BB(0xCD) + BB(0xC8) BB(0x2D) BB(0x8D) BB(0x8E) BB(0xAC) BB(0x4E) + BB(0) + BB(0x66) //Checksum stub + //toplevelhandler eax + 0xF + 0x1D + __asm { + push ebp + mov ebp, esp + sub esp, 0x200 + } + struct _EXCEPTION_POINTERS *ExceptionInfo; + DWORD DecAddr; + __asm { + mov eax, [ebp + 0x8] + mov ExceptionInfo, eax + call getjmpaddr + getjmpaddr : + pop eax + jmp getjmpaddrend + jmp epilogue + getjmpaddrend : + add eax, 0x3 + mov DecAddr, eax + } + if (ExceptionInfo->ContextRecord->Dr0 || ExceptionInfo->ContextRecord->Dr1 || ExceptionInfo->ContextRecord->Dr2 || ExceptionInfo->ContextRecord->Dr3) + { + DecAddr += ExceptionInfo->ContextRecord->Dr7; + } + ExceptionInfo->ContextRecord->Esp -= 4; + *(DWORD*)(ExceptionInfo->ContextRecord->Esp) = ExceptionInfo->ContextRecord->Eip + 2; + ExceptionInfo->ContextRecord->Eip = DecAddr; + __asm{ + mov esp, ebp + pop ebp + mov eax, EXCEPTION_CONTINUE_EXECUTION + ret 0x4 + } + stubback: + __asm{ + push 0 + } + BB(0xCD) + BB(0x3) + __asm { //Dummy Code + mov ecx, 0x23333 + l: + call get_module_list + inc eax + loop l + popad + } + BB(0xEB) + BB(0x2F) + BB(0xE8) + BB(0x56) + BB(0xFF) + __asm { //Decrypt all sections push kernel32_image_base push target_image_base - call decrypt_sections - } - //Any additional code can go here - __asm { //Epilogue, stub exit point - mov eax, target_image_base - add eax, 0xCCDDEEFF //Signature to be replaced by original entry point (OEP) - mov esp, ebp - mov [esp+0x20], eax //Store OEP in EAX through ESP to preserve across popad - pop ebp - popad //Restore thread context, with OEP in EAX - jmp eax //Jump to OEP } - + __asm{ + push 1 + int 3 + } + __asm{ //Dummy code + mov esp, ebp + pop ebp + popad + jmp section_name + cld + xor eax, eax + mov eax, [eax] + pushad + pushfd + } + BB(0xFF) + BB(0xCD) + BB(0xEB) + __asm{ + call decrypt_sections + push ebp + //int 0x2 + call epilogue + } + BB(0xE8) /////////////////////////////////////////////////////////////////// //Gets the module list //Preserves no registers, PEB_LDR_DATA->PPEB_LDR_DATA->InLoadOrderModuleList returned in EAX /////////////////////////////////////////////////////////////////// __asm { - get_module_list: + get_module_list: mov eax, fs:[0x30] //PEB mov eax, [eax+0xC] //PEB_LDR_DATA->PPEB_LDR_DATA mov eax, [eax+0xC] //PEB_LDR_DATA->PPEB_LDR_DATA->InLoadOrderModuleList @@ -75,10 +183,10 @@ void __declspec(naked) injection_stub(void) { get_dll_base: push ebp mov ebp, esp - cmp [ebp+0xC], 0x0 //Initial zero check - je done - mov ecx, [ebp+0xC] //Set loop index mov eax, [ebp+0x8] //PEB->PPEB_LDR_DATA->InLoadOrderModuleList address + mov ecx, [ebp+0xC] //Set loop index + cmp ecx, 0x0 //Initial zero check + je done traverse_list: mov eax, [eax] //Go to next entry loop traverse_list @@ -121,15 +229,43 @@ void __declspec(naked) injection_stub(void) { strings_equal: push ebp mov ebp, esp - mov eax, 0x0 //Assume unequal - cld //Forward comparison + + mov edi, [ebp+0xC] //EDI gets known_string + mov ecx, [ebp+0x10] //ECX gets known_string_length + cmp ecx, 0x0 + je comp + + restore_str: + mov al, [edi] + rol al, 0x3 + mov [edi], al + inc edi + loop restore_str + + comp: + mov ecx, [ebp+0x10] //ECX gets known_string_length + mov edi, [ebp+0xC] //EDI gets known_string mov esi, [ebp+0x8] //ESI gets check_string + cld //Forward comparison + repe cmpsb //Start comparing + mov esi, 0x0 //Assume unequal + jne end1 + mov esi, 0x1 //Strings equal + end1: mov edi, [ebp+0xC] //EDI gets known_string mov ecx, [ebp+0x10] //ECX gets known_string_length - repe cmpsb //Start comparing - jne end - mov eax, 0x1 //Strings equal - end: + cmp ecx, 0x0 + je end2 + + destore_str: + mov al, [edi] + rol al, 0x5 + mov [edi], al + inc edi + loop destore_str + + end2: + mov eax, esi mov esp, ebp pop ebp ret 0xC @@ -159,7 +295,7 @@ void __declspec(naked) injection_stub(void) { mov function_names_equal, 0x0 } kernel32_nt_headers = (PIMAGE_NT_HEADERS)((DWORD_PTR)kernel32_dos_header + kernel32_dos_header->e_lfanew); - kernel32_export_dir = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)kernel32_dos_header + + kernel32_export_dir = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)kernel32_dos_header + kernel32_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); for(unsigned long i = 0; i < kernel32_export_dir->NumberOfNames; ++i) { char *eat_entry = (*(char **)((DWORD_PTR)kernel32_dos_header + kernel32_export_dir->AddressOfNames + i * sizeof(DWORD_PTR))) @@ -180,9 +316,7 @@ void __declspec(naked) injection_stub(void) { ret 0x8 } /////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - //Decrypts all sections in the image, excluding .rdata/.rsrc/.inject + //Decrypts all sections in the image, excluding .rdata/.rsrc/.pediy //Call as void decrypt_sections(void *image_base, void *kernel32_base) /////////////////////////////////////////////////////////////////// decrypt_sections: @@ -230,7 +364,11 @@ void __declspec(naked) injection_stub(void) { call get_proc_address mov virtualprotect_addr, eax } - PIMAGE_NT_HEADERS target_nt_headers = (PIMAGE_NT_HEADERS)((DWORD_PTR)target_dos_header + target_dos_header->e_lfanew); + LPVOID ESp; + __asm mov ESp, esp + virtualprotect_addr(ESp, 0x400, PAGE_READWRITE, &old_protections); + PIMAGE_NT_HEADERS target_nt_headers; + target_nt_headers = (PIMAGE_NT_HEADERS)((DWORD_PTR)target_dos_header + target_dos_header->e_lfanew); for(unsigned long j = 0; j < target_nt_headers->FileHeader.NumberOfSections; ++j) { section_offset = (target_dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (sizeof(IMAGE_SECTION_HEADER) * j)); @@ -242,10 +380,10 @@ void __declspec(naked) injection_stub(void) { STRING_COMPARE(str_rsrc_name, section_header) __asm add section_names_equal, eax if(section_names_equal == 0) { - unsigned char *current_byte = + unsigned char *current_byte = (unsigned char *)((DWORD_PTR)target_dos_header + section_header->VirtualAddress); - unsigned char *last_byte = - (unsigned char *)((DWORD_PTR)target_dos_header + section_header->VirtualAddress + unsigned char *last_byte = + (unsigned char *)((DWORD_PTR)target_dos_header + section_header->VirtualAddress + section_header->SizeOfRawData); const unsigned int num_rounds = 32; const unsigned int key[4] = {0x12345678, 0xAABBCCDD, 0x10101010, 0xF00DBABE}; @@ -282,20 +420,242 @@ void __declspec(naked) injection_stub(void) { ret 0x8 } + BB(0xEB) + epilogue: + __asm { //Epilogue, stub exit point + pop ecx + mov eax, target_image_base + add eax, 0xCCDDEEFF //Signature to be replaced by original entry point (OEP) + mov esp, ebp + mov [esp+0x5C], eax //Store OEP + mov edi, [esp+0x4] //Restore fs:[0] + add esp, 0xC + pop ebp + mov ebx ,[esp+0x4] + mov edx, [esp+0x8] + mov ecx, [esp+0xC] + mov eax, [esp+0x12] + pop esp + mov fs:[0], edi + pop esi + pop edi + add esp, 0x30 + ret //Jump to OEP + } + ExpHandle: + __asm{ + call GetHAddr + jmp RealHandler + GetHAddr: + pop esi + ret + } + RealHandler: + __asm{ + pushad + push ebp + mov ebp, esp + sub esp, 0x200 + } + DWORD i; + EXCEPTION_RECORD* excrecord; + CONTEXT* conrecord; + DWORD start; + DWORD stop; + __asm { + mov eax, [esp+0x228] + mov excrecord, eax + mov eax, [esp+0x230] + mov conrecord, eax + } + + i = *(DWORD*) conrecord->Esp; + if(i==0) + { + BB(0x6A) + BB(0x01) //push 0x1 + BB(0xCD) + BB(0x03) // int 03 + BB(0x91) + BB(0x64) + BB(0x74) + BB(0xEB) + BB(0xFF) + BB(0x90) + BB(0x60) + BB(0x61) + BB(0xE9) + BB(0x12) + BB(0xCC) + BB(0x90) + BB(0xA4) + BB(0x64) + BB(0x64) + BB(0x33) + BB(0x21) + BB(0xF0) + BB(0xE8) + __asm { + call stub + error : + int 0x2 + push eax + add ebx, 0x10 + push ebx + call Checksum + xor eax, eax //Test + test eax, eax + jne error + } + __asm { + call get_module_list //Get PEB + push 2 + push eax + call get_dll_base //Get kernel32.dll image base + mov ecx, eax + call stub + rdtsc + add eax, 0xF + push eax + mov ebx, eax + push ecx + call get_proc_address + add ebx, 0x1D + push ebx + call eax + } + } + if(i==0x55AA) + { + __asm{ + //TODO + } + } + + i = 0x13; + __asm { + call ExpHandle + mov start, esi + jmp HandleEnd + } + BB(0xEB) + BB(0x74) //Checksum Handle + __asm{ + HandleEndback: + pop edi + mov stop, edi + } + i++; + __asm{ + mov eax, start + push eax + mov eax, stop + inc eax + push eax + call eax //Check + pop ebx + pop ebx + mov ebx, i + add eax, ebx + mov i, eax + } + + if (excrecord->ExceptionCode == EXCEPTION_BREAKPOINT) { + conrecord->Eip ^= conrecord->Dr0; + conrecord->Eip ^= conrecord->Dr1; + conrecord->Eip ^= conrecord->Dr2; + conrecord->Eip ^= conrecord->Dr3; + conrecord->Eip += i; + conrecord->Esp += 4; + __asm { + mov esp, ebp + pop ebp + popad + mov eax, ExceptionContinueExecution + ret + } + } + else + { + if(excrecord->ExceptionCode == STATUS_ACCESS_VIOLATION && excrecord->ExceptionInformation[1] != 0xFFFFFFFF && excrecord->ExceptionInformation[0] !=0) + conrecord->Eip += i + 0xC; + __asm { + mov esp, ebp + pop ebp + popad + mov eax, ExceptionContinueSearch + ret + } + } + __asm{ + HandleEnd: + call HandleEndback + } + BB(0xEB) + Checksum: + __asm { + push ebp + mov ebp, esp + sub esp, 0x200 + } + DWORD s; + DWORD ed; + DWORD counter; + __asm{ + mov eax, [ebp+0x8] + mov ed, eax + mov eax, [ebp+0xC] + mov s, eax + } + counter = ed - s; + __asm{ + mov ecx, counter; + inc ecx + xor eax, eax + mov edx, eax + mov eax, s + test edx, edx + je checkloop + } + BB(0xE8) + __asm{ + checkloop: + mov bl, cs:[eax] + xor dl, bl + inc eax + loop checkloop + xor edx, edx //for test + cmp edx, ecx + je loopdone + pop eax + pop ebx + mov start, ebx + inc eax + push eax + jmp HandleEndback + } + BB(0xEB) + __asm{ + loopdone: + mov esp, ebp + pop ebp + mov eax, edx + ret + } __asm { virtualprotect: call virtualprotectback - BB('V') BB('i') BB('r') BB('t') BB('u') BB('a') BB('l') - BB('P') BB('r') BB('o') BB('t') BB('e') BB('c') BB('t') BB(0) + BB(0xCA) BB(0x2D) BB(0x4E) BB(0x8E) BB(0xAE) BB(0x2C) BB(0x8D) + BB(0x0A) BB(0x4E) BB(0xED) BB(0x8E) BB(0xAC) BB(0x6C) BB(0x8E) BB(0) rdata_name: call rdata_nameback - BB('.') BB('r') BB('d') BB('a') BB('t') BB('a') BB(0) + BB(0xC5) BB(0x4E) BB(0x8C) BB(0x2C) BB(0x8E) BB(0x2C) BB(0) rsrc_name: call rsrc_nameback - BB('.') BB('r') BB('s') BB('r') BB('c') BB(0) + BB(0xC5) BB(0x4E) BB(0x6E) BB(0x4E) BB(0x6C) BB(0) section_name: call section_nameback - BB('.') BB('i') BB('n') BB('j') BB('e') BB('c') BB('t') BB(0) + BB(0xC5) BB(0x0E) BB(0xAC) BB(0x8C) BB(0x2D) BB(0x2F) BB(0) int 0x3 //Function signature int 0x3 int 0x3 @@ -303,7 +663,7 @@ void __declspec(naked) injection_stub(void) { } } #pragma code_seg() -#pragma comment(linker, "/SECTION:.inject,re") +#pragma comment(linker, "/SECTION:.pediy,re") wchar_t *convert_to_unicode(char *str, unsigned int length) { wchar_t *wstr; @@ -328,6 +688,10 @@ int main(int argc, char* argv[]) { printf("Could not convert %s to unicode\n", argv[1]); return -1; } + + CopyFile(target_file_name, L"packed.exe", FALSE); + target_file_name = L"packed.exe"; + pfile_info target_file = file_info_create(); void (*stub_addr)(void) = injection_stub; unsigned int stub_size = get_stub_size(stub_addr); @@ -340,7 +704,7 @@ int main(int argc, char* argv[]) { PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)target_file->file_mem_buffer; PIMAGE_NT_HEADERS nt_headers = (PIMAGE_NT_HEADERS)((DWORD_PTR)dos_header + dos_header->e_lfanew); stub_size_aligned = align_to_boundary(stub_size, nt_headers->OptionalHeader.SectionAlignment); - const char *section_name = ".inject"; + const char *section_name = ".pediy"; file_info_destroy(target_file); target_file = file_info_create(); (void)map_file(target_file_name, stub_size_aligned, true, target_file);