recoded how "gadgets" are allocated... much more modular now

2.0
_xeroxz 4 years ago
parent e5e21b87fd
commit 20bce8a1d4

@ -5,41 +5,48 @@ namespace drv
hmdm_ctx::hmdm_ctx(const mapper_routines_t& routines) hmdm_ctx::hmdm_ctx(const mapper_routines_t& routines)
: :
kalloc(std::get<0>(routines)), kalloc(std::get<0>(routines)),
kmemcpy(std::get<1>(routines)) kmemcpy(std::get<1>(routines)),
resolve_symbol(std::get<2>(routines))
{} {}
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::printf("[+] allocating space for symbols...\n");
if (!alloc_symbol_space(objs)) if (!alloc_symbol_space(objs))
{ {
std::printf("> failed to allocate symbol space...\n"); std::printf("[!] failed to allocate symbol space...\n");
return {}; return {};
} }
std::printf("[+] allocating space for obfuscated symbols...\n");
if (!alloc_obfuscated_symbol_space(objs)) if (!alloc_obfuscated_symbol_space(objs))
{ {
std::printf("> failed to allocate space for obfuscated functions...\n"); std::printf("[!] failed to allocate space for obfuscated functions...\n");
return {}; return {};
} }
std::printf("[+] mapping obfuscated symbols...\n");
if (!map_obfuscated_symbols(objs)) if (!map_obfuscated_symbols(objs))
{ {
std::printf("> failed to resolve obfuscated relocs...\n"); std::printf("[!] failed to resolve obfuscated relocs...\n");
return {}; return {};
} }
std::printf("[+] resolving non-obfuscated relocations...\n");
if (!resolve_relocs(objs)) if (!resolve_relocs(objs))
{ {
std::printf("> failed to resolve relocations...\n"); std::printf("[!] failed to resolve relocations...\n");
return {}; return {};
} }
std::printf("[+] mapping non-obfuscated symbols...\n");
if (!map_symbols(objs)) if (!map_symbols(objs))
{ {
std::printf("> failed to map symbols into memory...\n"); std::printf("> failed to map symbols into memory...\n");
return {}; return {};
} }
std::printf("[+] linking complete...\n");
return mapped_symbols["drv_entry"]; return mapped_symbols["drv_entry"];
} }
@ -60,14 +67,17 @@ namespace drv
if (!symbol_mapped) if (!symbol_mapped)
{ {
std::printf("> failed to resolve symbol allocation = %s\n", std::printf(" > failed to resolve symbol allocation = %s\n",
symbol.symbol_name.c_str()); symbol.symbol_name.c_str());
return false; return false;
} }
kmemcpy(symbol_mapped, std::printf(" > mapping symbol = %s, at = 0x%p\n",
obj.data() + symbol.file_offset, symbol.size); symbol.symbol_name.c_str(), symbol_mapped);
kmemcpy(symbol_mapped, obj.data() +
symbol.file_offset, symbol.size);
} }
} }
return true; return true;
@ -81,7 +91,7 @@ namespace drv
{ {
if (reloc.type != IMAGE_REL_AMD64_ADDR64) if (reloc.type != IMAGE_REL_AMD64_ADDR64)
{ {
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 false; return false;
@ -91,36 +101,33 @@ namespace drv
reinterpret_cast<std::uintptr_t*>( reinterpret_cast<std::uintptr_t*>(
obj.data() + reloc.file_offset); obj.data() + reloc.file_offset);
// check obj symbol table for this relocation...
if (mapped_symbols[reloc.resolve_symbol_name]) if (mapped_symbols[reloc.resolve_symbol_name])
{ {
std::printf("> resolved relocation %s = 0x%p\n", std::printf(" > resolving internal symbol...\n");
reloc.resolve_symbol_name.c_str(), std::printf(" > address = 0x%p\n", mapped_symbols[reloc.resolve_symbol_name]);
mapped_symbols[reloc.resolve_symbol_name]); std::printf(" > symbol = %s\n", reloc.resolve_symbol_name.c_str());
// patch kernel address into relocation...
*reloc_addr = mapped_symbols[reloc.resolve_symbol_name]; *reloc_addr = mapped_symbols[reloc.resolve_symbol_name];
} }
else else // else check external symbol table...
{ {
// TODO: parse PDB for kernel driver symbols... const auto extern_symbol =
const auto ntoskrnl_symbol = resolve_symbol(reloc.resolve_symbol_name.c_str());
utils::kmodule::get_export(
"ntoskrnl.exe", reloc.resolve_symbol_name.c_str());
std::printf("> resolved external symbol %s = 0x%p\n",
reloc.resolve_symbol_name.c_str(), ntoskrnl_symbol);
if (!ntoskrnl_symbol) if (!extern_symbol)
{ {
std::printf("> brutal! unresolved external symbol = %s\n", std::printf("[!] unresolved external symbol = %s...\n",
reloc.resolve_symbol_name.c_str()); reloc.resolve_symbol_name.c_str());
return false; return false;
} }
// resolve ntoskrnl exports for now... *reloc_addr = extern_symbol;
*reloc_addr = ntoskrnl_symbol;
} }
std::printf(" > resolving external symbol...\n");
std::printf(" > address = 0x%p\n", *reloc_addr);
std::printf(" > symbol = %s\n", reloc.resolve_symbol_name.c_str());
} }
} }
return true; return true;
@ -135,222 +142,117 @@ namespace drv
if (!symbol.obfuscate_type) if (!symbol.obfuscate_type)
continue; continue;
std::printf("> resolving obfuscated relocations for routine = %s\n", symbol.symbol_name.c_str()); std::printf(" > mapping obfuscated routine %s into memory...\n", symbol.symbol_name.c_str());
// 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);
std::int32_t offset = 0; unsigned instruc_offset = 0u;
ZyanUSize length = symbol.size; while (true) // TODO: this is bad code... dont do this!
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 symbol_name = symbol.symbol_name;
auto jcc_symbol = symbol.symbol_name;
auto next_instruction_symbol = symbol.symbol_name;
jcc_symbol.append("@")
.append(std::to_string(
offset + instruction.operands[0].imm.value.s + instruction.length));
next_instruction_symbol.append("@").append( if (instruc_offset)
std::to_string(offset + instruction.length));
if (first_instruction)
first_instruction = false;
else
symbol_name.append("@") symbol_name.append("@")
.append(std::to_string(offset)); .append(std::to_string(instruc_offset));
switch (instruction.mnemonic) // if there is no allocation for this symbol then we are done...
{ if (!mapped_symbols[symbol_name])
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:
{
std::vector<std::uint8_t> final_instruction;
final_instruction.resize(instruction.length +
instruction.length + (JMP_RIP_SIZE * 2));
// copy instruction into buffer...
memcpy(final_instruction.data(),
obj.data() + symbol.file_offset + offset, instruction.length);
// TODO check to see if the compiler made a short JCC...
// with optimizations off it seems to not...
*reinterpret_cast<std::uint32_t*>(&final_instruction[
instruction.length - (instruction.operands[0].size / 8)]) = NULL;
// only jmping +-128 bytes to jtable...
final_instruction[instruction.length - (instruction.operands[0].size / 8)] = JMP_RIP_SIZE;
std::printf(" > fixing JCC instruction...\n");
std::printf(" > original rva = 0x%x, new rva = 0x%x\n", instruction.operands[0].imm.value.s, JMP_RIP_SIZE);
std::printf(" > conditional branch = 0x%p\n", mapped_symbols[jcc_symbol]);
std::printf(" > next instruction = 0x%p\n", mapped_symbols[next_instruction_symbol]);
// copy jmp [rip] after instruction...
memcpy(&final_instruction[instruction.length], jmp_rip, sizeof jmp_rip);
// copy jtable entry...
memcpy(&final_instruction[instruction.length + JMP_RIP_SIZE], jmp_rip, sizeof jmp_rip);
// this jmp [rip] goes to the conditional branch...
*reinterpret_cast<std::uintptr_t*>(&final_instruction[
instruction.length + JMP_RIP_SIZE + JMP_RIP_ADDR_IDX]) = mapped_symbols[jcc_symbol];
// this jmp [rip] goes to the next instruction...
*reinterpret_cast<std::uintptr_t*>(&final_instruction[
instruction.length + JMP_RIP_ADDR_IDX]) = mapped_symbols[next_instruction_symbol];
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; break;
}
case ZYDIS_MNEMONIC_JMP:
{
std::vector<std::uint8_t> final_instruction;
final_instruction.resize(JMP_RIP_SIZE);
memset(final_instruction.data(), NULL, final_instruction.size());
*reinterpret_cast<std::uintptr_t*>( const auto instruc_len = obfuscated_gadgets
&final_instruction[JMP_RIP_SIZE]) = mapped_symbols[jcc_symbol]; [mapped_symbols[symbol_name]]->get_instruc().length;
const auto instruc_alloc = auto gadget_stack = obfuscated_gadgets
reinterpret_cast<void*>( [mapped_symbols[symbol_name]]->get_gadget();
mapped_symbols[symbol_name]);
// copy the instruction into memory... const auto gadget_size = obfuscated_gadgets
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.size()); [mapped_symbols[symbol_name]]->get_size();
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 = unsigned gadget_offset = 0u;
reinterpret_cast<void*>( std::vector<std::uint8_t> gadget_raw;
mapped_symbols[symbol_name]);
// copy the instruction into memory... for (auto& [gadget, reloc] : gadget_stack)
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.size());
break;
}
default: // not a JCC, JMP, or RET...
{ {
std::vector<std::uint8_t> final_instruction; const auto fix_reloc_addr =
// resize buffer so that jmp [rip] can fit... gadget.data() + reloc.offset;
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... switch (reloc.type)
memcpy(&final_instruction[instruction.length], jmp_rip, sizeof jmp_rip); {
case obfuscation::reloc_type::next_instruction_addr:
{
const auto next_instruc_symbol =
std::string(symbol.symbol_name).append("@")
.append(std::to_string(instruc_offset + instruc_len));
// copy address to jmp to (next instruction)... *reinterpret_cast<std::uintptr_t*>(fix_reloc_addr) =
*reinterpret_cast<std::uintptr_t*>( mapped_symbols[next_instruc_symbol];
&final_instruction[instruction.length + JMP_RIP_ADDR_IDX]) = }
mapped_symbols[next_instruction_symbol]; default: // default check for relocations...
{
// check this instruction to see if it needs any relocs...
for (auto& reloc : lnk::sym::get_relocs(obj))
{
if (reloc.file_offset >= symbol.file_offset + instruc_offset &&
reloc.file_offset < symbol.file_offset + instruc_offset + instruc_len)
{
std::printf(" > resolving relocation for instruction...\n");
if (reloc.type != IMAGE_REL_AMD64_ADDR64)
{
std::printf("[!] error, cannot resolve reloc = %s, type = 0x%x\n",
reloc.resolve_symbol_name.c_str(), reloc.type);
// cant relocate anything but IMAGE_REL_AMD64_ADDR64...
// this is fine since the compiler shouldnt ever make any rip relative code
// besides JCC's...
return false;
}
const auto reloc_instruc_offset =
reloc.file_offset - (symbol.file_offset + instruc_offset);
const auto reloc_addr =
reinterpret_cast<std::uintptr_t*>(
gadget.data() + reloc_instruc_offset);
// check obj symbol table for this relocation...
if (mapped_symbols[reloc.resolve_symbol_name])
{
*reloc_addr = mapped_symbols[reloc.resolve_symbol_name];
}
else // else check external symbol table...
{
const auto extern_symbol =
resolve_symbol(reloc.resolve_symbol_name.c_str());
if (!extern_symbol)
{
std::printf("[!] unresolved external symbol = %s...\n",
reloc.resolve_symbol_name.c_str());
return false;
}
*reloc_addr = extern_symbol;
}
std::printf(" > address = 0x%p\n", *reloc_addr);
std::printf(" > symbol = %s\n", reloc.resolve_symbol_name.c_str());
break; // break out of for loop... we resolve the symbol...
}
}
}
}
std::printf(" > next instruction symbol = %s, address = 0x%p\n", gadget_raw.insert(gadget_raw.end(), gadget.begin(), gadget.end());
next_instruction_symbol.c_str(), *reinterpret_cast<std::uintptr_t*>( gadget_offset += gadget.size();
&final_instruction[instruction.length + JMP_RIP_ADDR_IDX])); }
const auto instruc_alloc = const auto gadget_addr =
reinterpret_cast<void*>( reinterpret_cast<void*>(
mapped_symbols[symbol_name]); mapped_symbols[symbol_name]);
// copy the instruction and jmp into memory... std::printf(" > copying gadget at = 0x%p\n", gadget_addr);
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.size()); kmemcpy(gadget_addr, gadget_raw.data(), gadget_raw.size());
break; // used to calc symbol for next instruction...
} instruc_offset += instruc_len;
}
offset += instruction.length;
} }
} }
} }
@ -359,88 +261,55 @@ namespace drv
bool hmdm_ctx::alloc_obfuscated_symbol_space(std::vector<lnk::obj_buffer_t>& objs) bool hmdm_ctx::alloc_obfuscated_symbol_space(std::vector<lnk::obj_buffer_t>& objs)
{ {
ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
for (auto& obj : objs) for (auto& obj : objs)
{ {
for (auto& symbol : lnk::sym::get_all(obj)) for (auto& symbol : lnk::sym::get_all(obj))
{ {
// skip obfuscated routines for now... those get scattered... // skip normal routines for now... those get scattered...
if (!symbol.obfuscate_type) if (!symbol.obfuscate_type)
continue; continue;
ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
ZyanUSize offset = 0; ZyanUSize offset = 0;
ZyanUSize length = symbol.size; ZyanUSize length = symbol.size;
ZydisDecodedInstruction instruction; ZydisDecodedInstruction instruction;
const auto routine_begin = symbol.file_offset + obj.data(); const auto routine_begin =
symbol.file_offset + obj.data();
bool first_instruction = true; bool first_instruction = true;
std::printf(" > obfuscating %s\n", symbol.symbol_name.c_str());
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, routine_begin + offset, length - offset, while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
&instruction))) &decoder, routine_begin + offset, length - offset, &instruction)))
{ {
auto symbol_name = symbol.symbol_name; // dont append @offset for the first instruction...
auto new_symbol = symbol.symbol_name;
if (first_instruction) if (first_instruction)
first_instruction = false; first_instruction = false;
else else
symbol_name.append("@") new_symbol.append("@")
.append(std::to_string(offset)); .append(std::to_string(offset));
switch (instruction.mnemonic) std::vector<std::uint8_t> instruc_bytes{};
{ instruc_bytes.resize(instruction.length);
case ZYDIS_MNEMONIC_JB:
case ZYDIS_MNEMONIC_JBE: memcpy(instruc_bytes.data(), obj.data() +
case ZYDIS_MNEMONIC_JCXZ: symbol.file_offset + offset, instruction.length);
case ZYDIS_MNEMONIC_JECXZ:
case ZYDIS_MNEMONIC_JKNZD: std::shared_ptr<obfuscation::obfuscate> new_gadget(
case ZYDIS_MNEMONIC_JKZD: new obfuscation::obfuscate({ instruction, instruc_bytes }));
case ZYDIS_MNEMONIC_JL:
case ZYDIS_MNEMONIC_JLE: mapped_symbols[new_symbol] =
case ZYDIS_MNEMONIC_JNB: reinterpret_cast<std::uintptr_t>(
case ZYDIS_MNEMONIC_JNBE: kalloc(new_gadget->get_size()));
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", obfuscated_gadgets[mapped_symbols[new_symbol]] = new_gadget;
symbol_name.c_str(), mapped_symbols[symbol_name]); std::printf(" > %s allocated = 0x%p, size = %d\n", new_symbol.c_str(),
mapped_symbols[new_symbol], new_gadget->get_size());
offset += instruction.length; offset += instruction.length;
} }
@ -462,7 +331,7 @@ namespace drv
mapped_symbols[symbol.symbol_name] = mapped_symbols[symbol.symbol_name] =
reinterpret_cast<std::uintptr_t>(kalloc(symbol.size)); reinterpret_cast<std::uintptr_t>(kalloc(symbol.size));
std::printf("> %s allocated at = 0x%p, size = %d\n", std::printf(" > %s allocated at = 0x%p, size = %d\n",
symbol.symbol_name.c_str(), mapped_symbols[symbol.symbol_name], symbol.size); symbol.symbol_name.c_str(), mapped_symbols[symbol.symbol_name], symbol.size);
} }
} }

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "utils.hpp" #include "utils.hpp"
#include "linker/linker.hpp" #include "linker/linker.hpp"
#include "obfuscation/obfuscation.hpp"
#include <Zycore/Zycore.h> #include <Zycore/Zycore.h>
#include <Zydis/Decoder.h> #include <Zydis/Decoder.h>
@ -9,23 +10,19 @@
#include <winternl.h> #include <winternl.h>
#include <type_traits> #include <type_traits>
#include <dbghelp.h> #include <dbghelp.h>
#include <mutex>
#include <string> #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
{ {
using kalloc_t = std::function<decltype(malloc)>; using kalloc_t = std::function<decltype(malloc)>;
using kmemcpy_t = std::function<decltype(memcpy)>; using kmemcpy_t = std::function<decltype(memcpy)>;
using kmemset_t = std::function<decltype(memset)>; using kmemset_t = std::function<decltype(memset)>;
using resolve_symbol_t = std::function<std::uintptr_t(const char*)>;
using image_entry_t = std::uintptr_t; using image_entry_t = std::uintptr_t;
using mapper_routines_t = std::pair<kalloc_t, kmemcpy_t>; using mapper_routines_t = std::tuple<kalloc_t, kmemcpy_t, resolve_symbol_t>;
class hmdm_ctx class hmdm_ctx
{ {
@ -35,6 +32,7 @@ namespace drv
kalloc_t kalloc; kalloc_t kalloc;
kmemcpy_t kmemcpy; kmemcpy_t kmemcpy;
resolve_symbol_t resolve_symbol;
private: private:
bool map_symbols(std::vector<lnk::obj_buffer_t>& objs); bool map_symbols(std::vector<lnk::obj_buffer_t>& objs);
bool map_obfuscated_symbols(std::vector<lnk::obj_buffer_t>& objs); bool map_obfuscated_symbols(std::vector<lnk::obj_buffer_t>& objs);
@ -42,6 +40,8 @@ namespace drv
bool resolve_relocs(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_obfuscated_symbol_space(std::vector<lnk::obj_buffer_t>& objs);
bool alloc_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; std::map<std::string, std::uintptr_t> mapped_symbols;
std::map<std::uintptr_t, std::shared_ptr<obfuscation::obfuscate>> obfuscated_gadgets;
}; };
} }

@ -57,6 +57,9 @@ namespace lnk
const auto obj_size = std::atoi( const auto obj_size = std::atoi(
reinterpret_cast<const char*>(archive_headers->Size)); reinterpret_cast<const char*>(archive_headers->Size));
if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A)
break;
if (!obj_size) if (!obj_size)
break; break;

@ -88,7 +88,13 @@ int main(int argc, char** argv)
return memcpy(dest, src, size); return memcpy(dest, src, size);
}; };
drv::hmdm_ctx drv_mapper({ _kalloc, _kmemcpy }); drv::resolve_symbol_t resolve_symbol =
[&](const char* symbol_name) -> std::uintptr_t
{
return utils::kmodule::get_export("ntoskrnl.exe", symbol_name);
};
drv::hmdm_ctx drv_mapper({ _kalloc, _kmemcpy, resolve_symbol });
const auto drv_entry = drv_mapper.map_objs(image_objs); const auto drv_entry = drv_mapper.map_objs(image_objs);
std::printf("\n\n> driver entry -> 0x%p\n", drv_entry); std::printf("\n\n> driver entry -> 0x%p\n", drv_entry);

@ -0,0 +1,107 @@
#include "obfuscation.hpp"
namespace obfuscation
{
obfuscate::obfuscate(instruction_info_t info)
:
instruction(info)
{
switch (instruction.first.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:
{
reloc_t inline_jmp_reloc
{
JMP_RIP_ADDR_IDX,
reloc_type::next_instruction_addr
};
const auto rva_fix_offset = instruction.first.length -
(instruction.first.operands[0].size / 8);
const auto rva_fix_addr =
instruction.second.data() + rva_fix_offset;
std::printf(" > fixing JCC rva...\n");
std::printf(" > new rva = 0x%x\n", JMP_RIP_SIZE);
std::printf(" > old rva = 0x%x\n",
*reinterpret_cast<std::uint32_t*>(rva_fix_addr));
// when you inherit obfuscate please be mindful of JCC rvas...
*reinterpret_cast<std::uint32_t*>(rva_fix_addr) = JMP_RIP_SIZE;
gadget_stack.push_back({ instruction.second, {} });
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
break;
}
case ZYDIS_MNEMONIC_JMP:
{
reloc_t inline_jmp_reloc
{
JMP_RIP_ADDR_IDX,
reloc_type::next_instruction_addr
};
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
break;
}
case ZYDIS_MNEMONIC_RET:
{
gadget_stack.push_back({ instruction.second, {} });
break;
}
default: // not a JCC, JMP, or RET...
{
reloc_t inline_jmp_reloc
{
JMP_RIP_ADDR_IDX,
reloc_type::next_instruction_addr
};
gadget_stack.push_back({ instruction.second, {} });
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
break;
}
}
}
auto obfuscate::get_size() const -> std::uint32_t
{
std::uint32_t result = 0u;
for (auto& gadget : gadget_stack)
result += gadget.first.size();
return result;
}
auto obfuscate::get_instruc() const -> ZydisDecodedInstruction
{
return instruction.first;
}
auto obfuscate::get_gadget() const -> gadget_stack_t
{
return gadget_stack;
}
}

@ -1,7 +1,57 @@
#include <Zydis/Zydis.h> #include <Zydis/Zydis.h>
#include <cstdint> #include <cstdint>
#include <vector>
#include <stack>
#include <map>
#define JMP_RIP_SIZE 14
#define JMP_RIP_ADDR_IDX 6
namespace obfuscation namespace obfuscation
{ {
inline const std::vector<std::uint8_t> jmp_rip =
{
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp [rip+0x0]
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 // address...
};
enum class reloc_type
{
jcc_rva = 1,
next_instruction_addr = 2,
external_symbol = 3
};
struct reloc_t
{
std::uint32_t offset;
reloc_type type;
};
using instruction_info_t = std::pair<ZydisDecodedInstruction, std::vector<std::uint8_t>>;
using gadget_stack_t = std::vector<std::pair<std::vector<std::uint8_t>, reloc_t>>;
class obfuscate
{
public:
explicit obfuscate(instruction_info_t info);
auto get_size() const -> std::uint32_t;
auto get_gadget() const -> gadget_stack_t;
auto get_instruc() const -> ZydisDecodedInstruction;
private:
instruction_info_t instruction;
gadget_stack_t gadget_stack;
};
/*class mutation : obfuscate
{
public:
explicit mutation(instruction_info_t info );
};
class encrypt : mutation
{
public:
explicit encrypt(instruction_info_t info);
};*/
} }
Loading…
Cancel
Save