-
-
Save hasherezade/3a9417377cacd893c580bdffb85292c1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <iostream> | |
#include <detours.h> // include MS Detours header | |
#include <peconv.h> // include libPeConv header | |
size_t g_PESize = 0; | |
BYTE *g_PEBuf = NULL; | |
NTSTATUS WINAPI ZwQueryInformationProcess( | |
_In_ HANDLE ProcessHandle, | |
_In_ DWORD ProcessInformationClass, | |
_Out_ PVOID ProcessInformation, | |
_In_ ULONG ProcessInformationLength, | |
_Out_opt_ PULONG ReturnLength | |
); | |
decltype(&ZwQueryInformationProcess) pZwQueryInformationProcess = nullptr; | |
NTSTATUS WINAPI my_ZwQueryInformationProcess( | |
_In_ HANDLE ProcessHandle, | |
_In_ DWORD ProcessInformationClass, | |
_Out_ DWORD* ProcessInformation, | |
_In_ ULONG ProcessInformationLength, | |
_Out_opt_ PULONG ReturnLength | |
) | |
{ | |
NTSTATUS result = pZwQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); | |
if (result == 0 && ProcessInformationClass == 0x22) { | |
(*ProcessInformation) |= 0x20; | |
} | |
return result; | |
} | |
bool hook_apis() | |
{ | |
HMODULE ntdll = LoadLibraryA("ntdll"); | |
if (!ntdll) return false; | |
auto proc = GetProcAddress(ntdll, "ZwQueryInformationProcess"); | |
if (!proc) return false; | |
pZwQueryInformationProcess = reinterpret_cast<decltype(&ZwQueryInformationProcess)>(proc); | |
//initialize hooking: | |
DetourTransactionBegin(); | |
DetourUpdateThread(GetCurrentThread()); | |
// This patch allows for the exceptions to be handled: | |
DetourAttach(&(PVOID&)pZwQueryInformationProcess, my_ZwQueryInformationProcess); | |
//finalize hooking: | |
DetourTransactionCommit(); | |
return true; | |
} | |
BYTE* load_pe(const LPCSTR pe_path) | |
{ | |
// manually load the PE file using libPeConv: | |
size_t v_size = 0; | |
#ifdef LOAD_FROM_PATH | |
//if the PE is dropped on the disk, you can load it from the file: | |
BYTE* my_pe = peconv::load_pe_executable(pe_path, v_size); | |
#else | |
size_t bufsize = 0; | |
BYTE *buffer = peconv::load_file(pe_path, bufsize); | |
// if the file is NOT dropped on the disk, you can load it directly from a memory buffer: | |
BYTE* my_pe = peconv::load_pe_executable(buffer, bufsize, v_size); | |
#endif | |
if (!my_pe) { | |
return NULL; | |
} | |
// set the loaded PE in the global variables: | |
g_PESize = v_size; | |
g_PEBuf = my_pe; | |
// if the loaded PE needs to access resources, you may need to connect it to the PEB: | |
peconv::set_main_module_in_peb((HMODULE)my_pe); | |
return g_PEBuf; | |
} | |
int run_pe_entrypoint(BYTE *my_pe) | |
{ | |
//calculate the Entry Point of the manually loaded module | |
DWORD ep_rva = peconv::get_entry_point_rva(my_pe); | |
if (!ep_rva) { | |
return -2; | |
} | |
ULONG_PTR ep_va = ep_rva + (ULONG_PTR)my_pe; | |
//assuming that the payload is an EXE file (not DLL) this will be the simplest prototype of the main: | |
int(*new_main)() = (int(*)())ep_va; | |
//call the Entry Point of the manually loaded PE: | |
return new_main(); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if (argc < 2) { | |
std::cout << "Args: <path to the exe>" << std::endl; | |
return 0; | |
} | |
const LPCSTR pe_path = argv[1]; | |
// manually load an EXE with libPEConv: | |
if (!load_pe(pe_path)) { | |
std::cout << "[-] Loading the PE: "<< pe_path << " failed!\n"; | |
return -1; | |
} | |
if (!hook_apis()) { | |
std::cerr << "Hooking failed!\n"; | |
return (-1); | |
} | |
// run the manually loaded EXE: | |
int res = run_pe_entrypoint(g_PEBuf); | |
system("pause"); | |
return res; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment