Skip to content

Instantly share code, notes, and snippets.

@hasherezade
Last active August 21, 2022 00:49
Show Gist options
  • Save hasherezade/97b032e2e3eb6864a48c63ab69cedd4c to your computer and use it in GitHub Desktop.
Save hasherezade/97b032e2e3eb6864a48c63ab69cedd4c to your computer and use it in GitHub Desktop.
libpPeConv-based loader for PEs using RtlPcToFileHeader
#include <Windows.h>
#include <iostream>
#include <tchar.h>
#include <peconv.h> // include libPeConv header
BYTE* g_Payload = nullptr;
size_t g_PayloadSize = 0;
PVOID my_RtlPcToFileHeader(
PVOID PcValue,
PVOID* BaseOfImage
)
{
PVOID ret = RtlPcToFileHeader(PcValue, BaseOfImage);
if (*BaseOfImage != NULL) {
return ret;
}
std::cout << "Cannot find image base for: " << std::hex << PcValue << std::endl;
if ((ULONG_PTR)PcValue >= (ULONG_PTR)g_Payload && (ULONG_PTR)PcValue <= ((ULONG_PTR)g_Payload + g_PayloadSize)) {
std::cout << "Overwriting base!\n";
*BaseOfImage = g_Payload;
return g_Payload;
}
return ret;
}
// manually load the PE file using libPeConv
bool load_payload(LPCTSTR pe_path)
{
// manually load the PE file using libPeConv:
g_PayloadSize = 0;
peconv::hooking_func_resolver my_res;
my_res.add_hook("RtlPcToFileHeader", (FARPROC)&my_RtlPcToFileHeader);
//if the PE is dropped on the disk, you can load it from the file:
g_Payload = peconv::load_pe_executable(pe_path, g_PayloadSize, (peconv::t_function_resolver*)&my_res);
if (!g_Payload) {
return false;
}
// if the loaded PE needs to access resources, you may need to connect it to the PEB:
//peconv::set_main_module_in_peb((HMODULE)g_Payload);
std::cout << "Loaded at base: " << std::hex << (ULONG_PTR)g_Payload << std::endl;
return true;
}
int run_payload()
{
if (!g_Payload) {
std::cerr << "[!] The payload is not loaded!\n";
return -1;
}
//calculate the Entry Point of the manually loaded module
DWORD ep_rva = peconv::get_entry_point_rva(g_Payload);
if (!ep_rva) {
std::cerr << "[!] Cannot fetch EP!\n";
return -2;
}
std::cout << "Running the payload:\n";
int ret = 0;
const ULONG_PTR ep_va = ep_rva + (ULONG_PTR)g_Payload;
if (peconv::is_module_dll(g_Payload)) {
//the prototype of the DllMain fuction:
BOOL WINAPI _DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved); // reserved
auto new_main = reinterpret_cast<decltype(&_DllMain)>(ep_va);
// call the Entry Point of the manually loaded PE :
ret = new_main((HINSTANCE)g_Payload, DLL_PROCESS_ATTACH, 0);
}
else {
//the simplest prototype of the main fuction:
int basic_main(void);
auto new_main = reinterpret_cast<decltype(&basic_main)>(ep_va);
//call the Entry Point of the manually loaded PE:
ret = new_main();
}
return ret;
}
int _tmain(int argc, LPTSTR argv[])
{
if (argc < 2) {
std::cout << "Args: <path to the exe>" << std::endl;
return 0;
}
const LPTSTR pe_path = argv[1];
if (!load_payload(pe_path)) {
return -1;
}
return run_payload();
}
@hasherezade
Copy link
Author

You can copy it into the template: https://github.com/hasherezade/libpeconv_tpl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment