diff --git a/.clang-format b/.clang-format deleted file mode 100644 index c721414..0000000 --- a/.clang-format +++ /dev/null @@ -1,10 +0,0 @@ ---- -BreakBeforeBraces: GNU -CompactNamespaces: 'false' -FixNamespaceComments: 'true' -NamespaceIndentation: All -ObjCBinPackProtocolList: Always -Standard: Cpp11 -UseTab: Always - -... diff --git a/src/calc_jmp.cpp b/src/calc_jmp.cpp index f8b26b3..8d47395 100644 --- a/src/calc_jmp.cpp +++ b/src/calc_jmp.cpp @@ -2,34 +2,32 @@ namespace vm { - namespace calc_jmp - { - bool get(const zydis_routine_t &vm_entry, zydis_routine_t &calc_jmp) - { - auto result = std::find_if( - vm_entry.begin(), vm_entry.end(), - [](const zydis_instr_t &instr_data) -> bool { - // mov/movsx/movzx rax/eax/ax/al, [rsi] - if (instr_data.instr.operand_count > 1 && - (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && - instr_data.instr.operands[0].type == - ZYDIS_OPERAND_TYPE_REGISTER && - util::reg::to64(instr_data.instr.operands[0].reg.value) == - ZYDIS_REGISTER_RAX && - instr_data.instr.operands[1].type == - ZYDIS_OPERAND_TYPE_MEMORY && - instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) - return true; - return false; - }); + namespace calc_jmp + { + bool get(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp) + { + auto result = std::find_if(vm_entry.begin(), vm_entry.end(), + [](const zydis_instr_t& instr_data) -> bool + { + // mov/movsx/movzx rax/eax/ax/al, [rsi] + if (instr_data.instr.operand_count > 1 && + (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && + instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX && + instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) + return true; + return false; + } + ); - if (result == vm_entry.end()) - return false; + if (result == vm_entry.end()) + return false; - calc_jmp.insert(calc_jmp.end(), result, vm_entry.end()); - return true; - } - } // namespace calc_jmp -} // namespace vm \ No newline at end of file + calc_jmp.insert(calc_jmp.end(), result, vm_entry.end()); + return true; + } + } +} \ No newline at end of file diff --git a/src/vmhandler.cpp b/src/vmhandler.cpp index 443d5c5..17c8584 100644 --- a/src/vmhandler.cpp +++ b/src/vmhandler.cpp @@ -2,407 +2,398 @@ namespace vm { - namespace handler - { - bool get(zydis_routine_t &calc_jmp, zydis_routine_t &vm_handler, - std::uintptr_t handler_addr) - { - if (!vm::util::flatten(vm_handler, handler_addr)) - return false; - - vm::util::deobfuscate(vm_handler); - - static const auto calc_jmp_check = [&](std::uintptr_t addr) -> bool { - for (const auto &[instr, instr_raw, instr_addr] : calc_jmp) - if (instr_addr == addr) - return true; - - return false; - }; - - auto result = std::find_if( - vm_handler.begin(), vm_handler.end(), - [](const zydis_instr_t &instr) -> bool { - if (instr.instr.mnemonic == ZYDIS_MNEMONIC_LEA && - instr.instr.operands[0].reg.value == ZYDIS_REGISTER_RAX && - instr.instr.operands[1].mem.base == ZYDIS_REGISTER_RDI && - instr.instr.operands[1].mem.disp.value == 0xE0) - return true; - - return calc_jmp_check(instr.addr); - }); - - // remove calc_jmp from the vm handler vector... - if (result != vm_handler.end()) - vm_handler.erase(result, vm_handler.end()); - else // locate the last mov al, [rsi], - // then remove all instructions after that... + namespace handler { - zydis_routine_t::iterator last = vm_handler.end(); - result = vm_handler.begin(); - - while (result != vm_handler.end()) - { - result = std::find_if( - ++result, vm_handler.end(), - [](const zydis_instr_t &instr_data) -> bool { - // mov/movsx/movzx rax/eax/ax/al, [rsi] - if (instr_data.instr.operand_count > 1 && - (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && - instr_data.instr.operands[0].type == - ZYDIS_OPERAND_TYPE_REGISTER && - util::reg::to64( - instr_data.instr.operands[0].reg.value) == - ZYDIS_REGISTER_RAX && - instr_data.instr.operands[1].type == - ZYDIS_OPERAND_TYPE_MEMORY && - instr_data.instr.operands[1].mem.base == - ZYDIS_REGISTER_RSI) - return true; - return false; - }); - - if (result != vm_handler.end()) - last = result; - } - - if (last != vm_handler.end()) - vm_handler.erase(last, vm_handler.end()); - } - return true; - } - - bool get_all(std::uintptr_t module_base, std::uintptr_t image_base, - zydis_routine_t &vm_entry, std::uintptr_t *vm_handler_table, - std::vector &vm_handlers) - { - zydis_decoded_instr_t instr; - if (!vm::handler::table::get_transform(vm_entry, &instr)) - return false; - - zydis_routine_t calc_jmp; - if (!vm::calc_jmp::get(vm_entry, calc_jmp)) - return false; - - for (auto idx = 0u; idx < 256; ++idx) - { - const auto decrypt_val = - vm::handler::table::decrypt(instr, vm_handler_table[idx]); + bool get(zydis_routine_t& calc_jmp, zydis_routine_t& vm_handler, std::uintptr_t handler_addr) + { + if (!vm::util::flatten(vm_handler, handler_addr)) + return false; + + vm::util::deobfuscate(vm_handler); + + static const auto calc_jmp_check = + [&](std::uintptr_t addr) -> bool + { + for (const auto& [instr, instr_raw, instr_addr] : calc_jmp) + if (instr_addr == addr) + return true; + + return false; + }; + + auto result = std::find_if( + vm_handler.begin(), vm_handler.end(), + [](const zydis_instr_t& instr) -> bool + { + if (instr.instr.mnemonic == ZYDIS_MNEMONIC_LEA && + instr.instr.operands[0].reg.value == ZYDIS_REGISTER_RAX && + instr.instr.operands[1].mem.base == ZYDIS_REGISTER_RDI && + instr.instr.operands[1].mem.disp.value == 0xE0) + return true; + + return calc_jmp_check(instr.addr); + } + ); + + // remove calc_jmp from the vm handler vector... + if (result != vm_handler.end()) + vm_handler.erase(result, vm_handler.end()); + else // locate the last mov al, [rsi], + // then remove all instructions after that... + { + zydis_routine_t::iterator last = vm_handler.end(); + result = vm_handler.begin(); + + while (result != vm_handler.end()) + { + result = std::find_if( + ++result, vm_handler.end(), + [](const zydis_instr_t& instr_data) -> bool + { + // mov/movsx/movzx rax/eax/ax/al, [rsi] + if (instr_data.instr.operand_count > 1 && + (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && + instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX && + instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) + return true; + return false; + } + ); + + if (result != vm_handler.end()) + last = result; + } + + if (last != vm_handler.end()) + vm_handler.erase(last, vm_handler.end()); + } + return true; + } - handler_t vm_handler; - vm::transform::map_t transforms; - zydis_routine_t vm_handler_instrs; + bool get_all(std::uintptr_t module_base, std::uintptr_t image_base, + zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector& vm_handlers) + { + zydis_decoded_instr_t instr; + if (!vm::handler::table::get_transform(vm_entry, &instr)) + return false; - if (!vm::handler::get(calc_jmp, vm_handler_instrs, - (decrypt_val - image_base) + module_base)) - return false; + zydis_routine_t calc_jmp; + if (!vm::calc_jmp::get(vm_entry, calc_jmp)) + return false; - const auto has_imm = vm::handler::has_imm(vm_handler_instrs); + for (auto idx = 0u; idx < 256; ++idx) + { + const auto decrypt_val = + vm::handler::table::decrypt( + instr, vm_handler_table[idx]); - const auto imm_size = vm::handler::imm_size(vm_handler_instrs); + handler_t vm_handler; + vm::transform::map_t transforms; + zydis_routine_t vm_handler_instrs; - if (has_imm && !vm::handler::get_operand_transforms(vm_handler_instrs, - transforms)) - return false; + if (!vm::handler::get(calc_jmp, vm_handler_instrs, (decrypt_val - image_base) + module_base)) + return false; - vm_handler.address = (decrypt_val - image_base) + module_base; - vm_handler.instrs = vm_handler_instrs; - vm_handler.imm_size = imm_size; - vm_handler.transforms = transforms; - vm_handler.profile = vm::handler::get_profile(vm_handler); - vm_handlers.push_back(vm_handler); - } + const auto has_imm = + vm::handler::has_imm(vm_handler_instrs); - return true; - } - - bool has_imm(const zydis_routine_t &vm_handler) - { - const auto result = std::find_if( - vm_handler.begin(), vm_handler.end(), - [](const zydis_instr_t &instr_data) -> bool { - // mov/movsx/movzx rax/eax/ax/al, [rsi] - if (instr_data.instr.operand_count > 1 && - (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && - instr_data.instr.operands[0].type == - ZYDIS_OPERAND_TYPE_REGISTER && - util::reg::to64(instr_data.instr.operands[0].reg.value) == - ZYDIS_REGISTER_RAX && - instr_data.instr.operands[1].type == - ZYDIS_OPERAND_TYPE_MEMORY && - instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) - return true; - return false; - }); - - return result != vm_handler.end(); - } - - std::uint8_t imm_size(const zydis_routine_t &vm_handler) - { - const auto result = std::find_if( - vm_handler.begin(), vm_handler.end(), - [](const zydis_instr_t &instr_data) -> bool { - // mov/movsx/movzx rax/eax/ax/al, [rsi] - if (instr_data.instr.operand_count > 1 && - (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && - instr_data.instr.operands[0].type == - ZYDIS_OPERAND_TYPE_REGISTER && - util::reg::to64(instr_data.instr.operands[0].reg.value) == - ZYDIS_REGISTER_RAX && - instr_data.instr.operands[1].type == - ZYDIS_OPERAND_TYPE_MEMORY && - instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) - return true; - return false; - }); - - if (result == vm_handler.end()) - return 0u; - - return result->instr.operands[1].size; - } - - bool get_operand_transforms(const zydis_routine_t &vm_handler, - transform::map_t &transforms) - { - auto imm_fetch = std::find_if( - vm_handler.begin(), vm_handler.end(), - [](const zydis_instr_t &instr_data) -> bool { - // mov/movsx/movzx rax/eax/ax/al, [rsi] - if (instr_data.instr.operand_count > 1 && - (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && - instr_data.instr.operands[0].type == - ZYDIS_OPERAND_TYPE_REGISTER && - util::reg::to64(instr_data.instr.operands[0].reg.value) == - ZYDIS_REGISTER_RAX && - instr_data.instr.operands[1].type == - ZYDIS_OPERAND_TYPE_MEMORY && - instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) - return true; - return false; - }); - - if (imm_fetch == vm_handler.end()) - return false; - - // this finds the first transformation which looks like: - // transform rax, rbx <--- note these registers can be smaller so we to64 - // them... - auto key_transform = std::find_if( - imm_fetch, vm_handler.end(), - [](const zydis_instr_t &instr_data) -> bool { - if (util::reg::compare(instr_data.instr.operands[0].reg.value, - ZYDIS_REGISTER_RAX) && - util::reg::compare(instr_data.instr.operands[1].reg.value, - ZYDIS_REGISTER_RBX)) - return true; - return false; - }); - - if (key_transform == vm_handler.end()) - return false; - - // look for a primer/instruction that alters RAX prior to the 5 - // transformations... - auto generic0 = std::find_if( - imm_fetch + 1, key_transform, - [](const zydis_instr_t &instr_data) -> bool { - return util::reg::compare(instr_data.instr.operands[0].reg.value, - ZYDIS_REGISTER_RAX) && - !util::reg::compare(instr_data.instr.operands[1].reg.value, - ZYDIS_REGISTER_RBX); - }); - - zydis_decoded_instr_t nogeneric0; - nogeneric0.mnemonic = ZYDIS_MNEMONIC_INVALID; - - transforms[transform::type::generic0] = - generic0 != key_transform ? generic0->instr : nogeneric0; - - // last transformation is the same as the first except src and dest are - // swwapped... - transforms[transform::type::rolling_key] = key_transform->instr; - auto instr_copy = key_transform->instr; - instr_copy.operands[0].reg.value = - key_transform->instr.operands[1].reg.value; - instr_copy.operands[1].reg.value = - key_transform->instr.operands[0].reg.value; - transforms[transform::type::update_key] = instr_copy; - - // three generic transformations... - auto generic_transform = key_transform; - - for (auto idx = 2u; idx < 5; ++idx) - { - generic_transform = std::find_if( - ++generic_transform, vm_handler.end(), - [](const zydis_instr_t &instr_data) -> bool { - if (util::reg::compare(instr_data.instr.operands[0].reg.value, - ZYDIS_REGISTER_RAX)) - return true; + const auto imm_size = + vm::handler::imm_size(vm_handler_instrs); - return false; - }); + if (has_imm && !vm::handler::get_operand_transforms(vm_handler_instrs, transforms)) + return false; - if (generic_transform == vm_handler.end()) - return false; + vm_handler.address = (decrypt_val - image_base) + module_base; + vm_handler.instrs = vm_handler_instrs; + vm_handler.imm_size = imm_size; + vm_handler.transforms = transforms; + vm_handler.profile = vm::handler::get_profile(vm_handler); + vm_handlers.push_back(vm_handler); + } - transforms[(transform::type)(idx)] = generic_transform->instr; - } + return true; + } - return true; - } - - vm::handler::profile_t *get_profile(handler_t &vm_handler) - { - static const auto vcontains = [](vm::handler::profile_t *vprofile, - handler_t *vm_handler) -> bool { - if (vprofile->imm_size != vm_handler->imm_size) - return false; - - for (auto &instr : vprofile->signature) - { - const auto contains = std::find_if( - vm_handler->instrs.begin(), vm_handler->instrs.end(), - - [&](zydis_instr_t &instr_data) -> bool { - return instr(instr_data.instr); - }); - - if (contains == vm_handler->instrs.end()) - return false; - } - - return true; - }; - - for (auto profile : vm::handler::profile::all) - if (vcontains(profile, &vm_handler)) - return profile; - - return nullptr; - } - - namespace table - { - std::uintptr_t *get(const zydis_routine_t &vm_entry) - { - const auto result = std::find_if( - vm_entry.begin(), vm_entry.end(), - [](const zydis_instr_t &instr_data) -> bool { - const auto instr = &instr_data.instr; - // lea r12, vm_handlers... (always r12)... - if (instr->mnemonic == ZYDIS_MNEMONIC_LEA && - instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && - instr->operands[0].reg.value == ZYDIS_REGISTER_R12 && - !instr->raw.sib.base) // no register used for the sib base... - return true; - - return false; - }); - - if (result == vm_entry.end()) - return nullptr; - - std::uintptr_t ptr = 0u; - ZydisCalcAbsoluteAddress(&result->instr, &result->instr.operands[1], - result->addr, &ptr); - - return reinterpret_cast(ptr); - } - - bool get_transform(const zydis_routine_t &vm_entry, - zydis_decoded_instr_t *transform_instr) - { - zydis_register_t rcx_or_rdx = ZYDIS_REGISTER_NONE; - - auto handler_fetch = std::find_if( - vm_entry.begin(), vm_entry.end(), - [&](const zydis_instr_t &instr_data) -> bool { - const auto instr = &instr_data.instr; - if (instr->mnemonic == ZYDIS_MNEMONIC_MOV && - instr->operand_count == 2 && - instr->operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && - instr->operands[1].mem.base == ZYDIS_REGISTER_R12 && - instr->operands[1].mem.index == ZYDIS_REGISTER_RAX && - instr->operands[1].mem.scale == 8 && - instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && - (instr->operands[0].reg.value == ZYDIS_REGISTER_RDX || - instr->operands[0].reg.value == ZYDIS_REGISTER_RCX)) + bool has_imm(const zydis_routine_t& vm_handler) { - rcx_or_rdx = instr->operands[0].reg.value; - return true; + const auto result = std::find_if( + vm_handler.begin(), vm_handler.end(), + [](const zydis_instr_t& instr_data) -> bool + { + // mov/movsx/movzx rax/eax/ax/al, [rsi] + if (instr_data.instr.operand_count > 1 && + (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && + instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX && + instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) + return true; + return false; + } + ); + + return result != vm_handler.end(); } - return false; - }); - - // check to see if we found the fetch instruction and if the next - // instruction is not the end of the vector... - if (handler_fetch == vm_entry.end() || - ++handler_fetch == vm_entry.end() || - // must be RCX or RDX... else something went wrong... - (rcx_or_rdx != ZYDIS_REGISTER_RCX && - rcx_or_rdx != ZYDIS_REGISTER_RDX)) - return false; - - // find the next instruction that writes to RCX or RDX... - // the register is determined by the vm handler fetch above... - auto handler_transform = std::find_if( - handler_fetch, vm_entry.end(), - [&](const zydis_instr_t &instr_data) -> bool { - if (instr_data.instr.operands[0].reg.value == rcx_or_rdx && - instr_data.instr.operands[0].actions & - ZYDIS_OPERAND_ACTION_WRITE) - return true; - return false; - }); - - if (handler_transform == vm_entry.end()) - return false; - - *transform_instr = handler_transform->instr; - return true; - } - - std::uint64_t encrypt(zydis_decoded_instr_t &transform_instr, - std::uint64_t val) - { - assert(transform_instr.operands[0].size == 64, - "invalid transformation for vm handler table entries..."); - - const auto operation = vm::transform::inverse[transform_instr.mnemonic]; - const auto bitsize = transform_instr.operands[0].size; - const auto imm = vm::transform::has_imm(&transform_instr) - ? transform_instr.operands[1].imm.value.u - : 0u; - - return vm::transform::apply(bitsize, operation, val, imm); - } - - std::uint64_t decrypt(zydis_decoded_instr_t &transform_instr, - std::uint64_t val) - { - assert(transform_instr.operands[0].size == 64, - "invalid transformation for vm handler table entries..."); - - const auto operation = transform_instr.mnemonic; - const auto bitsize = transform_instr.operands[0].size; - const auto imm = vm::transform::has_imm(&transform_instr) - ? transform_instr.operands[1].imm.value.u - : 0u; - - return vm::transform::apply(bitsize, operation, val, imm); - } - } // namespace table - } // namespace handler -} // namespace vm \ No newline at end of file + std::uint8_t imm_size(const zydis_routine_t& vm_handler) + { + const auto result = std::find_if( + vm_handler.begin(), vm_handler.end(), + [](const zydis_instr_t& instr_data) -> bool + { + // mov/movsx/movzx rax/eax/ax/al, [rsi] + if (instr_data.instr.operand_count > 1 && + (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && + instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX && + instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) + return true; + return false; + } + ); + + if (result == vm_handler.end()) + return 0u; + + return result->instr.operands[1].size; + } + + bool get_operand_transforms(const zydis_routine_t& vm_handler, transform::map_t& transforms) + { + auto imm_fetch = std::find_if( + vm_handler.begin(), vm_handler.end(), + [](const zydis_instr_t& instr_data) -> bool + { + // mov/movsx/movzx rax/eax/ax/al, [rsi] + if (instr_data.instr.operand_count > 1 && + (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) && + instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX && + instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI) + return true; + return false; + } + ); + + if (imm_fetch == vm_handler.end()) + return false; + + // this finds the first transformation which looks like: + // transform rax, rbx <--- note these registers can be smaller so we to64 them... + auto key_transform = std::find_if(imm_fetch, vm_handler.end(), + [](const zydis_instr_t& instr_data) -> bool + { + if (util::reg::compare(instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX) && + util::reg::compare(instr_data.instr.operands[1].reg.value, ZYDIS_REGISTER_RBX)) + return true; + return false; + } + ); + + if (key_transform == vm_handler.end()) + return false; + + // look for a primer/instruction that alters RAX prior to the 5 transformations... + auto generic0 = std::find_if(imm_fetch + 1, key_transform, + [](const zydis_instr_t& instr_data) -> bool + { + return util::reg::compare( + instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX) && + !util::reg::compare(instr_data.instr.operands[1].reg.value, ZYDIS_REGISTER_RBX); + } + ); + + zydis_decoded_instr_t nogeneric0; + nogeneric0.mnemonic = ZYDIS_MNEMONIC_INVALID; + + transforms[transform::type::generic0] = + generic0 != key_transform ? generic0->instr : nogeneric0; + + // last transformation is the same as the first except src and dest are swwapped... + transforms[transform::type::rolling_key] = key_transform->instr; + auto instr_copy = key_transform->instr; + instr_copy.operands[0].reg.value = key_transform->instr.operands[1].reg.value; + instr_copy.operands[1].reg.value = key_transform->instr.operands[0].reg.value; + transforms[transform::type::update_key] = instr_copy; + + // three generic transformations... + auto generic_transform = key_transform; + + for (auto idx = 2u; idx < 5; ++idx) + { + generic_transform = std::find_if(++generic_transform, vm_handler.end(), + [](const zydis_instr_t& instr_data) -> bool + { + if (util::reg::compare(instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX)) + return true; + + return false; + } + ); + + if (generic_transform == vm_handler.end()) + return false; + + transforms[(transform::type)(idx)] = generic_transform->instr; + } + + return true; + } + + vm::handler::profile_t* get_profile(handler_t& vm_handler) + { + static const auto vcontains = + [](vm::handler::profile_t* vprofile, handler_t* vm_handler) -> bool + { + if (vprofile->imm_size != vm_handler->imm_size) + return false; + + for (auto& instr : vprofile->signature) + { + const auto contains = std::find_if + ( + vm_handler->instrs.begin(), + vm_handler->instrs.end(), + + [&](zydis_instr_t& instr_data) -> bool + { return instr(instr_data.instr); } + ); + + if (contains == vm_handler->instrs.end()) + return false; + } + + return true; + }; + + for (auto profile : vm::handler::profile::all) + if (vcontains(profile, &vm_handler)) + return profile; + + return nullptr; + } + + namespace table + { + std::uintptr_t* get(const zydis_routine_t& vm_entry) + { + const auto result = std::find_if( + vm_entry.begin(), vm_entry.end(), + [](const zydis_instr_t& instr_data) -> bool + { + const auto instr = &instr_data.instr; + // lea r12, vm_handlers... (always r12)... + if (instr->mnemonic == ZYDIS_MNEMONIC_LEA && + instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + instr->operands[0].reg.value == ZYDIS_REGISTER_R12 && + !instr->raw.sib.base) // no register used for the sib base... + return true; + + return false; + } + ); + + if (result == vm_entry.end()) + return nullptr; + + std::uintptr_t ptr = 0u; + ZydisCalcAbsoluteAddress(&result->instr, + &result->instr.operands[1], result->addr, &ptr); + + return reinterpret_cast(ptr); + } + + bool get_transform(const zydis_routine_t& vm_entry, zydis_decoded_instr_t* transform_instr) + { + zydis_register_t rcx_or_rdx = ZYDIS_REGISTER_NONE; + + auto handler_fetch = std::find_if( + vm_entry.begin(), vm_entry.end(), + [&](const zydis_instr_t& instr_data) -> bool + { + const auto instr = &instr_data.instr; + if (instr->mnemonic == ZYDIS_MNEMONIC_MOV && + instr->operand_count == 2 && + instr->operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr->operands[1].mem.base == ZYDIS_REGISTER_R12 && + instr->operands[1].mem.index == ZYDIS_REGISTER_RAX && + instr->operands[1].mem.scale == 8 && + instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + (instr->operands[0].reg.value == ZYDIS_REGISTER_RDX || + instr->operands[0].reg.value == ZYDIS_REGISTER_RCX)) + { + rcx_or_rdx = instr->operands[0].reg.value; + return true; + } + + return false; + } + ); + + // check to see if we found the fetch instruction and if the next instruction + // is not the end of the vector... + if (handler_fetch == vm_entry.end() || ++handler_fetch == vm_entry.end() || + // must be RCX or RDX... else something went wrong... + (rcx_or_rdx != ZYDIS_REGISTER_RCX && rcx_or_rdx != ZYDIS_REGISTER_RDX)) + return false; + + // find the next instruction that writes to RCX or RDX... + // the register is determined by the vm handler fetch above... + auto handler_transform = std::find_if( + handler_fetch, vm_entry.end(), + [&](const zydis_instr_t& instr_data) -> bool + { + if (instr_data.instr.operands[0].reg.value == rcx_or_rdx && + instr_data.instr.operands[0].actions & ZYDIS_OPERAND_ACTION_WRITE) + return true; + return false; + } + ); + + if (handler_transform == vm_entry.end()) + return false; + + *transform_instr = handler_transform->instr; + return true; + } + + std::uint64_t encrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val) + { + assert(transform_instr.operands[0].size == 64, + "invalid transformation for vm handler table entries..."); + + const auto operation = vm::transform::inverse[transform_instr.mnemonic]; + const auto bitsize = transform_instr.operands[0].size; + const auto imm = vm::transform::has_imm(&transform_instr) ? + transform_instr.operands[1].imm.value.u : 0u; + + return vm::transform::apply(bitsize, operation, val, imm); + } + + std::uint64_t decrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val) + { + assert(transform_instr.operands[0].size == 64, + "invalid transformation for vm handler table entries..."); + + const auto operation = transform_instr.mnemonic; + const auto bitsize = transform_instr.operands[0].size; + const auto imm = vm::transform::has_imm(&transform_instr) ? + transform_instr.operands[1].imm.value.u : 0u; + + return vm::transform::apply(bitsize, operation, val, imm); + } + } + } +} \ No newline at end of file diff --git a/src/vminstrs.cpp b/src/vminstrs.cpp index 06dc44f..3589a84 100644 --- a/src/vminstrs.cpp +++ b/src/vminstrs.cpp @@ -2,191 +2,190 @@ namespace vm { - namespace instrs - { - std::pair - decrypt_operand(transform::map_t &transforms, std::uint64_t operand, - std::uint64_t rolling_key) - { - const auto generic_decrypt_0 = &transforms[transform::type::generic0]; - const auto key_decrypt = &transforms[transform::type::rolling_key]; - const auto generic_decrypt_1 = &transforms[transform::type::generic1]; - const auto generic_decrypt_2 = &transforms[transform::type::generic2]; - const auto generic_decrypt_3 = &transforms[transform::type::generic3]; - const auto update_key = &transforms[transform::type::update_key]; - - if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID) + namespace instrs { - operand = - transform::apply(generic_decrypt_0->operands[0].size, - generic_decrypt_0->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_0) - ? generic_decrypt_0->operands[1].imm.value.u - : 0); + std::pair decrypt_operand(transform::map_t& transforms, + std::uint64_t operand, std::uint64_t rolling_key) + { + const auto generic_decrypt_0 = &transforms[transform::type::generic0]; + const auto key_decrypt = &transforms[transform::type::rolling_key]; + const auto generic_decrypt_1 = &transforms[transform::type::generic1]; + const auto generic_decrypt_2 = &transforms[transform::type::generic2]; + const auto generic_decrypt_3 = &transforms[transform::type::generic3]; + const auto update_key = &transforms[transform::type::update_key]; + + if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID) + { + operand = transform::apply( + generic_decrypt_0->operands[0].size, + generic_decrypt_0->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_0) ? + generic_decrypt_0->operands[1].imm.value.u : 0); + } + + // apply transformation with rolling decrypt key... + operand = transform::apply(key_decrypt->operands[0].size, + key_decrypt->mnemonic, operand, rolling_key); + + // apply three generic transformations... + { + operand = transform::apply( + generic_decrypt_1->operands[0].size, + generic_decrypt_1->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_1) ? + generic_decrypt_1->operands[1].imm.value.u : 0); + + operand = transform::apply( + generic_decrypt_2->operands[0].size, + generic_decrypt_2->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_2) ? + generic_decrypt_2->operands[1].imm.value.u : 0); + + operand = transform::apply( + generic_decrypt_3->operands[0].size, + generic_decrypt_3->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_3) ? + generic_decrypt_3->operands[1].imm.value.u : 0); + } + + // update rolling key... + auto result = transform::apply(update_key->operands[0].size, + update_key->mnemonic, rolling_key, operand); + + // update decryption key correctly... + switch (update_key->operands[0].size) + { + case 8: + rolling_key = (rolling_key & ~0xFFull) + result; + break; + case 16: + rolling_key = (rolling_key & ~0xFFFFull) + result; + break; + default: + rolling_key = result; + break; + } + + return { operand, rolling_key }; + } + + std::pair encrypt_operand(transform::map_t& transforms, + std::uint64_t operand, std::uint64_t rolling_key) + { + transform::map_t inverse; + inverse_transforms(transforms, inverse); + + const auto generic_decrypt_0 = &inverse[transform::type::generic0]; + const auto key_decrypt = &inverse[transform::type::rolling_key]; + const auto generic_decrypt_1 = &inverse[transform::type::generic1]; + const auto generic_decrypt_2 = &inverse[transform::type::generic2]; + const auto generic_decrypt_3 = &inverse[transform::type::generic3]; + const auto update_key = &inverse[transform::type::update_key]; + + auto result = transform::apply(update_key->operands[0].size, + update_key->mnemonic, rolling_key, operand); + + // make sure we update the rolling decryption key correctly... + switch (update_key->operands[0].size) + { + case 8: + rolling_key = (rolling_key & ~0xFFull) + result; + break; + case 16: + rolling_key = (rolling_key & ~0xFFFFull) + result; + break; + default: + rolling_key = result; + break; + } + + { + operand = transform::apply( + generic_decrypt_3->operands[0].size, + generic_decrypt_3->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_3) ? + generic_decrypt_3->operands[1].imm.value.u : 0); + + operand = transform::apply( + generic_decrypt_2->operands[0].size, + generic_decrypt_2->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_2) ? + generic_decrypt_2->operands[1].imm.value.u : 0); + + operand = transform::apply( + generic_decrypt_1->operands[0].size, + generic_decrypt_1->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_1) ? + generic_decrypt_1->operands[1].imm.value.u : 0); + } + + operand = transform::apply(key_decrypt->operands[0].size, + key_decrypt->mnemonic, operand, rolling_key); + + if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID) + { + operand = transform::apply( + generic_decrypt_0->operands[0].size, + generic_decrypt_0->mnemonic, operand, + // check to see if this instruction has an IMM... + transform::has_imm(generic_decrypt_0) ? + generic_decrypt_0->operands[1].imm.value.u : 0); + } + + return { operand, rolling_key }; + } + + bool get_rva_decrypt( + const zydis_routine_t& vm_entry, std::vector& transform_instrs) + { + // + // find mov esi, [rsp+0xA0] + // + + auto result = std::find_if(vm_entry.begin(), vm_entry.end(), + [](const zydis_instr_t& instr_data) -> bool + { + if (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV && + instr_data.instr.operand_count == 2 && + instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI && + instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSP && + instr_data.instr.operands[1].mem.disp.has_displacement && + instr_data.instr.operands[1].mem.disp.value == 0xA0) + return true; + return false; + } + ); + + if (result == vm_entry.end()) + return false; + + // + // find the next three instruction with ESI as the dest... + // + + for (auto idx = 0u; idx < 3; ++idx) + { + result = std::find_if(++result, vm_entry.end(), + [](const zydis_instr_t& instr_data) -> bool + { + return instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI; + } + ); + + if (result == vm_entry.end()) + return false; + + transform_instrs.push_back(result->instr); + } + + return true; + } } - - // apply transformation with rolling decrypt key... - operand = transform::apply(key_decrypt->operands[0].size, - key_decrypt->mnemonic, operand, rolling_key); - - // apply three generic transformations... - operand = - transform::apply(generic_decrypt_1->operands[0].size, - generic_decrypt_1->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_1) - ? generic_decrypt_1->operands[1].imm.value.u - : 0); - - operand = - transform::apply(generic_decrypt_2->operands[0].size, - generic_decrypt_2->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_2) - ? generic_decrypt_2->operands[1].imm.value.u - : 0); - - operand = - transform::apply(generic_decrypt_3->operands[0].size, - generic_decrypt_3->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_3) - ? generic_decrypt_3->operands[1].imm.value.u - : 0); - - // update rolling key... - auto result = - transform::apply(update_key->operands[0].size, update_key->mnemonic, - rolling_key, operand); - - // update decryption key correctly... - switch (update_key->operands[0].size) - { - case 8: - rolling_key = (rolling_key & ~0xFFull) + result; - break; - case 16: - rolling_key = (rolling_key & ~0xFFFFull) + result; - break; - default: - rolling_key = result; - break; - } - - return {operand, rolling_key}; - } - - std::pair - encrypt_operand(transform::map_t &transforms, std::uint64_t operand, - std::uint64_t rolling_key) - { - transform::map_t inverse; - inverse_transforms(transforms, inverse); - - const auto generic_decrypt_0 = &inverse[transform::type::generic0]; - const auto key_decrypt = &inverse[transform::type::rolling_key]; - const auto generic_decrypt_1 = &inverse[transform::type::generic1]; - const auto generic_decrypt_2 = &inverse[transform::type::generic2]; - const auto generic_decrypt_3 = &inverse[transform::type::generic3]; - const auto update_key = &inverse[transform::type::update_key]; - - auto result = - transform::apply(update_key->operands[0].size, update_key->mnemonic, - rolling_key, operand); - - // make sure we update the rolling decryption key correctly... - switch (update_key->operands[0].size) - { - case 8: - rolling_key = (rolling_key & ~0xFFull) + result; - break; - case 16: - rolling_key = (rolling_key & ~0xFFFFull) + result; - break; - default: - rolling_key = result; - break; - } - - operand = - transform::apply(generic_decrypt_3->operands[0].size, - generic_decrypt_3->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_3) - ? generic_decrypt_3->operands[1].imm.value.u - : 0); - - operand = - transform::apply(generic_decrypt_2->operands[0].size, - generic_decrypt_2->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_2) - ? generic_decrypt_2->operands[1].imm.value.u - : 0); - - operand = - transform::apply(generic_decrypt_1->operands[0].size, - generic_decrypt_1->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_1) - ? generic_decrypt_1->operands[1].imm.value.u - : 0); - - operand = transform::apply(key_decrypt->operands[0].size, - key_decrypt->mnemonic, operand, rolling_key); - - if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID) - { - operand = - transform::apply(generic_decrypt_0->operands[0].size, - generic_decrypt_0->mnemonic, operand, - // check to see if this instruction has an IMM... - transform::has_imm(generic_decrypt_0) - ? generic_decrypt_0->operands[1].imm.value.u - : 0); - } - - return {operand, rolling_key}; - } - - bool get_rva_decrypt(const zydis_routine_t &vm_entry, - std::vector &transform_instrs) - { - // find mov esi, [rsp+0xA0] - auto result = std::find_if( - vm_entry.begin(), vm_entry.end(), - [](const zydis_instr_t &instr_data) -> bool { - if (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV && - instr_data.instr.operand_count == 2 && - instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI && - instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSP && - instr_data.instr.operands[1].mem.disp.has_displacement && - instr_data.instr.operands[1].mem.disp.value == 0xA0) - return true; - return false; - }); - - if (result == vm_entry.end()) - return false; - - // find the next three instruction with ESI as the dest... - for (auto idx = 0u; idx < 3; ++idx) - { - result = - std::find_if(++result, vm_entry.end(), - [](const zydis_instr_t &instr_data) -> bool { - return instr_data.instr.operands[0].reg.value == - ZYDIS_REGISTER_ESI; - }); - - if (result == vm_entry.end()) - return false; - - transform_instrs.push_back(result->instr); - } - - return true; - } - } // namespace instrs -} // namespace vm \ No newline at end of file +} \ No newline at end of file diff --git a/src/vmprofiler.vcxproj.filters b/src/vmprofiler.vcxproj.filters index cf954f0..e8d15e1 100644 --- a/src/vmprofiler.vcxproj.filters +++ b/src/vmprofiler.vcxproj.filters @@ -1,206 +1,227 @@ -< ? xml version = "1.0" encoding = - "utf-8" ? > - - {4FC737F1 - C7A5 - 4376 - A066 - - 2A32D752A2FF} - cpp; -c; -cc; -cxx; -c++; -cppm; -ixx; -def; -odl; -idl; -hpj; -bat; -asm; -asmx{ - 93995380 - 89BD - 4b04 - 88EB - 625FBE52EBFB} - h; -hh; -hpp; -hxx; -h++; -hm; -inl; -inc; -ipp; -xsd - {b85373f1 - 1f33 - 4b4f - aadd - - 04432b6d62f0} - { - f57dabfd - 2fe1 - 46a9 - 96d5 - 990cd620eda3} - - {40b5c3d5 - 2a68 - 4f45 - b655 - - b621ef669204} - { - 4dc3025a - a1f4 - 460d - b992 - 1ed53e44f2c0} - { - a4d9e340 - 8f8c - 4606 - bce8 - 58b86119c829} - { - 388154c1 - cb08 - 493f - 88fb - 7e16cfffa010} - - Source Files - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - - Source Files\vmprofiles - Source Files - - Source Files - Source Files - - - Header Files - - Header Files - Header Files - - Header Files\Zydis\Generated - - Header Files\Zydis\Generated - - Header Files\Zydis\Generated - - Header Files\Zydis\Generated - - Header Files\Zydis\Generated - - Header Files\Zydis\Internal - - Header Files\Zydis\Internal - - Header Files\Zydis\Internal - - Header Files\Zydis\Internal - - Header Files\Zydis\Internal - - Header Files\Zydis\Internal - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zydis - - Header Files\Zycore\API - - Header Files\Zycore\API - - Header Files\Zycore\API - - Header Files\Zycore\API - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files\Zycore - - Header Files - - Header Files \ No newline at end of file + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {b85373f1-1f33-4b4f-aadd-04432b6d62f0} + + + {f57dabfd-2fe1-46a9-96d5-990cd620eda3} + + + {40b5c3d5-2a68-4f45-b655-b621ef669204} + + + {4dc3025a-a1f4-460d-b992-1ed53e44f2c0} + + + {a4d9e340-8f8c-4606-bce8-58b86119c829} + + + {388154c1-cb08-493f-88fb-7e16cfffa010} + + + + + Source Files + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files\vmprofiles + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Generated + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zycore\API + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files\Zycore + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/src/vmutils.cpp b/src/vmutils.cpp index 90779c5..1890a01 100644 --- a/src/vmutils.cpp +++ b/src/vmutils.cpp @@ -3,229 +3,226 @@ namespace vm { - namespace util - { - namespace reg + namespace util { - zydis_register_t to64(zydis_register_t reg) - { - return ZydisRegisterGetLargestEnclosing(ZYDIS_MACHINE_MODE_LONG_64, - reg); - } - - bool compare(zydis_register_t a, zydis_register_t b) - { - return to64(a) == to64(b); - } - } // namespace reg - - void print(const zydis_decoded_instr_t &instr) - { - char buffer[256]; - ZydisFormatter formatter; - ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); - ZydisFormatterFormatInstruction(&formatter, &instr, buffer, - sizeof(buffer), 0u); - - puts(buffer); - } - - void print(zydis_routine_t &routine) - { - char buffer[256]; - ZydisFormatter formatter; - ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); - - for (auto [instr, raw, addr] : routine) - { - std::printf("> 0x%p ", addr); - ZydisFormatterFormatInstruction(&formatter, &instr, buffer, - sizeof(buffer), addr); - - puts(buffer); - } - } - - bool is_jmp(const zydis_decoded_instr_t &instr) - { - switch (instr.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_JMP: - 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: - return true; - default: - break; - } - return false; - } - - bool flatten(zydis_routine_t &routine, std::uintptr_t routine_addr, - bool keep_jmps) - { - ZydisDecoder decoder; - zydis_decoded_instr_t instr; - ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, - ZYDIS_ADDRESS_WIDTH_64); - - while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer( - &decoder, reinterpret_cast(routine_addr), 0x1000, &instr))) - { - std::vector raw_instr; - raw_instr.insert(raw_instr.begin(), (u8 *)routine_addr, - (u8 *)routine_addr + instr.length); - - if (is_jmp(instr)) - { - if (instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER) - { - routine.push_back({instr, raw_instr, routine_addr}); - return true; - } - - if (keep_jmps) - routine.push_back({instr, raw_instr, routine_addr}); - - ZydisCalcAbsoluteAddress(&instr, &instr.operands[0], routine_addr, - &routine_addr); - } - else if (instr.mnemonic == ZYDIS_MNEMONIC_RET) - { - routine.push_back({instr, raw_instr, routine_addr}); - return true; - } - else - { - routine.push_back({instr, raw_instr, routine_addr}); - routine_addr += instr.length; - } - } - return false; - } - - void deobfuscate(zydis_routine_t &routine) - { - static const auto _uses = [](ZydisDecodedOperand &op, - zydis_register_t reg) -> bool { - switch (op.type) - { - case ZYDIS_OPERAND_TYPE_MEMORY: - { - return reg::compare(op.mem.base, reg) || - reg::compare(op.mem.index, reg); - } - case ZYDIS_OPERAND_TYPE_REGISTER: - { - return reg::compare(op.reg.value, reg); - } - } - - return false; - }; - - static const auto _writes = [](zydis_decoded_instr_t &inst) -> bool { - for (auto idx = 0; idx < inst.operand_count; ++idx) - if (inst.operands[idx].actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) - return true; - - return false; - }; - - static const auto _remove = - [](zydis_routine_t &routine, zydis_routine_t::iterator itr, - zydis_register_t reg, u32 opcode_size) -> void { - for (; itr >= routine.begin(); --itr) - { - const auto instruction = &itr->instr; - bool stop = false; - - if (instruction->mnemonic == ZYDIS_MNEMONIC_JMP) - continue; - - for (auto op_idx = 0u; op_idx < instruction->operand_count; - ++op_idx) - { - const auto op = &instruction->operands[op_idx]; - - if (!_uses(*op, reg)) - continue; - - if (op->type == ZYDIS_OPERAND_TYPE_MEMORY) - { - stop = true; - continue; - } - - if (opcode_size < 32 && op->size > opcode_size) - continue; - - if (op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) - op->actions &= ~ZYDIS_OPERAND_ACTION_MASK_WRITE; - else - stop = true; - } - - if (!_writes(*instruction)) - routine.erase(itr); - - else if (stop) - break; - } - }; - - for (const auto &instr_data : routine) - { - if (routine.empty() || routine.size() == 1 || - instr_data.instr.mnemonic == ZYDIS_MNEMONIC_JMP) - continue; - - for (auto itr = routine.begin() + 1; itr != routine.end(); itr++) - { - if (itr->instr.mnemonic == ZYDIS_MNEMONIC_JMP || - itr->instr.mnemonic == ZYDIS_MNEMONIC_RET) - break; - - // find the write operations that happen... - for (auto idx = 0u; idx < itr->instr.operand_count; ++idx) - { - const auto op = &itr->instr.operands[idx]; - // if its a read, continue to next opcode... - if (op->actions & ZYDIS_OPERAND_ACTION_MASK_READ) - continue; - - // if its not a write then continue to next opcode... - if (!(op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE)) - continue; - - // if this operand is not a register then we continue... - if (op->type != ZYDIS_OPERAND_TYPE_REGISTER) - continue; - - // else we see if we can remove dead writes to this - // register... - _remove(routine, itr - 1, op->reg.value, op->size); - } - } - } + namespace reg + { + zydis_register_t to64(zydis_register_t reg) + { + return ZydisRegisterGetLargestEnclosing( + ZYDIS_MACHINE_MODE_LONG_64, reg); + } + + bool compare(zydis_register_t a, zydis_register_t b) + { + return to64(a) == to64(b); + } + } + + void print(const zydis_decoded_instr_t& instr) + { + char buffer[256]; + ZydisFormatter formatter; + ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); + ZydisFormatterFormatInstruction(&formatter, &instr, + buffer, sizeof(buffer), 0u); + + puts(buffer); + } + + void print(zydis_routine_t& routine) + { + char buffer[256]; + ZydisFormatter formatter; + ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); + + for (auto [instr, raw, addr] : routine) + { + std::printf("> 0x%p ", addr); + ZydisFormatterFormatInstruction(&formatter, &instr, + buffer, sizeof(buffer), addr); + + puts(buffer); + } + } + + bool is_jmp(const zydis_decoded_instr_t& instr) + { + switch (instr.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_JMP: + 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: + return true; + default: + break; + } + return false; + } + + bool flatten(zydis_routine_t& routine, std::uintptr_t routine_addr, bool keep_jmps) + { + ZydisDecoder decoder; + zydis_decoded_instr_t instr; + ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64); + + while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, reinterpret_cast( + routine_addr), 0x1000, &instr))) + { + std::vector raw_instr; + raw_instr.insert(raw_instr.begin(), + (u8*)routine_addr, + (u8*)routine_addr + instr.length); + + if (is_jmp(instr)) + { + if (instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER) + { + routine.push_back({ instr, raw_instr, routine_addr }); + return true; + } + + if (keep_jmps) + routine.push_back({ instr, raw_instr, routine_addr }); + + ZydisCalcAbsoluteAddress(&instr, &instr.operands[0], routine_addr, &routine_addr); + } + else if (instr.mnemonic == ZYDIS_MNEMONIC_RET) + { + routine.push_back({ instr, raw_instr, routine_addr }); + return true; + } + else + { + routine.push_back({ instr, raw_instr, routine_addr }); + routine_addr += instr.length; + } + } + return false; + } + + void deobfuscate(zydis_routine_t& routine) + { + static const auto _uses = + [](ZydisDecodedOperand& op, zydis_register_t reg) -> bool + { + switch (op.type) + { + case ZYDIS_OPERAND_TYPE_MEMORY: + { + return reg::compare(op.mem.base, reg) || reg::compare(op.mem.index, reg); + } + case ZYDIS_OPERAND_TYPE_REGISTER: + { + return reg::compare(op.reg.value, reg); + } + } + + return false; + }; + + static const auto _writes = + [](zydis_decoded_instr_t& inst) -> bool + { + for (auto idx = 0; idx < inst.operand_count; ++idx) + if (inst.operands[idx].actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) + return true; + + return false; + }; + + static const auto _remove = + [](zydis_routine_t& routine, zydis_routine_t::iterator itr, + zydis_register_t reg, u32 opcode_size) -> void + { + for (; itr >= routine.begin(); --itr) + { + const auto instruction = &itr->instr; + bool stop = false; + + if (instruction->mnemonic == ZYDIS_MNEMONIC_JMP) + continue; + + for (auto op_idx = 0u; op_idx < instruction->operand_count; ++op_idx) + { + const auto op = &instruction->operands[op_idx]; + + if (!_uses(*op, reg)) + continue; + + if (op->type == ZYDIS_OPERAND_TYPE_MEMORY) + { + stop = true; + continue; + } + + if (opcode_size < 32 && op->size > opcode_size) + continue; + + if (op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) + op->actions &= ~ZYDIS_OPERAND_ACTION_MASK_WRITE; + else stop = true; + } + + if (!_writes(*instruction)) + routine.erase(itr); + + else if (stop) break; + } + }; + + for (const auto& instr_data : routine) + { + if (routine.empty() || routine.size() == 1 || + instr_data.instr.mnemonic == ZYDIS_MNEMONIC_JMP) + continue; + + for (auto itr = routine.begin() + 1; itr != routine.end(); itr++) + { + if (itr->instr.mnemonic == ZYDIS_MNEMONIC_JMP || + itr->instr.mnemonic == ZYDIS_MNEMONIC_RET) + break; + + // find the write operations that happen... + for (auto idx = 0u; idx < itr->instr.operand_count; ++idx) + { + const auto op = &itr->instr.operands[idx]; + // if its a read, continue to next opcode... + if (op->actions & ZYDIS_OPERAND_ACTION_MASK_READ) + continue; + + // if its not a write then continue to next opcode... + if (!(op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE)) + continue; + + // if this operand is not a register then we continue... + if (op->type != ZYDIS_OPERAND_TYPE_REGISTER) + continue; + + // else we see if we can remove dead writes to this register... + _remove(routine, itr - 1, op->reg.value, op->size); + } + } + } + } } - } // namespace util -} // namespace vm \ No newline at end of file +} \ No newline at end of file