mirror of
https://gitlab.com/BinaryHardening/cfgrip
synced 2026-07-26 12:41:08 +00:00
164 lines
4.4 KiB
C++
164 lines
4.4 KiB
C++
#include "disasm/engine.hpp"
|
|
#include <cstring>
|
|
|
|
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<Instruction> Disassembler::disassemble(const vector<uint8_t>& bytes, addr_t base, size_t count)
|
|
{
|
|
vector<Instruction> 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<uint8_t>(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<Instruction>& insts) const
|
|
{
|
|
for (const auto& inst : insts)
|
|
{
|
|
if (inst.mnemonic == "push" && (inst.operands == "rbp" || inst.operands == "ebp"))
|
|
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;
|
|
}
|