From 20bce8a1d44f60a02227d4a31422395a24a27913 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Sat, 6 Mar 2021 19:35:38 -0800 Subject: [PATCH] recoded how "gadgets" are allocated... much more modular now --- Theodosius/hmdm_ctx.cpp | 447 +++++++++---------------- Theodosius/hmdm_ctx.h | 14 +- Theodosius/linker/linker.cpp | 3 + Theodosius/main.cpp | 8 +- Theodosius/obfuscation/obfuscation.cpp | 107 ++++++ Theodosius/obfuscation/obfuscation.hpp | 50 +++ 6 files changed, 332 insertions(+), 297 deletions(-) diff --git a/Theodosius/hmdm_ctx.cpp b/Theodosius/hmdm_ctx.cpp index f7ebaa6..513d5d8 100644 --- a/Theodosius/hmdm_ctx.cpp +++ b/Theodosius/hmdm_ctx.cpp @@ -3,43 +3,50 @@ 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& 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( 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; @@ -134,223 +141,118 @@ namespace drv { if (!symbol.obfuscate_type) continue; + + std::printf(" > mapping obfuscated routine %s into memory...\n", symbol.symbol_name.c_str()); - 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( - 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; - 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 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(&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(&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(&final_instruction[ - instruction.length + JMP_RIP_ADDR_IDX]) = mapped_symbols[next_instruction_symbol]; - - const auto instruc_alloc = - reinterpret_cast( - 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 final_instruction; - final_instruction.resize(JMP_RIP_SIZE); - memset(final_instruction.data(), NULL, final_instruction.size()); - *reinterpret_cast( - &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( - 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 final_instruction; - final_instruction.resize(instruction.length); + const auto gadget_size = obfuscated_gadgets + [mapped_symbols[symbol_name]]->get_size(); - // copy instruction into buffer... - memcpy(final_instruction.data(), - obj.data() + symbol.file_offset + offset, instruction.length); + unsigned gadget_offset = 0u; + std::vector gadget_raw; - const auto instruc_alloc = - reinterpret_cast( - 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... + for (auto& [gadget, reloc] : gadget_stack) { - std::vector final_instruction; - // resize buffer so that jmp [rip] can fit... - final_instruction.resize(instruction.length + JMP_RIP_SIZE); + const auto fix_reloc_addr = + gadget.data() + reloc.offset; - // 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); + 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( - &final_instruction[instruction.length + JMP_RIP_ADDR_IDX]) = - mapped_symbols[next_instruction_symbol]; + *reinterpret_cast(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( + 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( - &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( - mapped_symbols[symbol_name]); + const auto gadget_addr = + reinterpret_cast( + 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& 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( - kalloc(instruction.length + (JMP_RIP_SIZE * 2))); - break; - } - case ZYDIS_MNEMONIC_JMP: - { - mapped_symbols[symbol_name] = - reinterpret_cast( - kalloc(JMP_RIP_SIZE)); - break; - } - case ZYDIS_MNEMONIC_RET: - { - mapped_symbols[symbol_name] = - reinterpret_cast( - kalloc(instruction.length)); - break; - } - default: // not a JCC, JMP, or RET... - { - mapped_symbols[symbol_name] = - reinterpret_cast( - kalloc(instruction.length + JMP_RIP_SIZE)); - break; - } - } + std::vector instruc_bytes{}; + instruc_bytes.resize(instruction.length); + + memcpy(instruc_bytes.data(), obj.data() + + symbol.file_offset + offset, instruction.length); + + std::shared_ptr new_gadget( + new obfuscation::obfuscate({ instruction, instruc_bytes })); + + mapped_symbols[new_symbol] = + reinterpret_cast( + 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(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); } } diff --git a/Theodosius/hmdm_ctx.h b/Theodosius/hmdm_ctx.h index 49f2ff2..bbb3621 100644 --- a/Theodosius/hmdm_ctx.h +++ b/Theodosius/hmdm_ctx.h @@ -1,6 +1,7 @@ #pragma once #include "utils.hpp" #include "linker/linker.hpp" +#include "obfuscation/obfuscation.hpp" #include #include @@ -9,23 +10,19 @@ #include #include #include +#include #include -#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") namespace drv { using kalloc_t = std::function; using kmemcpy_t = std::function; using kmemset_t = std::function; + using resolve_symbol_t = std::function; using image_entry_t = std::uintptr_t; - using mapper_routines_t = std::pair; + using mapper_routines_t = std::tuple; class hmdm_ctx { @@ -35,6 +32,7 @@ namespace drv kalloc_t kalloc; kmemcpy_t kmemcpy; + resolve_symbol_t resolve_symbol; private: bool map_symbols(std::vector& objs); bool map_obfuscated_symbols(std::vector& objs); @@ -42,6 +40,8 @@ namespace drv bool resolve_relocs(std::vector& objs); bool alloc_obfuscated_symbol_space(std::vector& objs); bool alloc_symbol_space(std::vector& objs); + std::map mapped_symbols; + std::map> obfuscated_gadgets; }; } \ No newline at end of file diff --git a/Theodosius/linker/linker.cpp b/Theodosius/linker/linker.cpp index bb917a0..51bb956 100644 --- a/Theodosius/linker/linker.cpp +++ b/Theodosius/linker/linker.cpp @@ -57,6 +57,9 @@ namespace lnk const auto obj_size = std::atoi( reinterpret_cast(archive_headers->Size)); + if (archive_headers->EndHeader[0] != 0x60 || archive_headers->EndHeader[1] != 0x0A) + break; + if (!obj_size) break; diff --git a/Theodosius/main.cpp b/Theodosius/main.cpp index 1e8cd24..1c89ab0 100644 --- a/Theodosius/main.cpp +++ b/Theodosius/main.cpp @@ -87,8 +87,14 @@ int main(int argc, char** argv) { return memcpy(dest, src, size); }; + + 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 }); + drv::hmdm_ctx drv_mapper({ _kalloc, _kmemcpy, resolve_symbol }); const auto drv_entry = drv_mapper.map_objs(image_objs); std::printf("\n\n> driver entry -> 0x%p\n", drv_entry); diff --git a/Theodosius/obfuscation/obfuscation.cpp b/Theodosius/obfuscation/obfuscation.cpp index e69de29..27b9fb6 100644 --- a/Theodosius/obfuscation/obfuscation.cpp +++ b/Theodosius/obfuscation/obfuscation.cpp @@ -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(rva_fix_addr)); + + // when you inherit obfuscate please be mindful of JCC rvas... + *reinterpret_cast(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; + } +} \ No newline at end of file diff --git a/Theodosius/obfuscation/obfuscation.hpp b/Theodosius/obfuscation/obfuscation.hpp index 05e9075..9a3e536 100644 --- a/Theodosius/obfuscation/obfuscation.hpp +++ b/Theodosius/obfuscation/obfuscation.hpp @@ -1,7 +1,57 @@ #include #include +#include +#include +#include + +#define JMP_RIP_SIZE 14 +#define JMP_RIP_ADDR_IDX 6 namespace obfuscation { + inline const std::vector 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>; + using gadget_stack_t = std::vector, 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); + };*/ } \ No newline at end of file