#include "instruction_decoder.h" #include static bool read_u8(const Memory &memory, uint64_t addr, uint8_t &out) { auto it = memory.find(addr); if (it == memory.end()) return false; out = it->second; return true; } const ZydisDecoder &InstructionDecoder::x86_decoder() { static const ZydisDecoder decoder = [] { ZydisDecoder d; ZydisDecoderInit(&d, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32); return d; }(); return decoder; } std::optional InstructionDecoder::decode(const Memory &memory, uint64_t addr) { std::array bytes{}; bool have_byte = false; for (size_t i = 0; i < bytes.size(); ++i) { if (!read_u8(memory, addr + i, bytes[i])) break; have_byte = true; } if (!have_byte) return std::nullopt; DecodedInstruction decoded; decoded.address = addr; if (!ZYAN_SUCCESS( ZydisDecoderDecodeFull(&x86_decoder(), bytes.data(), bytes.size(), &decoded.instruction, decoded.operands) )) return std::nullopt; decoded.length = decoded.instruction.length; decoded.mnemonic = decoded.instruction.mnemonic; for (unsigned i = 0; i < decoded.instruction.operand_count; ++i) { const auto &op = decoded.operands[i]; if (op.type != ZYDIS_OPERAND_TYPE_IMMEDIATE || !op.imm.is_relative) continue; ZyanU64 target = 0; if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&decoded.instruction, &op, addr, &target))) { decoded.branch_target = static_cast(target); break; } } return decoded; } bool InstructionDecoder::is_ret(const DecodedInstruction &inst) { return inst.mnemonic == ZYDIS_MNEMONIC_RET; } bool InstructionDecoder::is_unconditional_jmp(const DecodedInstruction &inst) { return inst.mnemonic == ZYDIS_MNEMONIC_JMP; } bool InstructionDecoder::is_direct_call(const DecodedInstruction &inst) { return inst.mnemonic == ZYDIS_MNEMONIC_CALL && inst.branch_target.has_value(); } bool InstructionDecoder::is_pop(const DecodedInstruction &inst) { return inst.mnemonic == ZYDIS_MNEMONIC_POP || inst.mnemonic == ZYDIS_MNEMONIC_POPA || inst.mnemonic == ZYDIS_MNEMONIC_POPAD || inst.mnemonic == ZYDIS_MNEMONIC_POPF || inst.mnemonic == ZYDIS_MNEMONIC_POPFD; } std::optional InstructionDecoder::push_register_index(const DecodedInstruction &inst) { if (inst.mnemonic != ZYDIS_MNEMONIC_PUSH || inst.instruction.operand_count_visible < 1 || inst.operands[0].type != ZYDIS_OPERAND_TYPE_REGISTER) return std::nullopt; switch (inst.operands[0].reg.value) { case ZYDIS_REGISTER_EAX: return 0; case ZYDIS_REGISTER_ECX: return 1; case ZYDIS_REGISTER_EDX: return 2; case ZYDIS_REGISTER_EBX: return 3; case ZYDIS_REGISTER_ESP: return 4; case ZYDIS_REGISTER_EBP: return 5; case ZYDIS_REGISTER_ESI: return 6; case ZYDIS_REGISTER_EDI: return 7; default: return std::nullopt; } } bool InstructionDecoder::is_indirect_jmp(const std::optional::value_type &inst) { return inst.mnemonic == ZYDIS_MNEMONIC_JMP && inst.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER; }