mirror of
https://github.com/x64dbg/capstone_wrapper.git
synced 2026-11-08 15:19:37 -10:00
858 lines
25 KiB
C++
858 lines
25 KiB
C++
#include "capstone_wrapper.h"
|
|
#include <windows.h>
|
|
|
|
csh Capstone::mHandle = 0;
|
|
bool Capstone::mInitialized = false;
|
|
|
|
static void customMnem(csh handle, x86_insn mnem, const char* alias)
|
|
{
|
|
cs_opt_mnem om = { mnem, alias };
|
|
cs_option(handle, CS_OPT_MNEMONIC, (size_t)&om);
|
|
}
|
|
|
|
void Capstone::GlobalInitialize()
|
|
{
|
|
if(!mInitialized)
|
|
{
|
|
mInitialized = true;
|
|
#ifdef _WIN64
|
|
cs_open(CS_ARCH_X86, CS_MODE_64, &mHandle);
|
|
#else //x86
|
|
cs_open(CS_ARCH_X86, CS_MODE_32, &mHandle);
|
|
#endif //_WIN64
|
|
cs_option(mHandle, CS_OPT_DETAIL, CS_OPT_ON);
|
|
customMnem(mHandle, X86_INS_PUSHAL, "pushad");
|
|
customMnem(mHandle, X86_INS_POPAL, "popad");
|
|
}
|
|
}
|
|
|
|
void Capstone::GlobalFinalize()
|
|
{
|
|
if(mHandle) //close handle
|
|
cs_close(&mHandle);
|
|
mInitialized = false;
|
|
}
|
|
|
|
Capstone::Capstone()
|
|
{
|
|
GlobalInitialize();
|
|
mInstr = cs_malloc(mHandle);
|
|
mSuccess = false;
|
|
}
|
|
|
|
Capstone::Capstone(const Capstone & capstone)
|
|
: mInstr(cs_malloc(mHandle)),
|
|
mSuccess(false)
|
|
{
|
|
}
|
|
|
|
Capstone::~Capstone()
|
|
{
|
|
if(mInstr) //free last disassembled instruction
|
|
cs_free(mInstr, 1);
|
|
}
|
|
|
|
bool Capstone::Disassemble(size_t addr, const unsigned char data[MAX_DISASM_BUFFER])
|
|
{
|
|
return Disassemble(addr, data, MAX_DISASM_BUFFER);
|
|
}
|
|
|
|
bool Capstone::Disassemble(size_t addr, const unsigned char* data, int size)
|
|
{
|
|
if(!data || !size)
|
|
return false;
|
|
|
|
size_t codeSize = size;
|
|
uint64_t addr64 = addr;
|
|
|
|
return (mSuccess = cs_disasm_iter(mHandle, &data, &codeSize, &addr64, mInstr));
|
|
}
|
|
|
|
bool Capstone::DisassembleSafe(size_t addr, const unsigned char* data, int size)
|
|
{
|
|
unsigned char dataSafe[MAX_DISASM_BUFFER];
|
|
memset(dataSafe, 0, sizeof(dataSafe));
|
|
memcpy(dataSafe, data, min(MAX_DISASM_BUFFER, size_t(size)));
|
|
return Disassemble(addr, dataSafe);
|
|
}
|
|
|
|
const cs_insn* Capstone::GetInstr() const
|
|
{
|
|
if(!Success())
|
|
return nullptr;
|
|
return mInstr;
|
|
}
|
|
|
|
bool Capstone::Success() const
|
|
{
|
|
return mSuccess;
|
|
}
|
|
|
|
const char* Capstone::RegName(x86_reg reg) const
|
|
{
|
|
switch(reg)
|
|
{
|
|
case X86_REG_ST0:
|
|
return "st(0)";
|
|
case X86_REG_ST1:
|
|
return "st(1)";
|
|
case X86_REG_ST2:
|
|
return "st(2)";
|
|
case X86_REG_ST3:
|
|
return "st(3)";
|
|
case X86_REG_ST4:
|
|
return "st(4)";
|
|
case X86_REG_ST5:
|
|
return "st(5)";
|
|
case X86_REG_ST6:
|
|
return "st(6)";
|
|
case X86_REG_ST7:
|
|
return "st(7)";
|
|
default:
|
|
return cs_reg_name(mHandle, reg);
|
|
}
|
|
}
|
|
|
|
bool Capstone::InGroup(cs_group_type group) const
|
|
{
|
|
if(!Success())
|
|
return false;
|
|
if(group == CS_GRP_PRIVILEGE)
|
|
{
|
|
auto id = GetId();
|
|
// I/O instructions
|
|
if(id == X86_INS_OUT || id == X86_INS_OUTSB || id == X86_INS_OUTSD || id == X86_INS_OUTSW
|
|
|| id == X86_INS_IN || id == X86_INS_INSB || id == X86_INS_INSD || id == X86_INS_INSW
|
|
// system instructions
|
|
|| id == X86_INS_RDMSR || id == X86_INS_SMSW)
|
|
return true;
|
|
}
|
|
return cs_insn_group(mHandle, mInstr, group);
|
|
}
|
|
|
|
std::string Capstone::OperandText(int opindex) const
|
|
{
|
|
if(!Success() || opindex >= mInstr->detail->x86.op_count)
|
|
return "";
|
|
const auto & op = mInstr->detail->x86.operands[opindex];
|
|
std::string result;
|
|
char temp[32] = "";
|
|
switch(op.type)
|
|
{
|
|
case X86_OP_REG:
|
|
{
|
|
result = RegName(x86_reg(op.reg));
|
|
}
|
|
break;
|
|
|
|
case X86_OP_IMM:
|
|
{
|
|
sprintf_s(temp, "%llX", op.imm);
|
|
result = temp;
|
|
}
|
|
break;
|
|
|
|
case X86_OP_MEM:
|
|
{
|
|
const auto & mem = op.mem;
|
|
if(op.mem.base == X86_REG_RIP) //rip-relative
|
|
{
|
|
sprintf_s(temp, "%llX", Address() + op.mem.disp + Size());
|
|
result += temp;
|
|
}
|
|
else //normal
|
|
{
|
|
bool prependPlus = false;
|
|
if(mem.base)
|
|
{
|
|
result += RegName(x86_reg(mem.base));
|
|
prependPlus = true;
|
|
}
|
|
if(mem.index)
|
|
{
|
|
if(prependPlus)
|
|
result += "+";
|
|
result += RegName(x86_reg(mem.index));
|
|
sprintf_s(temp, "*%X", mem.scale);
|
|
result += temp;
|
|
prependPlus = true;
|
|
}
|
|
if(mem.disp)
|
|
{
|
|
char operatorText = '+';
|
|
if(mem.disp < 0)
|
|
{
|
|
operatorText = '-';
|
|
sprintf_s(temp, "%llX", mem.disp * -1);
|
|
}
|
|
else
|
|
sprintf_s(temp, "%llX", mem.disp);
|
|
if(prependPlus)
|
|
result += operatorText;
|
|
result += temp;
|
|
}
|
|
if(!mem.disp && !mem.base && !mem.index)
|
|
result += '0';
|
|
}
|
|
}
|
|
break;
|
|
|
|
case X86_OP_INVALID:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int Capstone::Size() const
|
|
{
|
|
if(!Success())
|
|
return 1;
|
|
return GetInstr()->size;
|
|
}
|
|
|
|
size_t Capstone::Address() const
|
|
{
|
|
if(!Success())
|
|
return 0;
|
|
return size_t(GetInstr()->address);
|
|
}
|
|
|
|
const cs_x86 & Capstone::x86() const
|
|
{
|
|
if(!Success())
|
|
DebugBreak();
|
|
return GetInstr()->detail->x86;
|
|
}
|
|
|
|
bool Capstone::IsFilling() const
|
|
{
|
|
if(!Success())
|
|
return false;
|
|
switch(GetId())
|
|
{
|
|
case X86_INS_NOP:
|
|
case X86_INS_INT3:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Capstone::IsLoop() const
|
|
{
|
|
if(!Success())
|
|
return false;
|
|
switch(GetId())
|
|
{
|
|
case X86_INS_LOOP:
|
|
case X86_INS_LOOPE:
|
|
case X86_INS_LOOPNE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
x86_insn Capstone::GetId() const
|
|
{
|
|
if(!Success())
|
|
DebugBreak();
|
|
return x86_insn(mInstr->id);
|
|
}
|
|
|
|
std::string Capstone::InstructionText(bool replaceRipRelative) const
|
|
{
|
|
if(!Success())
|
|
return "???";
|
|
std::string result = Mnemonic();
|
|
if(OpCount())
|
|
{
|
|
result += " ";
|
|
result += mInstr->op_str;
|
|
}
|
|
#ifdef _WIN64
|
|
if(replaceRipRelative)
|
|
{
|
|
//replace [rip +/- 0x?] with the actual address
|
|
bool ripPlus = true;
|
|
auto found = result.find("[rip + ");
|
|
if(found == std::string::npos)
|
|
{
|
|
ripPlus = false;
|
|
found = result.find("[rip - ");
|
|
}
|
|
if(found != std::string::npos)
|
|
{
|
|
auto wVA = Address();
|
|
auto end = result.find("]", found);
|
|
auto ripStr = result.substr(found + 1, end - found - 1);
|
|
uint64_t offset;
|
|
sscanf_s(ripStr.substr(ripStr.rfind(' ') + 1).c_str(), "%llX", &offset);
|
|
auto dest = ripPlus ? (wVA + offset + Size()) : (wVA - offset + Size());
|
|
char buf[20];
|
|
sprintf_s(buf, "0x%llx", dest);
|
|
result.replace(found + 1, ripStr.length(), buf);
|
|
}
|
|
}
|
|
#endif //_WIN64
|
|
return result;
|
|
}
|
|
|
|
int Capstone::OpCount() const
|
|
{
|
|
if(!Success())
|
|
return 0;
|
|
return x86().op_count;
|
|
}
|
|
|
|
const cs_x86_op & Capstone::operator[](int index) const
|
|
{
|
|
if(!Success() || index < 0 || index >= OpCount())
|
|
DebugBreak();
|
|
return x86().operands[index];
|
|
}
|
|
|
|
static bool isSafe64NopRegOp(const cs_x86_op & op)
|
|
{
|
|
if(op.type != X86_OP_REG)
|
|
return true; //a non-register is safe
|
|
#ifdef _WIN64
|
|
switch(op.reg)
|
|
{
|
|
case X86_REG_EAX:
|
|
case X86_REG_EBX:
|
|
case X86_REG_ECX:
|
|
case X86_REG_EDX:
|
|
case X86_REG_EBP:
|
|
case X86_REG_ESP:
|
|
case X86_REG_ESI:
|
|
case X86_REG_EDI:
|
|
return false; //32 bit register modifications clear the high part of the 64 bit register
|
|
default:
|
|
return true; //all other registers are safe
|
|
}
|
|
#else
|
|
return true;
|
|
#endif //_WIN64
|
|
}
|
|
|
|
bool Capstone::IsNop() const
|
|
{
|
|
if(!Success())
|
|
return false;
|
|
const auto & ops = x86().operands;
|
|
cs_x86_op op;
|
|
switch(GetId())
|
|
{
|
|
case X86_INS_NOP:
|
|
case X86_INS_PAUSE:
|
|
case X86_INS_FNOP:
|
|
// nop
|
|
return true;
|
|
case X86_INS_MOV:
|
|
case X86_INS_CMOVA:
|
|
case X86_INS_CMOVAE:
|
|
case X86_INS_CMOVB:
|
|
case X86_INS_CMOVBE:
|
|
case X86_INS_CMOVE:
|
|
case X86_INS_CMOVNE:
|
|
case X86_INS_CMOVG:
|
|
case X86_INS_CMOVGE:
|
|
case X86_INS_CMOVL:
|
|
case X86_INS_CMOVLE:
|
|
case X86_INS_CMOVO:
|
|
case X86_INS_CMOVNO:
|
|
case X86_INS_CMOVP:
|
|
case X86_INS_CMOVNP:
|
|
case X86_INS_CMOVS:
|
|
case X86_INS_CMOVNS:
|
|
case X86_INS_MOVAPS:
|
|
case X86_INS_MOVAPD:
|
|
case X86_INS_MOVUPS:
|
|
case X86_INS_MOVUPD:
|
|
case X86_INS_XCHG:
|
|
// mov edi, edi
|
|
return ops[0].type == X86_OP_REG && ops[1].type == X86_OP_REG && ops[0].reg == ops[1].reg && isSafe64NopRegOp(ops[0]);
|
|
case X86_INS_LEA:
|
|
{
|
|
// lea eax, [eax + 0]
|
|
auto reg = ops[0].reg;
|
|
auto mem = ops[1].mem;
|
|
return ops[0].type == X86_OP_REG && ops[1].type == X86_OP_MEM && mem.disp == 0 &&
|
|
((mem.index == X86_REG_INVALID && mem.base == reg) ||
|
|
(mem.index == reg && mem.base == X86_REG_INVALID && mem.scale == 1)) && isSafe64NopRegOp(ops[0]);
|
|
}
|
|
case X86_INS_JMP:
|
|
case X86_INS_JA:
|
|
case X86_INS_JAE:
|
|
case X86_INS_JB:
|
|
case X86_INS_JBE:
|
|
case X86_INS_JE:
|
|
case X86_INS_JNE:
|
|
case X86_INS_JG:
|
|
case X86_INS_JGE:
|
|
case X86_INS_JL:
|
|
case X86_INS_JLE:
|
|
case X86_INS_JO:
|
|
case X86_INS_JNO:
|
|
case X86_INS_JP:
|
|
case X86_INS_JNP:
|
|
case X86_INS_JS:
|
|
case X86_INS_JNS:
|
|
case X86_INS_JECXZ:
|
|
case X86_INS_JRCXZ:
|
|
case X86_INS_JCXZ:
|
|
// jmp 0
|
|
op = ops[0];
|
|
return op.type == X86_OP_IMM && op.imm == this->Address() + this->Size();
|
|
case X86_INS_SHL:
|
|
case X86_INS_SHR:
|
|
case X86_INS_ROL:
|
|
case X86_INS_ROR:
|
|
case X86_INS_SAR:
|
|
case X86_INS_SAL:
|
|
// shl eax, 0
|
|
op = ops[1];
|
|
return op.type == X86_OP_IMM && op.imm == 0 && isSafe64NopRegOp(ops[0]);
|
|
case X86_INS_SHLD:
|
|
case X86_INS_SHRD:
|
|
// shld eax, ebx, 0
|
|
op = ops[2];
|
|
return op.type == X86_OP_IMM && op.imm == 0 && isSafe64NopRegOp(ops[0]) && isSafe64NopRegOp(ops[1]);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Capstone::IsInt3() const
|
|
{
|
|
if(!Success())
|
|
return false;
|
|
switch(GetId())
|
|
{
|
|
case X86_INS_INT3:
|
|
return true;
|
|
case X86_INS_INT:
|
|
{
|
|
cs_x86_op op = x86().operands[0];
|
|
return op.type == X86_OP_IMM && op.imm == 3;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Capstone::IsUnusual() const
|
|
{
|
|
auto id = GetId();
|
|
return (InGroup(CS_GRP_PRIVILEGE) || InGroup(CS_GRP_IRET) || InGroup(CS_GRP_INVALID)
|
|
|| id == X86_INS_RDTSC || id == X86_INS_SYSCALL || id == X86_INS_SYSENTER || id == X86_INS_CPUID || id == X86_INS_RDTSCP
|
|
|| id == X86_INS_RDRAND || id == X86_INS_RDSEED || id == X86_INS_UD2 || id == X86_INS_UD2B);
|
|
}
|
|
|
|
std::string Capstone::Mnemonic() const
|
|
{
|
|
if(!Success())
|
|
return "???";
|
|
return mInstr->mnemonic;
|
|
}
|
|
|
|
std::string Capstone::MnemonicId() const
|
|
{
|
|
if(!Success())
|
|
return "???";
|
|
return cs_insn_name(mHandle, GetId());
|
|
}
|
|
|
|
const char* Capstone::MemSizeName(int size) const
|
|
{
|
|
switch(size)
|
|
{
|
|
case 1:
|
|
return "byte";
|
|
case 2:
|
|
return "word";
|
|
case 4:
|
|
return "dword";
|
|
case 6:
|
|
return "fword";
|
|
case 8:
|
|
return "qword";
|
|
case 10:
|
|
return "tword";
|
|
case 14:
|
|
return "m14";
|
|
case 16:
|
|
return "xmmword";
|
|
case 28:
|
|
return "m28";
|
|
case 32:
|
|
return "yword";
|
|
case 64:
|
|
return "zword";
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
size_t Capstone::BranchDestination() const
|
|
{
|
|
if(!Success())
|
|
return 0;
|
|
if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL) || IsLoop())
|
|
{
|
|
const auto & op = x86().operands[0];
|
|
if(op.type == X86_OP_IMM)
|
|
return size_t(op.imm);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t Capstone::ResolveOpValue(int opindex, const std::function<size_t(x86_reg)> & resolveReg) const
|
|
{
|
|
size_t dest = 0;
|
|
const auto & op = x86().operands[opindex];
|
|
switch(op.type)
|
|
{
|
|
case X86_OP_IMM:
|
|
dest = size_t(op.imm);
|
|
break;
|
|
case X86_OP_REG:
|
|
dest = resolveReg(op.reg);
|
|
break;
|
|
case X86_OP_MEM:
|
|
dest = size_t(op.mem.disp);
|
|
if(op.mem.base == X86_REG_RIP) //rip-relative
|
|
dest += Address() + Size();
|
|
else
|
|
dest += resolveReg(op.mem.base) + resolveReg(op.mem.index) * op.mem.scale;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
bool Capstone::IsBranchGoingToExecute(size_t cflags, size_t ccx) const
|
|
{
|
|
return IsBranchGoingToExecute(GetId(), cflags, ccx);
|
|
}
|
|
|
|
bool Capstone::IsBranchGoingToExecute(x86_insn id, size_t cflags, size_t ccx)
|
|
{
|
|
auto bCF = (cflags & (1 << 0)) != 0;
|
|
auto bPF = (cflags & (1 << 2)) != 0;
|
|
auto bZF = (cflags & (1 << 6)) != 0;
|
|
auto bSF = (cflags & (1 << 7)) != 0;
|
|
auto bOF = (cflags & (1 << 11)) != 0;
|
|
switch(id)
|
|
{
|
|
case X86_INS_CALL:
|
|
case X86_INS_LJMP:
|
|
case X86_INS_JMP:
|
|
case X86_INS_RET:
|
|
case X86_INS_RETF:
|
|
case X86_INS_RETFQ:
|
|
return true;
|
|
case X86_INS_JAE: //jump short if above or equal
|
|
return !bCF;
|
|
case X86_INS_JA: //jump short if above
|
|
return !bCF && !bZF;
|
|
case X86_INS_JBE: //jump short if below or equal/not above
|
|
return bCF || bZF;
|
|
case X86_INS_JB: //jump short if below/not above nor equal/carry
|
|
return bCF;
|
|
case X86_INS_JCXZ: //jump short if ecx register is zero
|
|
case X86_INS_JECXZ: //jump short if ecx register is zero
|
|
case X86_INS_JRCXZ: //jump short if rcx register is zero
|
|
return ccx == 0;
|
|
case X86_INS_JE: //jump short if equal
|
|
return bZF;
|
|
case X86_INS_JGE: //jump short if greater or equal
|
|
return bSF == bOF;
|
|
case X86_INS_JG: //jump short if greater
|
|
return !bZF && bSF == bOF;
|
|
case X86_INS_JLE: //jump short if less or equal/not greater
|
|
return bZF || bSF != bOF;
|
|
case X86_INS_JL: //jump short if less/not greater
|
|
return bSF != bOF;
|
|
case X86_INS_JNE: //jump short if not equal/not zero
|
|
return !bZF;
|
|
case X86_INS_JNO: //jump short if not overflow
|
|
return !bOF;
|
|
case X86_INS_JNP: //jump short if not parity/parity odd
|
|
return !bPF;
|
|
case X86_INS_JNS: //jump short if not sign
|
|
return !bSF;
|
|
case X86_INS_JO: //jump short if overflow
|
|
return bOF;
|
|
case X86_INS_JP: //jump short if parity/parity even
|
|
return bPF;
|
|
case X86_INS_JS: //jump short if sign
|
|
return bSF;
|
|
case X86_INS_LOOP: //decrement count; jump short if ecx!=0
|
|
return ccx != 0;
|
|
case X86_INS_LOOPE: //decrement count; jump short if ecx!=0 and zf=1
|
|
return ccx != 0 && bZF;
|
|
case X86_INS_LOOPNE: //decrement count; jump short if ecx!=0 and zf=0
|
|
return ccx != 0 && !bZF;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Capstone::IsConditionalGoingToExecute(size_t cflags, size_t ccx) const
|
|
{
|
|
return IsConditionalGoingToExecute(GetId(), cflags, ccx);
|
|
}
|
|
|
|
bool Capstone::IsConditionalGoingToExecute(x86_insn id, size_t cflags, size_t ccx)
|
|
{
|
|
auto bCF = (cflags & (1 << 0)) != 0;
|
|
auto bPF = (cflags & (1 << 2)) != 0;
|
|
auto bZF = (cflags & (1 << 6)) != 0;
|
|
auto bSF = (cflags & (1 << 7)) != 0;
|
|
auto bOF = (cflags & (1 << 11)) != 0;
|
|
switch(id)
|
|
{
|
|
case X86_INS_CMOVA: //conditional move - above/not below nor equal
|
|
return !bCF && !bZF;
|
|
case X86_INS_CMOVAE: //conditional move - above or equal/not below/not carry
|
|
return !bCF;
|
|
case X86_INS_CMOVB: //conditional move - below/not above nor equal/carry
|
|
return bCF;
|
|
case X86_INS_CMOVBE: //conditional move - below or equal/not above
|
|
return bCF || bZF;
|
|
case X86_INS_CMOVE: //conditional move - equal/zero
|
|
return bZF;
|
|
case X86_INS_CMOVG: //conditional move - greater/not less nor equal
|
|
return !bZF && bSF == bOF;
|
|
case X86_INS_CMOVGE: //conditional move - greater or equal/not less
|
|
return bSF == bOF;
|
|
case X86_INS_CMOVL: //conditional move - less/not greater nor equal
|
|
return bSF != bOF;
|
|
case X86_INS_CMOVLE: //conditional move - less or equal/not greater
|
|
return bZF || bSF != bOF;
|
|
case X86_INS_CMOVNE: //conditional move - not equal/not zero
|
|
return !bZF;
|
|
case X86_INS_CMOVNO: //conditional move - not overflow
|
|
return !bOF;
|
|
case X86_INS_CMOVNP: //conditional move - not parity/parity odd
|
|
return !bPF;
|
|
case X86_INS_CMOVNS: //conditional move - not sign
|
|
return !bSF;
|
|
case X86_INS_CMOVO: //conditional move - overflow
|
|
return bOF;
|
|
case X86_INS_CMOVP: //conditional move - parity/parity even
|
|
return bPF;
|
|
case X86_INS_CMOVS: //conditional move - sign
|
|
return bSF;
|
|
case X86_INS_FCMOVBE: //fp conditional move - below or equal
|
|
return bCF || bZF;
|
|
case X86_INS_FCMOVB: //fp conditional move - below
|
|
return bCF;
|
|
case X86_INS_FCMOVE: //fp conditional move - equal
|
|
return bZF;
|
|
case X86_INS_FCMOVNBE: //fp conditional move - not below or equal
|
|
return !bCF && !bZF;
|
|
case X86_INS_FCMOVNB: //fp conditional move - not below
|
|
return !bCF;
|
|
case X86_INS_FCMOVNE: //fp conditional move - not equal
|
|
return !bZF;
|
|
case X86_INS_FCMOVNU: //fp conditional move - not unordered
|
|
return !bPF;
|
|
case X86_INS_FCMOVU: //fp conditional move - unordered
|
|
return bPF;
|
|
case X86_INS_SETA: //set byte on condition - above/not below nor equal
|
|
return !bCF && !bZF;
|
|
case X86_INS_SETAE: //set byte on condition - above or equal/not below/not carry
|
|
return !bCF;
|
|
case X86_INS_SETB: //set byte on condition - below/not above nor equal/carry
|
|
return bCF;
|
|
case X86_INS_SETBE: //set byte on condition - below or equal/not above
|
|
return bCF || bZF;
|
|
case X86_INS_SETE: //set byte on condition - equal/zero
|
|
return bZF;
|
|
case X86_INS_SETG: //set byte on condition - greater/not less nor equal
|
|
return !bZF && bSF == bOF;
|
|
case X86_INS_SETGE: //set byte on condition - greater or equal/not less
|
|
return bSF == bOF;
|
|
case X86_INS_SETL: //set byte on condition - less/not greater nor equal
|
|
return bSF != bOF;
|
|
case X86_INS_SETLE: //set byte on condition - less or equal/not greater
|
|
return bZF || bSF != bOF;
|
|
case X86_INS_SETNE: //set byte on condition - not equal/not zero
|
|
return !bZF;
|
|
case X86_INS_SETNO: //set byte on condition - not overflow
|
|
return !bOF;
|
|
case X86_INS_SETNP: //set byte on condition - not parity/parity odd
|
|
return !bPF;
|
|
case X86_INS_SETNS: //set byte on condition - not sign
|
|
return !bSF;
|
|
case X86_INS_SETO: //set byte on condition - overflow
|
|
return bOF;
|
|
case X86_INS_SETP: //set byte on condition - parity/parity even
|
|
return bPF;
|
|
case X86_INS_SETS: //set byte on condition - sign
|
|
return bSF;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void Capstone::RegInfo(uint8_t regs[X86_REG_ENDING]) const
|
|
{
|
|
memset(regs, 0, sizeof(uint8_t) * X86_REG_ENDING);
|
|
if(!Success() || IsNop())
|
|
return;
|
|
for(int i = 0; i < OpCount(); i++)
|
|
{
|
|
const auto & op = x86().operands[i];
|
|
switch(op.type)
|
|
{
|
|
case X86_OP_REG:
|
|
if((op.access & CS_AC_READ) == CS_AC_READ)
|
|
regs[op.reg] |= Read | Explicit;
|
|
if((op.access & CS_AC_WRITE) == CS_AC_WRITE)
|
|
regs[op.reg] |= Write | Explicit;
|
|
break;
|
|
|
|
case X86_OP_MEM:
|
|
{
|
|
if(op.mem.segment == X86_REG_INVALID)
|
|
{
|
|
switch(op.mem.base)
|
|
{
|
|
#ifdef _WIN64
|
|
case X86_REG_RSP:
|
|
case X86_REG_RBP:
|
|
#else //x86
|
|
case X86_REG_ESP:
|
|
case X86_REG_EBP:
|
|
#endif //_WIN64
|
|
regs[X86_REG_SS] |= Read | Explicit;
|
|
break;
|
|
default:
|
|
regs[X86_REG_DS] |= Read | Explicit;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
regs[op.mem.segment] |= Read | Explicit;
|
|
regs[op.mem.base] |= Read | Explicit;
|
|
regs[op.mem.index] |= Read | Explicit;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
const cs_detail* detail = GetInstr()->detail;
|
|
for(uint8_t i = 0; i < detail->regs_read_count; i++)
|
|
regs[detail->regs_read[i]] |= Read | Implicit;
|
|
for(uint8_t i = 0; i < detail->regs_write_count; i++)
|
|
regs[detail->regs_write[i]] |= Write | Implicit;
|
|
if(InGroup(CS_GRP_CALL) || InGroup(CS_GRP_RET) || InGroup(CS_GRP_JUMP) || IsLoop())
|
|
#ifdef _WIN64
|
|
regs[X86_REG_RIP] = Write | Implicit;
|
|
#else //x86
|
|
regs[X86_REG_EIP] = Write | Implicit;
|
|
#endif //_WIN64
|
|
}
|
|
|
|
void Capstone::FlagInfo(uint8_t info[FLAG_ENDING]) const
|
|
{
|
|
memset(info, 0, sizeof(uint8_t) * FLAG_ENDING);
|
|
if(!Success())
|
|
return;
|
|
auto eflags = x86().eflags;
|
|
#define setFlagInfo(flag, access, test) info[flag] |= (eflags & test) == test ? access : 0
|
|
//Write
|
|
setFlagInfo(FLAG_AF, Modify, X86_EFLAGS_MODIFY_AF);
|
|
setFlagInfo(FLAG_CF, Modify, X86_EFLAGS_MODIFY_CF);
|
|
setFlagInfo(FLAG_SF, Modify, X86_EFLAGS_MODIFY_SF);
|
|
setFlagInfo(FLAG_ZF, Modify, X86_EFLAGS_MODIFY_ZF);
|
|
setFlagInfo(FLAG_PF, Modify, X86_EFLAGS_MODIFY_PF);
|
|
setFlagInfo(FLAG_OF, Modify, X86_EFLAGS_MODIFY_OF);
|
|
setFlagInfo(FLAG_TF, Modify, X86_EFLAGS_MODIFY_TF);
|
|
setFlagInfo(FLAG_IF, Modify, X86_EFLAGS_MODIFY_IF);
|
|
setFlagInfo(FLAG_DF, Modify, X86_EFLAGS_MODIFY_DF);
|
|
setFlagInfo(FLAG_NT, Modify, X86_EFLAGS_MODIFY_NT);
|
|
setFlagInfo(FLAG_RF, Modify, X86_EFLAGS_MODIFY_RF);
|
|
//None
|
|
setFlagInfo(FLAG_OF, Prior, X86_EFLAGS_PRIOR_OF);
|
|
setFlagInfo(FLAG_SF, Prior, X86_EFLAGS_PRIOR_SF);
|
|
setFlagInfo(FLAG_ZF, Prior, X86_EFLAGS_PRIOR_ZF);
|
|
setFlagInfo(FLAG_AF, Prior, X86_EFLAGS_PRIOR_AF);
|
|
setFlagInfo(FLAG_PF, Prior, X86_EFLAGS_PRIOR_PF);
|
|
setFlagInfo(FLAG_CF, Prior, X86_EFLAGS_PRIOR_CF);
|
|
setFlagInfo(FLAG_TF, Prior, X86_EFLAGS_PRIOR_TF);
|
|
setFlagInfo(FLAG_IF, Prior, X86_EFLAGS_PRIOR_IF);
|
|
setFlagInfo(FLAG_DF, Prior, X86_EFLAGS_PRIOR_DF);
|
|
setFlagInfo(FLAG_NT, Prior, X86_EFLAGS_PRIOR_NT);
|
|
//Write
|
|
setFlagInfo(FLAG_OF, Reset, X86_EFLAGS_RESET_OF);
|
|
setFlagInfo(FLAG_CF, Reset, X86_EFLAGS_RESET_CF);
|
|
setFlagInfo(FLAG_DF, Reset, X86_EFLAGS_RESET_DF);
|
|
setFlagInfo(FLAG_IF, Reset, X86_EFLAGS_RESET_IF);
|
|
setFlagInfo(FLAG_SF, Reset, X86_EFLAGS_RESET_SF);
|
|
setFlagInfo(FLAG_AF, Reset, X86_EFLAGS_RESET_AF);
|
|
setFlagInfo(FLAG_TF, Reset, X86_EFLAGS_RESET_TF);
|
|
setFlagInfo(FLAG_NT, Reset, X86_EFLAGS_RESET_NT);
|
|
setFlagInfo(FLAG_PF, Reset, X86_EFLAGS_RESET_PF);
|
|
//Write
|
|
setFlagInfo(FLAG_CF, Set, X86_EFLAGS_SET_CF);
|
|
setFlagInfo(FLAG_DF, Set, X86_EFLAGS_SET_DF);
|
|
setFlagInfo(FLAG_IF, Set, X86_EFLAGS_SET_IF);
|
|
//Read
|
|
setFlagInfo(FLAG_OF, Test, X86_EFLAGS_TEST_OF);
|
|
setFlagInfo(FLAG_SF, Test, X86_EFLAGS_TEST_SF);
|
|
setFlagInfo(FLAG_ZF, Test, X86_EFLAGS_TEST_ZF);
|
|
setFlagInfo(FLAG_PF, Test, X86_EFLAGS_TEST_PF);
|
|
setFlagInfo(FLAG_CF, Test, X86_EFLAGS_TEST_CF);
|
|
setFlagInfo(FLAG_NT, Test, X86_EFLAGS_TEST_NT);
|
|
setFlagInfo(FLAG_DF, Test, X86_EFLAGS_TEST_DF);
|
|
//None
|
|
setFlagInfo(FLAG_OF, Undefined, X86_EFLAGS_UNDEFINED_OF);
|
|
setFlagInfo(FLAG_SF, Undefined, X86_EFLAGS_UNDEFINED_SF);
|
|
setFlagInfo(FLAG_ZF, Undefined, X86_EFLAGS_UNDEFINED_ZF);
|
|
setFlagInfo(FLAG_PF, Undefined, X86_EFLAGS_UNDEFINED_PF);
|
|
setFlagInfo(FLAG_AF, Undefined, X86_EFLAGS_UNDEFINED_AF);
|
|
setFlagInfo(FLAG_CF, Undefined, X86_EFLAGS_UNDEFINED_CF);
|
|
#undef setFlagInfo
|
|
}
|
|
|
|
const char* Capstone::FlagName(Flag flag) const
|
|
{
|
|
switch(flag)
|
|
{
|
|
case FLAG_AF:
|
|
return "AF";
|
|
case FLAG_CF:
|
|
return "CF";
|
|
case FLAG_SF:
|
|
return "SF";
|
|
case FLAG_ZF:
|
|
return "ZF";
|
|
case FLAG_PF:
|
|
return "PF";
|
|
case FLAG_OF:
|
|
return "OF";
|
|
case FLAG_TF:
|
|
return "TF";
|
|
case FLAG_IF:
|
|
return "IF";
|
|
case FLAG_DF:
|
|
return "DF";
|
|
case FLAG_NT:
|
|
return "NT";
|
|
case FLAG_RF:
|
|
return "RF";
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|