diff --git a/hldr32/hldr32.asm b/hldr32/hldr32.asm index a00c899..87f0aba 100644 --- a/hldr32/hldr32.asm +++ b/hldr32/hldr32.asm @@ -22,10 +22,8 @@ hldr_begin: ;API CRC table, null terminated ;----------------------------------------------------------------------------- - dd 0E9258E7Ah ;FlushInstructionCache dd 0C97C1FFFh ;GetProcAddress dd 03FC1BD8Dh ;LoadLibraryA - dd 009CE0D4Ah ;VirtualAlloc db 0 ;----------------------------------------------------------------------------- @@ -84,49 +82,16 @@ crc_skip: jnz walk_names ;----------------------------------------------------------------------------- -;allocate memory for mapping +;save the pointers to the PE structure ;----------------------------------------------------------------------------- mov esi, dword [esp + krncrcstk_size + 20h + 4] mov ebp, dword [esi + lfanew] add ebp, esi - mov ch, (MEM_COMMIT | MEM_RESERVE) >> 8 - push PAGE_EXECUTE_READWRITE - push ecx - push dword [ebp + _IMAGE_NT_HEADERS.nthOptionalHeader + _IMAGE_OPTIONAL_HEADER.ohSizeOfImage] - push 0 - call dword [esp + 10h + krncrcstk.kVirtualAlloc] - push eax - mov ebx, esp -;----------------------------------------------------------------------------- -;map MZ header, NT Header, FileHeader, OptionalHeader, all section headers... -;----------------------------------------------------------------------------- - - mov ecx, dword [ebp + _IMAGE_NT_HEADERS.nthOptionalHeader + _IMAGE_OPTIONAL_HEADER.ohSizeOfHeaders] - mov edi, eax push esi - rep movsb - pop esi - -;----------------------------------------------------------------------------- -;map sections data -;----------------------------------------------------------------------------- - - mov cx, word [ebp + _IMAGE_NT_HEADERS.nthFileHeader + _IMAGE_FILE_HEADER.fhSizeOfOptionalHeader] - lea edx, dword [ebp + ecx + _IMAGE_NT_HEADERS.nthOptionalHeader] - mov cx, word [ebp + _IMAGE_NT_HEADERS.nthFileHeader + _IMAGE_FILE_HEADER.fhNumberOfSections] - xchg edi, eax - -map_section: - pushad - add esi, dword [edx + _IMAGE_SECTION_HEADER.shPointerToRawData] - add edi, dword [edx + _IMAGE_SECTION_HEADER.shVirtualAddress] - mov ecx, dword [edx + _IMAGE_SECTION_HEADER.shSizeOfRawData] - rep movsb - popad - add edx, _IMAGE_SECTION_HEADER_size - loop map_section + mov ebx, esp + mov edi, esi ;----------------------------------------------------------------------------- ;import DLL @@ -242,11 +207,6 @@ reloc_abs: ;----------------------------------------------------------------------------- xor ecx, ecx - push ecx - push ecx - dec ecx - push ecx - call dword [ebx + mapstk_size + krncrcstk.kFlushInstructionCache] mov eax, dword [ebp + _IMAGE_NT_HEADERS.nthOptionalHeader + _IMAGE_OPTIONAL_HEADER.ohAddressOfEntryPoint] add eax, dword [ebx] call eax diff --git a/hldr32/hldr32.inc b/hldr32/hldr32.inc index c2c18dc..e8f8036 100644 --- a/hldr32/hldr32.inc +++ b/hldr32/hldr32.inc @@ -24,10 +24,8 @@ struc mapstk endstruc struc krncrcstk -.kVirtualAlloc: resd 1 .kLoadLibraryA: resd 1 .kGetProcAddress: resd 1 -.kFlushInstructionCache: resd 1 endstruc struc _IMAGE_FILE_HEADER diff --git a/hldr64/hldr64.asm b/hldr64/hldr64.asm index ac49c0d..333e71c 100644 --- a/hldr64/hldr64.asm +++ b/hldr64/hldr64.asm @@ -29,10 +29,9 @@ regstksize equ 30h lodsq mov rbp, qword [rax + mDllBase] call parse_exports - dd 0E9258E7Ah ;FlushInstructionCache + dd 0C97C1FFFh ;GetProcAddress dd 03FC1BD8Dh ;LoadLibraryA - dd 009CE0D4Ah ;VirtualAlloc db 0 ;----------------------------------------------------------------------------- @@ -104,51 +103,15 @@ crc_skip: and rsp, -10h ;align on 16-byte boundary ;----------------------------------------------------------------------------- -;allocate memory for mapping +;save the pointers to the PE structure ;----------------------------------------------------------------------------- mov rsi, qword [rbx + mapstk_size + krncrcstk_size + regstksize + 8] mov ebp, dword [rsi + lfanew] add rbp, rsi - push PAGE_EXECUTE_READWRITE - pop r9 - mov r8d, MEM_COMMIT | MEM_RESERVE - mov edx, dword [rbp + _IMAGE_NT_HEADERS.nthOptionalHeader + _IMAGE_OPTIONAL_HEADER.ohSizeOfImage] - call qword [rbx + mapstk_size + krncrcstk.kVirtualAlloc] - mov qword [rbx], rax - -;----------------------------------------------------------------------------- -;map MZ header, NT Header, FileHeader, OptionalHeader, all section headers... -;----------------------------------------------------------------------------- - - mov ecx, dword [rbp + _IMAGE_NT_HEADERS.nthOptionalHeader + _IMAGE_OPTIONAL_HEADER.ohSizeOfHeaders] - push rax - pop rdi - push rsi - rep movsb - pop rsi - -;----------------------------------------------------------------------------- -;map sections data -;----------------------------------------------------------------------------- - - mov cx, word [rbp + _IMAGE_NT_HEADERS.nthFileHeader + _IMAGE_FILE_HEADER.fhSizeOfOptionalHeader] - lea rdx, qword [rbp + rcx + _IMAGE_NT_HEADERS.nthOptionalHeader] - mov cx, word [rbp + _IMAGE_NT_HEADERS.nthFileHeader + _IMAGE_FILE_HEADER.fhNumberOfSections] - -map_section: - push rcx - push rsi - mov ecx, dword [rdx + _IMAGE_SECTION_HEADER.shPointerToRawData] - add rsi, rcx - mov edi, dword [rdx + _IMAGE_SECTION_HEADER.shVirtualAddress] - add rdi, rax - mov ecx, dword [rdx + _IMAGE_SECTION_HEADER.shSizeOfRawData] - rep movsb - pop rsi - pop rcx - add rdx, _IMAGE_SECTION_HEADER_size - loop map_section + mov rax, rsi + mov qword [rbx], rsi + mov rdi, rsi ;----------------------------------------------------------------------------- ;import DLL @@ -239,11 +202,6 @@ reloc_finished: ;----------------------------------------------------------------------------- ;call entrypoint ;----------------------------------------------------------------------------- - - xor r8, r8 - xor edx, edx - or ecx, -1 - call qword [rbx + mapstk_size + krncrcstk.kFlushInstructionCache] mov eax, dword [rbp + _IMAGE_NT_HEADERS.nthOptionalHeader + _IMAGE_OPTIONAL_HEADER.ohAddressOfEntryPoint] add rax, qword [rbx] call rax diff --git a/hldr64/hldr64.inc b/hldr64/hldr64.inc index c2736c2..3a6c624 100644 --- a/hldr64/hldr64.inc +++ b/hldr64/hldr64.inc @@ -26,10 +26,8 @@ struc mapstk endstruc struc krncrcstk -.kVirtualAlloc: resq 1 .kLoadLibraryA: resq 1 .kGetProcAddress: resq 1 -.kFlushInstructionCache: resq 1 endstruc struc _IMAGE_FILE_HEADER diff --git a/pe2shc/main.cpp b/pe2shc/main.cpp index b7cb294..57ae5d0 100644 --- a/pe2shc/main.cpp +++ b/pe2shc/main.cpp @@ -58,7 +58,7 @@ bool has_tls_callbacks(BYTE *my_exe, size_t exe_size) { IMAGE_DATA_DIRECTORY* tls_dir = peconv::get_directory_entry(my_exe, IMAGE_DIRECTORY_ENTRY_TLS); if (!tls_dir) return false; - + IMAGE_TLS_DIRECTORY* tls = peconv::get_type_directory((HMODULE)my_exe, IMAGE_DIRECTORY_ENTRY_TLS); if (!tls) return false; @@ -164,7 +164,7 @@ int main(int argc, char *argv[]) } size_t exe_size = 0; - BYTE *my_exe = peconv::load_file(in_path.c_str(), exe_size); + BYTE *my_exe = peconv::load_pe_module(in_path.c_str(), exe_size, false, false); if (!my_exe) { std::cout << "[-] Could not read the input file!" << std::endl; return -1; @@ -178,7 +178,10 @@ int main(int argc, char *argv[]) peconv::free_file(my_exe); return -3; } - if (peconv::dump_to_file(out_str.c_str(), ext_buf, ext_size)) { + // remap pe to raw == virtual, so that remapping on load will not be required + peconv::t_pe_dump_mode dump_mode = peconv::PE_DUMP_REALIGN; + ULONGLONG current_base = peconv::get_image_base(ext_buf); + if (peconv::dump_pe(out_str.c_str(), ext_buf, ext_size, current_base, dump_mode)) { std::cout << "[+] Saved as: " << out_str << std::endl; } else { @@ -186,5 +189,5 @@ int main(int argc, char *argv[]) } peconv::free_file(my_exe); peconv::free_aligned(ext_buf); - return 0; + return 0; } diff --git a/pe2shc/stub32.bin b/pe2shc/stub32.bin index f0631c5..f07d36a 100644 Binary files a/pe2shc/stub32.bin and b/pe2shc/stub32.bin differ diff --git a/pe2shc/stub64.bin b/pe2shc/stub64.bin index de936cf..5f3edc2 100644 Binary files a/pe2shc/stub64.bin and b/pe2shc/stub64.bin differ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 277be8c..04538c7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,8 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") #add the application that will be used for tests: add_subdirectory ( test_case1 ) +add_subdirectory ( dpc_test ) +add_subdirectory ( injector ) enable_testing() diff --git a/tests/dpc_test/CMakeLists.txt b/tests/dpc_test/CMakeLists.txt new file mode 100644 index 0000000..e8a521f --- /dev/null +++ b/tests/dpc_test/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required (VERSION 2.8) +project (dpc_test) + +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + +set (srcs + main.cpp +) + +set (hdrs +) + +add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs}) + +if(PE2SHC_BUILD_TESTING) + INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) +endif() diff --git a/tests/dpc_test/main.cpp b/tests/dpc_test/main.cpp new file mode 100644 index 0000000..2d7d020 --- /dev/null +++ b/tests/dpc_test/main.cpp @@ -0,0 +1,16 @@ +#include +#include + +int main() +{ + PROCESS_MITIGATION_DYNAMIC_CODE_POLICY dcp = {}; + dcp.ProhibitDynamicCode = 1; + SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &dcp, sizeof(dcp)); + std::cout << "PID: " << std::dec << GetCurrentProcessId() << "\n"; + std::cout << "PROCESS_MITIGATION_DYNAMIC_CODE_POLICY enabled...\n"; + while (true) + { + Sleep(6000); + } + return 0; +} diff --git a/tests/injector/CMakeLists.txt b/tests/injector/CMakeLists.txt new file mode 100644 index 0000000..26ca244 --- /dev/null +++ b/tests/injector/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required (VERSION 2.8) +project (injector) + +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + +set (srcs + main.cpp + util.cpp +) + +set (hdrs + util.h +) + +add_executable ( ${PROJECT_NAME} ${hdrs} ${srcs}) + +if(PE2SHC_BUILD_TESTING) + INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) +endif() diff --git a/tests/injector/main.cpp b/tests/injector/main.cpp new file mode 100644 index 0000000..51ccc9a --- /dev/null +++ b/tests/injector/main.cpp @@ -0,0 +1,45 @@ +#include +#include +#include "util.h" + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + std::cout << "Args: \n"; + return 0; + } + + char *path = argv[1]; + int pid = atoi(argv[2]); + size_t shc_size = 0; + BYTE *shellcode = util::load_file(path, shc_size); + if (!shellcode) { + std::cerr << "Could not load the shellcode file\n"; + return -1; + } + std::cout << "Injecting to: " << pid << "\n"; + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + if (hProcess == NULL) { + std::cerr << "[ERROR] Could not open process : " << std::hex << GetLastError() << std::endl; + return -1; + } + LPVOID remote_buf = VirtualAllocEx(hProcess, NULL, shc_size, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); + if (remote_buf == NULL) { + std::cerr << "[ERROR] Could not allocate a remote buffer : " << std::hex << GetLastError() << std::endl; + return -1; + } + if (!WriteProcessMemory(hProcess, remote_buf, shellcode, shc_size, NULL)) { + std::cerr << "[ERROR] WriteProcessMemory failed, status : " << std::hex << GetLastError() << std::endl; + return -1; + } + HANDLE hMyThread = NULL; + DWORD threadId = 0; + if ((hMyThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remote_buf, NULL, 0, &threadId)) == NULL) { + std::cerr << "[ERROR] CreateRemoteThread failed, status : " << std::hex << GetLastError() << std::endl; + return -1; + } + std::cout << "Injected, created Thread, id = " << threadId << "\n"; + CloseHandle(hMyThread); + CloseHandle(hProcess); + return 0; +} diff --git a/tests/injector/util.cpp b/tests/injector/util.cpp new file mode 100644 index 0000000..7d373d0 --- /dev/null +++ b/tests/injector/util.cpp @@ -0,0 +1,81 @@ +#include "util.h" +#include + +BYTE* util::alloc_aligned(size_t buffer_size, DWORD protect, ULONGLONG desired_base) +{ + if (!buffer_size) return NULL; + + BYTE* buf = (BYTE*)VirtualAlloc((LPVOID)desired_base, buffer_size, MEM_COMMIT | MEM_RESERVE, protect); + return buf; +} + +bool util::free_aligned(BYTE* buffer) +{ + if (buffer == nullptr) return true; + if (!VirtualFree(buffer, 0, MEM_RELEASE)) { +#ifdef _DEBUG + std::cerr << "Releasing failed" << std::endl; +#endif + return false; + } + return true; +} + +BYTE* util::load_file(IN const char *filename, OUT size_t &read_size) +{ + HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) { +#ifdef _DEBUG + std::cerr << "Could not open file!" << std::endl; +#endif + return nullptr; + } + HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0); + if (!mapping) { +#ifdef _DEBUG + std::cerr << "Could not create mapping!" << std::endl; +#endif + CloseHandle(file); + return nullptr; + } + BYTE *dllRawData = (BYTE*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); + if (!dllRawData) { +#ifdef _DEBUG + std::cerr << "Could not map view of file" << std::endl; +#endif + CloseHandle(mapping); + CloseHandle(file); + return nullptr; + } + size_t r_size = GetFileSize(file, 0); + if (read_size != 0 && read_size <= r_size) { + r_size = read_size; + } + if (IsBadReadPtr(dllRawData, r_size)) { + std::cerr << "[-] Mapping of " << filename << " is invalid!" << std::endl; + UnmapViewOfFile(dllRawData); + CloseHandle(mapping); + CloseHandle(file); + return nullptr; + } + BYTE* localCopyAddress = alloc_aligned(r_size, PAGE_READWRITE); + if (localCopyAddress != nullptr) { + memcpy(localCopyAddress, dllRawData, r_size); + read_size = r_size; + } + else { + read_size = 0; +#ifdef _DEBUG + std::cerr << "Could not allocate memory in the current process" << std::endl; +#endif + } + UnmapViewOfFile(dllRawData); + CloseHandle(mapping); + CloseHandle(file); + return localCopyAddress; +} + +void util::free_file(BYTE* buffer) +{ + free_aligned(buffer); +} diff --git a/tests/injector/util.h b/tests/injector/util.h new file mode 100644 index 0000000..2d01a47 --- /dev/null +++ b/tests/injector/util.h @@ -0,0 +1,15 @@ +#pragma once + +#include + + +namespace util { + + BYTE* alloc_aligned(size_t buffer_size, DWORD protect, ULONGLONG desired_base=0); + + bool free_aligned(BYTE* buffer); + + BYTE* load_file(IN const char *filename, OUT size_t &read_size); + + void free_file(BYTE* buffer); +} diff --git a/tests/test_case1/main.cpp b/tests/test_case1/main.cpp index addb03b..77b4d07 100644 --- a/tests/test_case1/main.cpp +++ b/tests/test_case1/main.cpp @@ -17,6 +17,7 @@ int main() if (get_date() == 1337) { std::cout << "Test passed!\n"; } + MessageBoxW(0, L"Hello World!", L"Demo!", MB_OK); std::cout << "Test Case 1 finished\n"; return 0; }