everything works... still need to add JCC/JMP support...

2.0
_xeroxz 4 years ago
parent 2106099c68
commit e98a543f14

@ -91,6 +91,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="DriverEntry.c" /> <ClCompile Include="DriverEntry.c" />
<ClCompile Include="ObfuscateDemo.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Theodosius.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

@ -5,13 +5,21 @@
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter> </Filter>
<Filter Include="Header"> <Filter Include="Header Files">
<UniqueIdentifier>{6ad835cd-061a-454e-b69a-e064070a3bc2}</UniqueIdentifier> <UniqueIdentifier>{92e25b44-aaeb-40a2-b8c9-7eab6c210e8d}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="DriverEntry.c"> <ClCompile Include="DriverEntry.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="ObfuscateDemo.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Theodosius.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,8 +1,7 @@
#include <intrin.h> #include "Theodosius.h"
#define ObfiscateRoutine __declspec(code_seg(".theo"))
unsigned long DbgPrint(const char* format, ...);
int drv_entry() int drv_entry()
{ {
DbgPrint("> hello world! this is a demo!\n"); DbgPrint("> hello world! this is a demo!\n");
DbgPrint("> current pml4 = 0x%p\n", get_dirbase());
} }

@ -0,0 +1,14 @@
#include "Theodosius.h"
ObfuscateRoutine
unsigned long long get_dirbase()
{
cr3 result;
result.flags =
*(unsigned long long*)(IoGetCurrentProcess() + 0x28);
if (!result.address_of_page_directory)
return -1;
return result.address_of_page_directory << 12;
}

@ -0,0 +1,21 @@
#pragma once
#include <intrin.h>
#define ObfuscateRoutine __declspec(code_seg(".theo"))
unsigned long DbgPrint(const char* format, ...);
unsigned long long IoGetCurrentProcess();
unsigned long long get_dirbase();
typedef union
{
struct
{
unsigned long long reserved1 : 3;
unsigned long long page_level_write_through : 1;
unsigned long long page_level_cache_disable : 1;
unsigned long long reserved2 : 7;
unsigned long long address_of_page_directory : 36;
unsigned long long reserved3 : 16;
};
unsigned long long flags;
} cr3;

@ -10,40 +10,72 @@ namespace drv
auto hmdm_ctx::map_objs(std::vector<lnk::obj_buffer_t>& objs) -> image_entry_t auto hmdm_ctx::map_objs(std::vector<lnk::obj_buffer_t>& objs) -> image_entry_t
{ {
std::map<std::string, std::uintptr_t> mapped_symbols; if (!alloc_symbol_space(objs))
// for each obj, allocate space for each symbol and create a map of where
// these symbols will be in memory...
for (auto obj : objs)
{ {
for (auto symbol : lnk::sym::get_all(obj)) std::printf("> failed to allocate symbol space...\n");
{ return {};
mapped_symbols[symbol.symbol_name] = }
reinterpret_cast<std::uintptr_t>(kalloc(symbol.size));
std::printf("> %s allocated at = 0x%p, size = %d\n", if (!alloc_obfuscated_symbol_space(objs))
symbol.symbol_name.c_str(), mapped_symbols[symbol.symbol_name], symbol.size); {
} std::printf("> failed to allocate space for obfuscated functions...\n");
return {};
} }
try if (!map_obfuscated_symbols(objs))
{ {
if (!mapped_symbols["drv_entry"]) std::printf("> failed to resolve obfuscated relocs...\n");
{ return {};
std::printf("> no symbol named drv_entry... (entry point must be named drv_entry)...\n"); }
return {};
} if (!resolve_relocs(objs))
{
std::printf("> failed to resolve relocations...\n");
return {};
} }
catch (std::exception& e)
if (!map_symbols(objs))
{ {
std::printf("> no symbol named drv_entry... (entry point must be named drv_entry)...\n"); std::printf("> failed to map symbols into memory...\n");
return {}; return {};
} }
// resolve relocations and "imports"... return mapped_symbols["drv_entry"];
// if a relocation to a symbol is not found inside of the hashmap of symbols }
// created in the last for loop (above ^) then its going to try and
// resolve the symbol as an ntoskrnl import... bool hmdm_ctx::map_symbols(std::vector<lnk::obj_buffer_t>& objs)
for (auto obj : objs) {
for (auto& obj : objs)
{
for (auto symbol : lnk::sym::get_all(obj))
{
// dont map obfuscated routines into memory as they
// get mapped differently...
if (symbol.obfuscate_routine)
continue;
const auto symbol_mapped =
reinterpret_cast<void*>(
mapped_symbols[symbol.symbol_name]);
if (!symbol_mapped)
{
std::printf("> failed to resolve symbol allocation = %s\n",
symbol.symbol_name.c_str());
return false;
}
kmemcpy(symbol_mapped,
obj.data() + symbol.file_offset, symbol.size);
}
}
return true;
}
bool hmdm_ctx::resolve_relocs(std::vector<lnk::obj_buffer_t>& objs)
{
for (auto& obj : objs)
{ {
for (auto reloc : lnk::sym::get_relocs(obj)) for (auto reloc : lnk::sym::get_relocs(obj))
{ {
@ -52,7 +84,7 @@ namespace drv
std::printf("> error... unsupported relocation at file offset = 0x%x\n\t> symbol = %s\n", std::printf("> error... unsupported relocation at file offset = 0x%x\n\t> symbol = %s\n",
reloc.file_offset, reloc.resolve_symbol_name.c_str()); reloc.file_offset, reloc.resolve_symbol_name.c_str());
return {}; return false;
} }
const auto reloc_addr = const auto reloc_addr =
@ -61,6 +93,10 @@ namespace drv
if (mapped_symbols[reloc.resolve_symbol_name]) if (mapped_symbols[reloc.resolve_symbol_name])
{ {
std::printf("> resolved relocation %s = 0x%p\n",
reloc.resolve_symbol_name.c_str(),
mapped_symbols[reloc.resolve_symbol_name]);
// patch kernel address into relocation... // patch kernel address into relocation...
*reloc_addr = mapped_symbols[reloc.resolve_symbol_name]; *reloc_addr = mapped_symbols[reloc.resolve_symbol_name];
} }
@ -78,7 +114,8 @@ namespace drv
{ {
std::printf("> brutal! unresolved external symbol = %s\n", std::printf("> brutal! unresolved external symbol = %s\n",
reloc.resolve_symbol_name.c_str()); reloc.resolve_symbol_name.c_str());
return {};
return false;
} }
// resolve ntoskrnl exports for now... // resolve ntoskrnl exports for now...
@ -86,21 +123,292 @@ namespace drv
} }
} }
} }
return true;
}
// copy each symbol into memory now... bool hmdm_ctx::map_obfuscated_symbols(std::vector<lnk::obj_buffer_t>& objs)
for (auto obj : objs) {
for (auto& obj : objs)
{ {
for (auto symbol : lnk::sym::get_all(obj)) for (auto symbol : lnk::sym::get_all(obj))
{ {
const auto symbol_mapped = if (!symbol.obfuscate_routine)
reinterpret_cast<void*>( continue;
mapped_symbols[symbol.symbol_name]);
kmemcpy(symbol_mapped, std::printf("> resolving obfuscated relocations for routine = %s\n", symbol.symbol_name.c_str());
obj.data() + symbol.file_offset, symbol.size);
// fix relocations inside of this obfuscated routine...
for (auto reloc : lnk::sym::get_relocs(obj))
{
// if the relocation lands inside of this symbol then we resolve it right now...
if (reloc.file_offset >= symbol.file_offset &&
reloc.file_offset < symbol.file_offset + symbol.size)
{
if (reloc.type != IMAGE_REL_AMD64_ADDR64)
{
std::printf("> error... unsupported relocation at file offset = 0x%x\n\t> symbol = %s\n",
reloc.file_offset, reloc.resolve_symbol_name.c_str());
return false;
}
const auto reloc_addr =
reinterpret_cast<std::uintptr_t*>(
obj.data() + reloc.file_offset);
if (mapped_symbols[reloc.resolve_symbol_name])
{
std::printf(" > resolved obfuscated relocation %s = 0x%p\n",
reloc.resolve_symbol_name.c_str(),
mapped_symbols[reloc.resolve_symbol_name]);
// patch kernel address into relocation...
*reloc_addr = mapped_symbols[reloc.resolve_symbol_name];
}
else
{
// TODO: parse PDB for kernel driver symbols...
const auto ntoskrnl_symbol =
utils::kmodule::get_export(
"ntoskrnl.exe", reloc.resolve_symbol_name.c_str());
std::printf(" > resolved obfuscated external symbol %s = 0x%p\n",
reloc.resolve_symbol_name.c_str(), ntoskrnl_symbol);
if (!ntoskrnl_symbol)
{
std::printf("> brutal! unresolved external symbol = %s\n",
reloc.resolve_symbol_name.c_str());
return false;
}
// resolve ntoskrnl exports for now...
*reloc_addr = ntoskrnl_symbol;
}
}
}
ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
ZyanUSize offset = 0;
ZyanUSize length = symbol.size;
ZydisDecodedInstruction instruction;
const auto routine_begin = symbol.file_offset + obj.data();
bool first_instruction = true;
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, routine_begin + offset,
length - offset, &instruction)))
{
auto symbol_name = symbol.symbol_name;
auto next_instruction_symbol = symbol.symbol_name;
next_instruction_symbol.append("@").append(
std::to_string(offset + instruction.length));
if (first_instruction)
first_instruction = false;
else
symbol_name.append("@")
.append(std::to_string(offset));
switch (instruction.mnemonic)
{
case ZYDIS_MNEMONIC_JB:
case ZYDIS_MNEMONIC_JBE:
case ZYDIS_MNEMONIC_JCXZ:
case ZYDIS_MNEMONIC_JECXZ:
case ZYDIS_MNEMONIC_JKNZD:
case ZYDIS_MNEMONIC_JKZD:
case ZYDIS_MNEMONIC_JL:
case ZYDIS_MNEMONIC_JLE:
case ZYDIS_MNEMONIC_JNB:
case ZYDIS_MNEMONIC_JNBE:
case ZYDIS_MNEMONIC_JNL:
case ZYDIS_MNEMONIC_JNLE:
case ZYDIS_MNEMONIC_JNO:
case ZYDIS_MNEMONIC_JNP:
case ZYDIS_MNEMONIC_JNS:
case ZYDIS_MNEMONIC_JNZ:
case ZYDIS_MNEMONIC_JO:
case ZYDIS_MNEMONIC_JP:
case ZYDIS_MNEMONIC_JRCXZ:
case ZYDIS_MNEMONIC_JS:
case ZYDIS_MNEMONIC_JZ:
{
break;
}
case ZYDIS_MNEMONIC_JMP:
{
break;
}
case ZYDIS_MNEMONIC_RET:
{
std::vector<std::uint8_t> final_instruction;
final_instruction.resize(instruction.length);
// copy instruction into buffer...
memcpy(final_instruction.data(),
obj.data() + symbol.file_offset + offset, instruction.length);
const auto instruc_alloc =
reinterpret_cast<void*>(
mapped_symbols[symbol_name]);
// copy the instruction into memory...
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.size());
break;
}
default: // not a JCC, JMP, or RET...
{
std::vector<std::uint8_t> final_instruction;
// resize buffer so that jmp [rip] can fit...
final_instruction.resize(instruction.length + JMP_RIP_SIZE);
// copy instruction into buffer...
memcpy(final_instruction.data(),
obj.data() + symbol.file_offset + offset, instruction.length);
// copy jmp [rip] after instruction...
memcpy(&final_instruction[instruction.length], jmp_rip, sizeof jmp_rip);
// copy address to jmp to (next instruction)...
*reinterpret_cast<std::uintptr_t*>(
&final_instruction[instruction.length + JMP_RIP_ADDR_IDX]) =
mapped_symbols[next_instruction_symbol];
std::printf(" > next instruction symbol = %s, address = 0x%p\n",
next_instruction_symbol, *reinterpret_cast<std::uintptr_t*>(
&final_instruction[instruction.length + JMP_RIP_ADDR_IDX]));
const auto instruc_alloc =
reinterpret_cast<void*>(
mapped_symbols[symbol_name]);
// copy the instruction and jmp into memory...
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.size());
break;
}
}
offset += instruction.length;
}
} }
} }
return true;
}
return mapped_symbols["drv_entry"]; bool hmdm_ctx::alloc_obfuscated_symbol_space(std::vector<lnk::obj_buffer_t>& objs)
{
for (auto& obj : objs)
{
for (auto symbol : lnk::sym::get_all(obj))
{
// skip obfuscated routines for now... those get scattered...
if (!symbol.obfuscate_routine)
continue;
ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
ZyanUSize offset = 0;
ZyanUSize length = symbol.size;
ZydisDecodedInstruction instruction;
const auto routine_begin = symbol.file_offset + obj.data();
bool first_instruction = true;
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, routine_begin + offset, length - offset,
&instruction)))
{
auto symbol_name = symbol.symbol_name;
if (first_instruction)
first_instruction = false;
else
symbol_name.append("@")
.append(std::to_string(offset));
switch (instruction.mnemonic)
{
case ZYDIS_MNEMONIC_JB:
case ZYDIS_MNEMONIC_JBE:
case ZYDIS_MNEMONIC_JCXZ:
case ZYDIS_MNEMONIC_JECXZ:
case ZYDIS_MNEMONIC_JKNZD:
case ZYDIS_MNEMONIC_JKZD:
case ZYDIS_MNEMONIC_JL:
case ZYDIS_MNEMONIC_JLE:
case ZYDIS_MNEMONIC_JNB:
case ZYDIS_MNEMONIC_JNBE:
case ZYDIS_MNEMONIC_JNL:
case ZYDIS_MNEMONIC_JNLE:
case ZYDIS_MNEMONIC_JNO:
case ZYDIS_MNEMONIC_JNP:
case ZYDIS_MNEMONIC_JNS:
case ZYDIS_MNEMONIC_JNZ:
case ZYDIS_MNEMONIC_JO:
case ZYDIS_MNEMONIC_JP:
case ZYDIS_MNEMONIC_JRCXZ:
case ZYDIS_MNEMONIC_JS:
case ZYDIS_MNEMONIC_JZ:
{
mapped_symbols[symbol_name] =
reinterpret_cast<std::uintptr_t>(
kalloc(instruction.length + (JMP_RIP_SIZE * 2)));
break;
}
case ZYDIS_MNEMONIC_JMP:
{
mapped_symbols[symbol_name] =
reinterpret_cast<std::uintptr_t>(
kalloc(JMP_RIP_SIZE));
break;
}
case ZYDIS_MNEMONIC_RET:
{
mapped_symbols[symbol_name] =
reinterpret_cast<std::uintptr_t>(
kalloc(instruction.length));
break;
}
default: // not a JCC, JMP, or RET...
{
mapped_symbols[symbol_name] =
reinterpret_cast<std::uintptr_t>(
kalloc(instruction.length + JMP_RIP_SIZE));
break;
}
}
std::printf(" > %s allocated = 0x%p\n",
symbol_name.c_str(), mapped_symbols[symbol_name]);
offset += instruction.length;
}
}
}
return true;
}
bool hmdm_ctx::alloc_symbol_space(std::vector<lnk::obj_buffer_t>& objs)
{
for (auto& obj : objs)
{
for (auto symbol : lnk::sym::get_all(obj))
{
// skip obfuscated routines for now... those get scattered...
if (symbol.obfuscate_routine)
continue;
mapped_symbols[symbol.symbol_name] =
reinterpret_cast<std::uintptr_t>(kalloc(symbol.size));
std::printf("> %s allocated at = 0x%p, size = %d\n",
symbol.symbol_name.c_str(), mapped_symbols[symbol.symbol_name], symbol.size);
}
}
} }
} }

@ -9,6 +9,13 @@
#include <winternl.h> #include <winternl.h>
#include <type_traits> #include <type_traits>
#include <dbghelp.h> #include <dbghelp.h>
#include <string>
#define JMP_RIP_SIZE 14
#define JMP_RIP_ADDR_IDX 6
inline const std::uint8_t jmp_rip[] =
{ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 };
#pragma comment(lib, "Dbghelp.lib") #pragma comment(lib, "Dbghelp.lib")
namespace drv namespace drv
@ -26,8 +33,15 @@ namespace drv
explicit hmdm_ctx(const mapper_routines_t& routines); explicit hmdm_ctx(const mapper_routines_t& routines);
auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> image_entry_t; auto map_objs(std::vector<lnk::obj_buffer_t>& objs) -> image_entry_t;
const kalloc_t kalloc; kalloc_t kalloc;
const kmemcpy_t kmemcpy; kmemcpy_t kmemcpy;
private: private:
bool map_symbols(std::vector<lnk::obj_buffer_t>& objs);
bool map_obfuscated_symbols(std::vector<lnk::obj_buffer_t>& objs);
bool resolve_relocs(std::vector<lnk::obj_buffer_t>& objs);
bool alloc_obfuscated_symbol_space(std::vector<lnk::obj_buffer_t>& objs);
bool alloc_symbol_space(std::vector<lnk::obj_buffer_t>& objs);
std::map<std::string, std::uintptr_t> mapped_symbols;
}; };
} }

@ -175,6 +175,7 @@ namespace lnk
std::string(string_table + std::string(string_table +
symbol_table[idx].N.Name.Long); symbol_table[idx].N.Name.Long);
// skip over aux symbols...
if (symbol_table[idx].NumberOfAuxSymbols) if (symbol_table[idx].NumberOfAuxSymbols)
++idx; ++idx;
@ -186,6 +187,13 @@ namespace lnk
symbol.type = symbol_table[idx].Type; symbol.type = symbol_table[idx].Type;
symbol.size = get_symbol_size(symbol, obj); symbol.size = get_symbol_size(symbol, obj);
if (!strncmp((char*)section_headers[
symbol_table[idx].SectionNumber - 1].Name, ".theo", strlen(".theo") - 1))
symbol.obfuscate_routine = true;
else
symbol.obfuscate_routine = false;
// there can be more then one aux symbols...
if (symbol_table[idx].NumberOfAuxSymbols) if (symbol_table[idx].NumberOfAuxSymbols)
idx += symbol_table[idx].NumberOfAuxSymbols; idx += symbol_table[idx].NumberOfAuxSymbols;

@ -28,6 +28,9 @@ namespace lnk
// only used by functions... size in bytes of routine... // only used by functions... size in bytes of routine...
std::uint32_t size; std::uint32_t size;
// if this symbol is a function and is inside of a .theo section...
bool obfuscate_routine;
}; };
// redef of IMAGE_RELOCATION so that "VirtualAddress" // redef of IMAGE_RELOCATION so that "VirtualAddress"

@ -27,7 +27,8 @@ int main(int argc, char** argv)
} }
std::printf("> number of objs = %d\n", image_objs.size()); std::printf("> number of objs = %d\n", image_objs.size());
const auto [drv_handle, drv_key, drv_status] = vdm::load_drv(); /*const auto [drv_handle, drv_key, drv_status] = vdm::load_drv();
if (drv_status != STATUS_SUCCESS || drv_handle == INVALID_HANDLE_VALUE) if (drv_status != STATUS_SUCCESS || drv_handle == INVALID_HANDLE_VALUE)
{ {
std::printf("> failed to load driver... reason -> 0x%x\n", drv_status); std::printf("> failed to load driver... reason -> 0x%x\n", drv_status);
@ -44,7 +45,9 @@ int main(int argc, char** argv)
drv::kalloc_t _kalloc = [&](std::size_t size) -> void* drv::kalloc_t _kalloc = [&](std::size_t size) -> void*
{ {
void* alloc_base; void* alloc_base;
msrexec.exec([&](void* krnl_base, get_system_routine_t get_kroutine) -> void msrexec.exec
(
[&](void* krnl_base, get_system_routine_t get_kroutine) -> void
{ {
using ex_alloc_pool_t = using ex_alloc_pool_t =
void* (*)(std::uint32_t, std::size_t); void* (*)(std::uint32_t, std::size_t);
@ -54,7 +57,8 @@ int main(int argc, char** argv)
get_kroutine(krnl_base, "ExAllocatePool")); get_kroutine(krnl_base, "ExAllocatePool"));
alloc_base = ex_alloc_pool(NULL, size); alloc_base = ex_alloc_pool(NULL, size);
}); }
);
return alloc_base; return alloc_base;
}; };
@ -62,15 +66,29 @@ int main(int argc, char** argv)
[&](void* dest, const void* src, std::size_t size) -> void* [&](void* dest, const void* src, std::size_t size) -> void*
{ {
void* result = nullptr; void* result = nullptr;
msrexec.exec([&](void* krnl_base, get_system_routine_t get_kroutine) -> void msrexec.exec
(
[&](void* krnl_base, get_system_routine_t get_kroutine) -> void
{ {
const auto kmemcpy = const auto kmemcpy =
reinterpret_cast<decltype(&memcpy)>( reinterpret_cast<decltype(&memcpy)>(
get_kroutine(krnl_base, "memcpy")); get_kroutine(krnl_base, "memcpy"));
result = kmemcpy(dest, src, size); result = kmemcpy(dest, src, size);
}); }
);
return result; return result;
};*/
drv::kmemcpy_t _kmemcpy =
[&](void* dest, const void* src, std::size_t size) -> void*
{
return memcpy(dest, src, size);
};
drv::kalloc_t _kalloc = [&](std::size_t size) -> void*
{
return malloc(size);
}; };
drv::hmdm_ctx drv_mapper({ _kalloc, _kmemcpy }); drv::hmdm_ctx drv_mapper({ _kalloc, _kmemcpy });
@ -79,7 +97,7 @@ int main(int argc, char** argv)
std::printf("\n\n> driver entry -> 0x%p\n", drv_entry); std::printf("\n\n> driver entry -> 0x%p\n", drv_entry);
std::getchar(); std::getchar();
int result; /*int result;
msrexec.exec([&result, drv_entry = drv_entry] msrexec.exec([&result, drv_entry = drv_entry]
(void* krnl_base, get_system_routine_t get_kroutine) -> void (void* krnl_base, get_system_routine_t get_kroutine) -> void
{ {
@ -92,7 +110,8 @@ int main(int argc, char** argv)
{ {
std::printf("> failed to unload driver... reason -> 0x%x\n", unload_status); std::printf("> failed to unload driver... reason -> 0x%x\n", unload_status);
return -1; return -1;
} }*/
std::printf("> press enter to close...\n"); std::printf("> press enter to close...\n");
std::getchar(); std::getchar();
} }

@ -291,12 +291,14 @@ namespace utils
// free the RTL_PROCESS_MODULES buffer... // free the RTL_PROCESS_MODULES buffer...
VirtualFree(buffer, NULL, MEM_RELEASE); VirtualFree(buffer, NULL, MEM_RELEASE);
const auto rva = const auto export_um_addr =
reinterpret_cast<std::uintptr_t>( reinterpret_cast<std::uintptr_t>(
GetProcAddress(module_base, export_name)) - GetProcAddress(module_base, export_name));
reinterpret_cast<std::uintptr_t>(module_base);
return image_base + rva; if (!export_um_addr)
return NULL;
return (export_um_addr - reinterpret_cast<std::uintptr_t>(module_base)) + image_base;
} }
} }

Loading…
Cancel
Save