#include "disasm/engine.hpp" #include Disassembler::Disassembler() : m_handle(0), m_initialized(false) {} Disassembler::~Disassembler() { if (m_initialized) cs_close(&m_handle); } bool Disassembler::init(Arch arch) { cs_arch a; cs_mode m; if (arch == Arch::X64) { a = CS_ARCH_X86; m = CS_MODE_64; } else if (arch == Arch::X86) { a = CS_ARCH_X86; m = CS_MODE_32; } else return false; if (cs_open(a, m, &m_handle) != CS_ERR_OK) return false; cs_option(m_handle, CS_OPT_DETAIL, CS_OPT_ON); m_initialized = true; return true; } vector Disassembler::disassemble(const vector& bytes, addr_t base, size_t count) { vector result; if (!m_initialized || bytes.empty()) return result; const uint8_t* code = bytes.data(); size_t size = bytes.size(); addr_t addr = base; size_t n = count ? count : size; cs_insn* insn = cs_malloc(m_handle); if (!insn) return result; while (cs_disasm_iter(m_handle, &code, &size, &addr, insn)) { Instruction inst; inst.address = insn->address; inst.mnemonic = insn->mnemonic; inst.operands = insn->op_str; inst.size = static_cast(insn->size); inst.bytes.assign(insn->bytes, insn->bytes + insn->size); result.push_back(inst); if (count && result.size() >= count) break; } cs_free(insn, 1); return result; } bool Disassembler::isProlog(const vector& insts) const { for (const auto& inst : insts) { if (inst.mnemonic == "push" && (inst.operands == "rbp" || inst.operands == "ebp")) return true; if (inst.mnemonic == "push") { const string& ops = inst.operands; if (ops == "r15" || ops == "r14" || ops == "r13" || ops == "r12" || ops == "rbx" || ops == "rdi" || ops == "rsi") return true; } if (inst.mnemonic == "sub") { const string& ops = inst.operands; size_t p = ops.find("rsp"); if (p == string::npos) p = ops.find("esp"); if (p != string::npos && (p == 0 || ops[p-1] == ' ' || ops[p-1] == ',')) { size_t x = ops.rfind("0x"); if (x != string::npos && x > p) { try { uint64_t val = stoull(ops.substr(x), nullptr, 16); if (val >= 0x20) return true; } catch (...) {} } } } if (inst.mnemonic == "enter") return true; } return false; } bool Disassembler::isEpilog(const Instruction& inst) const { return inst.mnemonic == "leave" || inst.mnemonic == "ret" || inst.mnemonic == "retf"; } bool Disassembler::isReturn(const Instruction& inst) const { return inst.mnemonic == "ret" || inst.mnemonic == "retf" || inst.mnemonic == "iret" || inst.mnemonic == "iretd"; } bool Disassembler::isTrap(const Instruction& inst) const { return inst.mnemonic == "hlt" || inst.mnemonic == "ud2" || inst.mnemonic == "int3" || inst.mnemonic == "ud0"; } bool Disassembler::isCall(const Instruction& inst) const { return inst.mnemonic == "call"; } bool Disassembler::isUnconditionalBranch(const Instruction& inst) const { return inst.mnemonic == "jmp" || inst.mnemonic == "ljmp"; } bool Disassembler::isConditionalBranch(const Instruction& inst) const { return inst.mnemonic.size() == 2 && inst.mnemonic[0] == 'j' && inst.mnemonic != "jmp"; } bool Disassembler::isIndirectBranch(const Instruction& inst) const { const string& ops = inst.operands; if (inst.mnemonic == "call" || inst.mnemonic == "jmp") { if (ops.find('[') != string::npos) return true; if (ops.size() >= 3 && ops[0] == 'r' && isdigit(ops[1])) return true; if (ops.size() >= 4 && ops[0] == 'r' && ops[1] == '1' && isdigit(ops[2])) return true; if (ops.size() >= 3 && ops[0] == 'e' && isdigit(ops[1])) return true; if (ops[0] == '*') return true; } return false; } addr_t Disassembler::getBranchTarget(const Instruction& inst) const { const string& ops = inst.operands; if (ops.empty()) return 0; size_t pos = string::npos; if (ops[0] == '0' && ops.size() > 2 && ops[1] == 'x') pos = 0; else if (ops[0] >= '0' && ops[0] <= '9') pos = 0; else pos = ops.find("0x"); if (pos == string::npos) return 0; try { return stoull(ops.substr(pos), nullptr, 16); } catch (...) { return 0; } } int64_t Disassembler::getRIPDisp(const Instruction& inst) const { if (!m_initialized) return 0; auto bytes = inst.bytes; if (bytes.empty()) return 0; cs_insn* insn = cs_malloc(m_handle); if (!insn) return 0; const uint8_t* code = bytes.data(); size_t size = bytes.size(); addr_t addr = inst.address; int64_t disp = 0; if (cs_disasm_iter(m_handle, &code, &size, &addr, insn)) { if (insn->detail) { for (int i = 0; i < insn->detail->x86.op_count; i++) { const auto& op = insn->detail->x86.operands[i]; if (op.type == X86_OP_MEM && op.mem.base == X86_REG_RIP) { disp = op.mem.disp; break; } } } } cs_free(insn, 1); return disp; }