|
|
|
@ -5,41 +5,48 @@ namespace drv
|
|
|
|
|
hmdm_ctx::hmdm_ctx(const mapper_routines_t& 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
|
|
|
|
|
{
|
|
|
|
|
std::printf("[+] allocating space for symbols...\n");
|
|
|
|
|
if (!alloc_symbol_space(objs))
|
|
|
|
|
{
|
|
|
|
|
std::printf("> failed to allocate symbol space...\n");
|
|
|
|
|
std::printf("[!] failed to allocate symbol space...\n");
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::printf("[+] allocating space for obfuscated symbols...\n");
|
|
|
|
|
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 {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::printf("[+] mapping obfuscated symbols...\n");
|
|
|
|
|
if (!map_obfuscated_symbols(objs))
|
|
|
|
|
{
|
|
|
|
|
std::printf("> failed to resolve obfuscated relocs...\n");
|
|
|
|
|
std::printf("[!] failed to resolve obfuscated relocs...\n");
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::printf("[+] resolving non-obfuscated relocations...\n");
|
|
|
|
|
if (!resolve_relocs(objs))
|
|
|
|
|
{
|
|
|
|
|
std::printf("> failed to resolve relocations...\n");
|
|
|
|
|
std::printf("[!] failed to resolve relocations...\n");
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::printf("[+] mapping non-obfuscated symbols...\n");
|
|
|
|
|
if (!map_symbols(objs))
|
|
|
|
|
{
|
|
|
|
|
std::printf("> failed to map symbols into memory...\n");
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::printf("[+] linking complete...\n");
|
|
|
|
|
return mapped_symbols["drv_entry"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -60,14 +67,17 @@ namespace drv
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kmemcpy(symbol_mapped,
|
|
|
|
|
obj.data() + symbol.file_offset, symbol.size);
|
|
|
|
|
std::printf(" > mapping symbol = %s, at = 0x%p\n",
|
|
|
|
|
symbol.symbol_name.c_str(), symbol_mapped);
|
|
|
|
|
|
|
|
|
|
kmemcpy(symbol_mapped, obj.data() +
|
|
|
|
|
symbol.file_offset, symbol.size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
@ -81,7 +91,7 @@ namespace drv
|
|
|
|
|
{
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
@ -91,36 +101,33 @@ namespace drv
|
|
|
|
|
reinterpret_cast<std::uintptr_t*>(
|
|
|
|
|
obj.data() + reloc.file_offset);
|
|
|
|
|
|
|
|
|
|
// check obj symbol table for this relocation...
|
|
|
|
|
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...
|
|
|
|
|
std::printf(" > resolving internal symbol...\n");
|
|
|
|
|
std::printf(" > address = 0x%p\n", mapped_symbols[reloc.resolve_symbol_name]);
|
|
|
|
|
std::printf(" > symbol = %s\n", reloc.resolve_symbol_name.c_str());
|
|
|
|
|
*reloc_addr = mapped_symbols[reloc.resolve_symbol_name];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
else // else check external symbol table...
|
|
|
|
|
{
|
|
|
|
|
// 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 external symbol %s = 0x%p\n",
|
|
|
|
|
reloc.resolve_symbol_name.c_str(), ntoskrnl_symbol);
|
|
|
|
|
const auto extern_symbol =
|
|
|
|
|
resolve_symbol(reloc.resolve_symbol_name.c_str());
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resolve ntoskrnl exports for now...
|
|
|
|
|
*reloc_addr = ntoskrnl_symbol;
|
|
|
|
|
*reloc_addr = extern_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;
|
|
|
|
@ -135,222 +142,117 @@ namespace drv
|
|
|
|
|
if (!symbol.obfuscate_type)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
std::printf("> resolving obfuscated relocations for routine = %s\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::printf(" > mapping obfuscated routine %s into memory...\n", symbol.symbol_name.c_str());
|
|
|
|
|
|
|
|
|
|
std::int32_t 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)))
|
|
|
|
|
unsigned instruc_offset = 0u;
|
|
|
|
|
while (true) // TODO: this is bad code... dont do this!
|
|
|
|
|
{
|
|
|
|
|
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(
|
|
|
|
|
std::to_string(offset + instruction.length));
|
|
|
|
|
|
|
|
|
|
if (first_instruction)
|
|
|
|
|
first_instruction = false;
|
|
|
|
|
else
|
|
|
|
|
if (instruc_offset)
|
|
|
|
|
symbol_name.append("@")
|
|
|
|
|
.append(std::to_string(offset));
|
|
|
|
|
.append(std::to_string(instruc_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:
|
|
|
|
|
{
|
|
|
|
|
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());
|
|
|
|
|
// if there is no allocation for this symbol then we are done...
|
|
|
|
|
if (!mapped_symbols[symbol_name])
|
|
|
|
|
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*>(
|
|
|
|
|
&final_instruction[JMP_RIP_SIZE]) = mapped_symbols[jcc_symbol];
|
|
|
|
|
const auto instruc_len = obfuscated_gadgets
|
|
|
|
|
[mapped_symbols[symbol_name]]->get_instruc().length;
|
|
|
|
|
|
|
|
|
|
const auto instruc_alloc =
|
|
|
|
|
reinterpret_cast<void*>(
|
|
|
|
|
mapped_symbols[symbol_name]);
|
|
|
|
|
auto gadget_stack = obfuscated_gadgets
|
|
|
|
|
[mapped_symbols[symbol_name]]->get_gadget();
|
|
|
|
|
|
|
|
|
|
// copy the instruction into memory...
|
|
|
|
|
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.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 gadget_size = obfuscated_gadgets
|
|
|
|
|
[mapped_symbols[symbol_name]]->get_size();
|
|
|
|
|
|
|
|
|
|
const auto instruc_alloc =
|
|
|
|
|
reinterpret_cast<void*>(
|
|
|
|
|
mapped_symbols[symbol_name]);
|
|
|
|
|
unsigned gadget_offset = 0u;
|
|
|
|
|
std::vector<std::uint8_t> gadget_raw;
|
|
|
|
|
|
|
|
|
|
// copy the instruction into memory...
|
|
|
|
|
kmemcpy(instruc_alloc, final_instruction.data(), final_instruction.size());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: // not a JCC, JMP, or RET...
|
|
|
|
|
for (auto& [gadget, reloc] : gadget_stack)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
const auto fix_reloc_addr =
|
|
|
|
|
gadget.data() + reloc.offset;
|
|
|
|
|
|
|
|
|
|
// copy jmp [rip] after instruction...
|
|
|
|
|
memcpy(&final_instruction[instruction.length], jmp_rip, sizeof jmp_rip);
|
|
|
|
|
switch (reloc.type)
|
|
|
|
|
{
|
|
|
|
|
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*>(
|
|
|
|
|
&final_instruction[instruction.length + JMP_RIP_ADDR_IDX]) =
|
|
|
|
|
mapped_symbols[next_instruction_symbol];
|
|
|
|
|
*reinterpret_cast<std::uintptr_t*>(fix_reloc_addr) =
|
|
|
|
|
mapped_symbols[next_instruc_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",
|
|
|
|
|
next_instruction_symbol.c_str(), *reinterpret_cast<std::uintptr_t*>(
|
|
|
|
|
&final_instruction[instruction.length + JMP_RIP_ADDR_IDX]));
|
|
|
|
|
gadget_raw.insert(gadget_raw.end(), gadget.begin(), gadget.end());
|
|
|
|
|
gadget_offset += gadget.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto instruc_alloc =
|
|
|
|
|
reinterpret_cast<void*>(
|
|
|
|
|
mapped_symbols[symbol_name]);
|
|
|
|
|
const auto gadget_addr =
|
|
|
|
|
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;
|
|
|
|
|
std::printf(" > copying gadget at = 0x%p\n", gadget_addr);
|
|
|
|
|
kmemcpy(gadget_addr, gadget_raw.data(), gadget_raw.size());
|
|
|
|
|
// used to calc symbol for next instruction...
|
|
|
|
|
instruc_offset += instruc_len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -359,88 +261,55 @@ namespace drv
|
|
|
|
|
|
|
|
|
|
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& 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)
|
|
|
|
|
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();
|
|
|
|
|
const auto routine_begin =
|
|
|
|
|
symbol.file_offset + obj.data();
|
|
|
|
|
|
|
|
|
|
bool first_instruction = true;
|
|
|
|
|
std::printf(" > obfuscating %s\n", symbol.symbol_name.c_str());
|
|
|
|
|
|
|
|
|
|
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, routine_begin + offset, length - offset,
|
|
|
|
|
&instruction)))
|
|
|
|
|
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
|
|
|
|
|
&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)
|
|
|
|
|
first_instruction = false;
|
|
|
|
|
else
|
|
|
|
|
symbol_name.append("@")
|
|
|
|
|
new_symbol.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::vector<std::uint8_t> instruc_bytes{};
|
|
|
|
|
instruc_bytes.resize(instruction.length);
|
|
|
|
|
|
|
|
|
|
memcpy(instruc_bytes.data(), obj.data() +
|
|
|
|
|
symbol.file_offset + offset, instruction.length);
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<obfuscation::obfuscate> new_gadget(
|
|
|
|
|
new obfuscation::obfuscate({ instruction, instruc_bytes }));
|
|
|
|
|
|
|
|
|
|
mapped_symbols[new_symbol] =
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(
|
|
|
|
|
kalloc(new_gadget->get_size()));
|
|
|
|
|
|
|
|
|
|
std::printf(" > %s allocated = 0x%p\n",
|
|
|
|
|
symbol_name.c_str(), mapped_symbols[symbol_name]);
|
|
|
|
|
obfuscated_gadgets[mapped_symbols[new_symbol]] = new_gadget;
|
|
|
|
|
std::printf(" > %s allocated = 0x%p, size = %d\n", new_symbol.c_str(),
|
|
|
|
|
mapped_symbols[new_symbol], new_gadget->get_size());
|
|
|
|
|
|
|
|
|
|
offset += instruction.length;
|
|
|
|
|
}
|
|
|
|
@ -462,7 +331,7 @@ namespace drv
|
|
|
|
|
mapped_symbols[symbol.symbol_name] =
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|