Replace Capstone with Zydis

- While at it, added branch info logic to disassembler class
  - Thus reduce direct checks by mnemonic in GUI and analysis code
- Replaced direct disassembler struct access with disassembler class calls where trivially possible
- Removed workarounds for empty segment registers
- Temp. disabled `cbInstrCapstone` command
- Temp. disabled flag stuff in `QBeaEngine`
This commit is contained in:
Joel Höner 2017-09-20 08:17:34 +02:00 committed by Duncan Ogilvie
parent 103866eafe
commit 5338a0a85b
31 changed files with 292 additions and 319 deletions

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "deps"]
path = deps
url = https://github.com/x64dbg/deps
[submodule "src/zydis_wrapper"]
path = src/zydis_wrapper
url = https://athre0z@github.com/athre0z/zydis-x64dbg-module.git

View File

@ -1,5 +1,5 @@
#include "TraceRecord.h"
#include "capstone_wrapper.h"
#include "zydis_wrapper.h"
#include "module.h"
#include "memory.h"
#include "threading.h"

View File

@ -355,9 +355,9 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, BRID
if(instr.arg[i].constant == instr.arg[i].value) //avoid: call <module.label> ; addr:label
{
auto constant = instr.arg[i].constant;
if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.InGroup(CS_GRP_CALL))
if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.IsCall())
temp_string.assign("call $0");
else if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.InGroup(CS_GRP_JUMP))
else if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.IsJump())
temp_string.assign("jmp $0");
else if(instr.type == instr_branch)
continue;
@ -738,77 +738,77 @@ extern "C" DLL_EXPORT duint _dbg_getbranchdestination(duint addr)
Capstone cp;
if(!cp.Disassemble(addr, data))
return 0;
if(cp.InGroup(CS_GRP_JUMP) || cp.InGroup(CS_GRP_CALL) || cp.IsLoop())
if(cp.IsBranchType(Capstone::BT_Jmp | Capstone::BT_Call | Capstone::BT_Loop))
{
auto opValue = cp.ResolveOpValue(0, [](x86_reg reg) -> size_t
auto opValue = cp.ResolveOpValue(0, [](ZydisRegister reg) -> size_t
{
switch(reg)
switch(reg)
{
#ifndef _WIN64 //x32
case X86_REG_EAX:
case ZYDIS_REGISTER_EAX:
return titcontext.cax;
case X86_REG_EBX:
case ZYDIS_REGISTER_EBX:
return titcontext.cbx;
case X86_REG_ECX:
case ZYDIS_REGISTER_ECX:
return titcontext.ccx;
case X86_REG_EDX:
case ZYDIS_REGISTER_EDX:
return titcontext.cdx;
case X86_REG_EBP:
case ZYDIS_REGISTER_EBP:
return titcontext.cbp;
case X86_REG_ESP:
case ZYDIS_REGISTER_ESP:
return titcontext.csp;
case X86_REG_ESI:
case ZYDIS_REGISTER_ESI:
return titcontext.csi;
case X86_REG_EDI:
case ZYDIS_REGISTER_EDI:
return titcontext.cdi;
case X86_REG_EIP:
case ZYDIS_REGISTER_EIP:
return titcontext.cip;
#else //x64
case X86_REG_RAX:
case ZYDIS_REGISTER_RAX:
return titcontext.cax;
case X86_REG_RBX:
case ZYDIS_REGISTER_RBX:
return titcontext.cbx;
case X86_REG_RCX:
case ZYDIS_REGISTER_RCX:
return titcontext.ccx;
case X86_REG_RDX:
case ZYDIS_REGISTER_RDX:
return titcontext.cdx;
case X86_REG_RBP:
case ZYDIS_REGISTER_RBP:
return titcontext.cbp;
case X86_REG_RSP:
case ZYDIS_REGISTER_RSP:
return titcontext.csp;
case X86_REG_RSI:
case ZYDIS_REGISTER_RSI:
return titcontext.csi;
case X86_REG_RDI:
case ZYDIS_REGISTER_RDI:
return titcontext.cdi;
case X86_REG_RIP:
case ZYDIS_REGISTER_RIP:
return titcontext.cip;
case X86_REG_R8:
case ZYDIS_REGISTER_R8:
return titcontext.r8;
case X86_REG_R9:
case ZYDIS_REGISTER_R9:
return titcontext.r9;
case X86_REG_R10:
case ZYDIS_REGISTER_R10:
return titcontext.r10;
case X86_REG_R11:
case ZYDIS_REGISTER_R11:
return titcontext.r11;
case X86_REG_R12:
case ZYDIS_REGISTER_R12:
return titcontext.r12;
case X86_REG_R13:
case ZYDIS_REGISTER_R13:
return titcontext.r13;
case X86_REG_R14:
case ZYDIS_REGISTER_R14:
return titcontext.r14;
case X86_REG_R15:
case ZYDIS_REGISTER_R15:
return titcontext.r15;
#endif //_WIN64
default:
return 0;
}
});
if(cp[0].type == X86_OP_MEM)
if(cp[0].type == ZYDIS_OPERAND_TYPE_MEMORY)
{
#ifdef _WIN64
auto const tebseg = X86_REG_GS;
auto const tebseg = ZYDIS_REGISTER_GS;
#else
auto const tebseg = X86_REG_FS;
auto const tebseg = ZYDIS_REGISTER_FS;
#endif //_WIN64
if(cp[0].mem.segment == tebseg)
opValue += duint(GetTEBLocation(hActiveThread));
@ -818,7 +818,7 @@ extern "C" DLL_EXPORT duint _dbg_getbranchdestination(duint addr)
else
return opValue;
}
if(cp.InGroup(CS_GRP_RET))
if(cp.IsRet())
{
auto csp = titcontext.csp;
duint dest = 0;

View File

@ -31,16 +31,16 @@ bool CodeFollowPass::Analyse()
return false;
}
duint CodeFollowPass::GetReferenceOperand(const cs_x86 & Context)
duint CodeFollowPass::GetReferenceOperand(const ZydisDecodedInstruction & Context)
{
for(int i = 0; i < Context.op_count; i++)
for(int i = 0; i < Context.operandCount; i++)
{
auto operand = Context.operands[i];
// Looking for immediate references
if(operand.type == X86_OP_IMM)
if(operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE)
{
duint dest = (duint)operand.imm;
duint dest = (duint)operand.imm.value.u;
if(ValidateAddress(dest))
return dest;
@ -50,25 +50,25 @@ duint CodeFollowPass::GetReferenceOperand(const cs_x86 & Context)
return 0;
}
duint CodeFollowPass::GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect)
duint CodeFollowPass::GetMemoryOperand(Capstone & Disasm, const ZydisDecodedInstruction & Context, bool* Indirect)
{
if(Context.op_count <= 0)
if(Context.operandCount <= 0)
return 0;
// Only the first operand matters
auto operand = Context.operands[0];
// Jumps and calls only
if(Disasm.InGroup(CS_GRP_CALL) || Disasm.InGroup(CS_GRP_JUMP))
if(Disasm.IsCall() || Disasm.IsJump())
{
// Looking for memory references
if(operand.type == X86_OP_MEM)
if(operand.type == ZYDIS_OPERAND_TYPE_MEMORY)
{
// Notify if the operand was indirect
if(Indirect)
{
if(operand.mem.base != X86_REG_INVALID ||
operand.mem.index != X86_REG_INVALID ||
if(operand.mem.base != ZYDIS_REGISTER_NONE ||
operand.mem.index != ZYDIS_REGISTER_NONE ||
operand.mem.scale != 0)
{
*Indirect = true;
@ -81,7 +81,7 @@ duint CodeFollowPass::GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context
// TODO: Translate RIP-Relative
return 0;
duint dest = (duint)operand.mem.disp;
duint dest = (duint)operand.mem.disp.value;
if(ValidateAddress(dest))
return dest;

View File

@ -2,7 +2,7 @@
#include "AnalysisPass.h"
#include "BasicBlock.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
class CodeFollowPass : public AnalysisPass
{
@ -14,6 +14,6 @@ public:
virtual bool Analyse() override;
private:
duint GetReferenceOperand(const cs_x86 & Context);
duint GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect);
duint GetReferenceOperand(const ZydisDecodedInstruction & Context);
duint GetMemoryOperand(Capstone & Disasm, const ZydisDecodedInstruction & Context, bool* Indirect);
};

View File

@ -2,7 +2,7 @@
#include <ppl.h>
#include "AnalysisPass.h"
#include "LinearPass.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
LinearPass::LinearPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
@ -167,10 +167,10 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
insnCount++;
// The basic block ends here if it is a branch
bool call = disasm.InGroup(CS_GRP_CALL); // CALL
bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP
bool ret = disasm.InGroup(CS_GRP_RET); // RETURN
bool padding = disasm.IsFilling(); // INSTRUCTION PADDING
bool call = disasm.IsCall(); // CALL
bool jmp = disasm.IsJump(); // JUMP
bool ret = disasm.IsRet(); // RETURN
bool padding = disasm.IsFilling(); // INSTRUCTION PADDING
if(padding)
{
@ -211,25 +211,25 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
if(!padding)
{
// Check if absolute jump, regardless of operand
if(disasm.GetId() == X86_INS_JMP)
if(disasm.GetId() == ZYDIS_MNEMONIC_JMP)
block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP);
// Figure out the operand type(s)
const auto & operand = disasm.x86().operands[0];
const auto & operand = disasm[0];
if(operand.type == X86_OP_IMM)
if(operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE)
{
// Branch target immediate
block->Target = (duint)operand.imm;
block->Target = (duint)operand.imm.value.u;
}
else
{
// Indirects (no operand, register, or memory)
block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT);
if(operand.type == X86_OP_MEM &&
operand.mem.base == X86_REG_RIP &&
operand.mem.index == X86_REG_INVALID &&
if(operand.type == ZYDIS_OPERAND_TYPE_MEMORY &&
operand.mem.base == ZYDIS_REGISTER_RIP &&
operand.mem.index == ZYDIS_REGISTER_NONE &&
operand.mem.scale == 1)
{
/*

View File

@ -106,11 +106,11 @@ void AdvancedAnalysis::analyzeFunction(duint entryPoint, bool writedata)
for(int i = 1; i < mCp.Size(); i++)
mEncMap[node.end - mBase + i] = (byte)enc_middle;
}
if(mCp.InGroup(CS_GRP_JUMP) || mCp.IsLoop()) //jump
if(mCp.IsJump() || mCp.IsLoop()) //jump
{
//set the branch destinations
node.brtrue = mCp.BranchDestination();
if(mCp.GetId() != X86_INS_JMP) //unconditional jumps dont have a brfalse
if(mCp.GetId() != ZYDIS_MNEMONIC_JMP) //unconditional jumps dont have a brfalse
node.brfalse = node.end + mCp.Size();
//add node to the function graph
@ -124,14 +124,14 @@ void AdvancedAnalysis::analyzeFunction(duint entryPoint, bool writedata)
break;
}
if(mCp.InGroup(CS_GRP_CALL)) //call
if(mCp.IsCall()) //call
{
//TODO: handle no return
duint target = mCp.BranchDestination();
if(inRange(target) && mEntryPoints.find(target) == mEntryPoints.end())
mCandidateEPs.insert(target);
}
if(mCp.InGroup(CS_GRP_RET)) //return
if(mCp.IsRet()) //return
{
node.terminal = true;
graph.AddNode(node);
@ -164,7 +164,7 @@ void AdvancedAnalysis::linearXrefPass()
xref.from = mCp.Address();
for(auto i = 0; i < mCp.OpCount(); i++)
{
duint dest = mCp.ResolveOpValue(i, [](x86_reg)->size_t
duint dest = mCp.ResolveOpValue(i, [](ZydisRegister)->size_t
{
return 0;
});
@ -176,9 +176,9 @@ void AdvancedAnalysis::linearXrefPass()
}
if(xref.addr)
{
if(mCp.InGroup(CS_GRP_CALL))
if(mCp.IsCall())
xref.type = XREF_CALL;
else if(mCp.InGroup(CS_GRP_JUMP))
else if(mCp.IsJump())
xref.type = XREF_JMP;
else
xref.type = XREF_DATA;
@ -218,21 +218,21 @@ void AdvancedAnalysis::findInvalidXrefs()
}
}
bool isFloatInstruction(x86_insn opcode)
bool isFloatInstruction(ZydisMnemonic opcode)
{
switch(opcode)
{
case X86_INS_FLD:
case X86_INS_FST:
case X86_INS_FSTP:
case X86_INS_FADD:
case X86_INS_FSUB:
case X86_INS_FSUBR:
case X86_INS_FMUL:
case X86_INS_FDIV:
case X86_INS_FDIVR:
case X86_INS_FCOM:
case X86_INS_FCOMP:
case ZYDIS_MNEMONIC_FLD:
case ZYDIS_MNEMONIC_FST:
case ZYDIS_MNEMONIC_FSTP:
case ZYDIS_MNEMONIC_FADD:
case ZYDIS_MNEMONIC_FSUB:
case ZYDIS_MNEMONIC_FSUBR:
case ZYDIS_MNEMONIC_FMUL:
case ZYDIS_MNEMONIC_FDIV:
case ZYDIS_MNEMONIC_FDIVR:
case ZYDIS_MNEMONIC_FCOM:
case ZYDIS_MNEMONIC_FCOMP:
return true;
default:
@ -261,7 +261,7 @@ void AdvancedAnalysis::writeDataXrefs()
ENCODETYPE type = enc_unknown;
//Todo: Analyze op type and set correct type
if(op.type == X86_OP_MEM)
if(op.type == ZYDIS_OPERAND_TYPE_MEMORY)
{
duint datasize = op.size;
duint size = datasize;

View File

@ -2,7 +2,7 @@
#define _ANALYSIS_H
#include "_global.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
class Analysis
{

View File

@ -150,15 +150,15 @@ void ControlFlowAnalysis::BasicBlockStarts()
mBlockStarts.insert(addr);
}
}
else if(mCp.InGroup(CS_GRP_RET)) //RET breaks control flow
else if(mCp.IsRet()) //RET breaks control flow
{
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
}
else if(mCp.InGroup(CS_GRP_JUMP) || mCp.IsLoop()) //branches
else if(mCp.IsJump() || mCp.IsLoop()) //branches
{
auto dest1 = getReferenceOperand();
duint dest2 = 0;
if(mCp.GetId() != X86_INS_JMP) //conditional jump
if(mCp.GetId() != ZYDIS_MNEMONIC_JMP) //conditional jump
dest2 = addr + mCp.Size();
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
@ -168,7 +168,7 @@ void ControlFlowAnalysis::BasicBlockStarts()
if(dest2)
mBlockStarts.insert(dest2);
}
else if(mCp.InGroup(CS_GRP_CALL))
else if(mCp.IsCall())
{
auto dest1 = getReferenceOperand();
if(dest1)
@ -206,15 +206,15 @@ void ControlFlowAnalysis::BasicBlocks()
prevaddr = addr;
if(mCp.Disassemble(addr, translateAddr(addr), MAX_DISASM_BUFFER))
{
if(mCp.InGroup(CS_GRP_RET))
if(mCp.IsRet())
{
insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
break;
}
else if(mCp.InGroup(CS_GRP_JUMP) || mCp.IsLoop())
else if(mCp.IsJump() || mCp.IsLoop())
{
auto dest1 = getReferenceOperand();
auto dest2 = mCp.GetId() != X86_INS_JMP ? addr + mCp.Size() : 0;
auto dest2 = mCp.GetId() != ZYDIS_MNEMONIC_JMP ? addr + mCp.Size() : 0;
insertBlock(BasicBlock(start, addr, dest1, dest2));
insertParent(dest1, start);
insertParent(dest2, start);
@ -415,17 +415,17 @@ duint ControlFlowAnalysis::getReferenceOperand() const
{
for(auto i = 0; i < mCp.OpCount(); i++)
{
const auto & op = mCp.x86().operands[i];
if(op.type == X86_OP_IMM)
const auto & op = mCp[i];
if(op.type == ZYDIS_OPERAND_TYPE_IMMEDIATE)
{
auto dest = duint(op.imm);
auto dest = duint(op.imm.value.u);
if(inRange(dest))
return dest;
}
else if(op.type == X86_OP_MEM)
else if(op.type == ZYDIS_OPERAND_TYPE_MEMORY)
{
auto dest = duint(op.mem.disp);
if(op.mem.base == X86_REG_RIP) //rip-relative
auto dest = duint(op.mem.disp.value);
if(op.mem.base == ZYDIS_REGISTER_RIP) //rip-relative
dest += mCp.Address() + mCp.Size();
if(inRange(dest))
return dest;

View File

@ -86,7 +86,7 @@ duint LinearAnalysis::findFunctionEnd(duint start, duint maxaddr)
if(mCp.Disassemble(start, translateAddr(start), MAX_DISASM_BUFFER))
{
//JMP [123456] ; import
if(mCp.InGroup(CS_GRP_JUMP) && mCp.x86().operands[0].type == X86_OP_MEM)
if(mCp.IsJump() && mCp[0].type == ZYDIS_OPERAND_TYPE_MEMORY)
return 0;
}
@ -100,10 +100,10 @@ duint LinearAnalysis::findFunctionEnd(duint start, duint maxaddr)
if(addr + mCp.Size() > maxaddr) //we went past the maximum allowed address
break;
const auto & op = mCp.x86().operands[0];
if((mCp.InGroup(CS_GRP_JUMP) || mCp.IsLoop()) && op.type == X86_OP_IMM) //jump
const auto & op = mCp[0];
if((mCp.IsJump() || mCp.IsLoop()) && op.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) //jump
{
auto dest = duint(op.imm);
auto dest = duint(op.imm.value.u);
if(dest >= maxaddr) //jump across function boundaries
{
@ -113,12 +113,12 @@ duint LinearAnalysis::findFunctionEnd(duint start, duint maxaddr)
{
fardest = dest;
}
else if(end && dest < end && (mCp.GetId() == X86_INS_JMP || mCp.GetId() == X86_INS_LOOP)) //save the last JMP backwards
else if(end && dest < end && (mCp.GetId() == ZYDIS_MNEMONIC_JMP || mCp.GetId() == ZYDIS_MNEMONIC_LOOP)) //save the last JMP backwards
{
jumpback = addr;
}
}
else if(mCp.InGroup(CS_GRP_RET)) //possible function end?
else if(mCp.IsRet()) //possible function end?
{
end = addr;
if(fardest < addr) //we stop if the farthest JXX destination forward is before this RET
@ -137,12 +137,12 @@ duint LinearAnalysis::getReferenceOperand() const
{
for(auto i = 0; i < mCp.OpCount(); i++)
{
const auto & op = mCp.x86().operands[i];
if(mCp.InGroup(CS_GRP_JUMP) || mCp.IsLoop()) //skip jumps/loops
const auto & op = mCp[i];
if(mCp.IsJump() || mCp.IsLoop()) //skip jumps/loops
continue;
if(op.type == X86_OP_IMM) //we are looking for immediate references
if(op.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) //we are looking for immediate references
{
auto dest = duint(op.imm);
auto dest = duint(op.imm.value.u);
if(inRange(dest))
return dest;
}

View File

@ -103,7 +103,7 @@ void RecursiveAnalysis::analyzeFunction(duint entryPoint)
xref.from = mCp.Address();
for(auto i = 0; i < mCp.OpCount(); i++)
{
duint dest = mCp.ResolveOpValue(i, [](x86_reg)->size_t
duint dest = mCp.ResolveOpValue(i, [](ZydisRegister)->size_t
{
return 0;
});
@ -116,23 +116,23 @@ void RecursiveAnalysis::analyzeFunction(duint entryPoint)
if(xref.addr)
mXrefs.push_back(xref);
if(!mCp.IsNop() && (mCp.InGroup(CS_GRP_JUMP) || mCp.IsLoop())) //non-nop jump
if(!mCp.IsNop() && (mCp.IsJump() || mCp.IsLoop())) //non-nop jump
{
//set the branch destinations
node.brtrue = mCp.BranchDestination();
if(mCp.GetId() != X86_INS_JMP && mCp.GetId() != X86_INS_LJMP) //unconditional jumps dont have a brfalse
if(mCp.GetId() != ZYDIS_MNEMONIC_JMP) //unconditional jumps dont have a brfalse
node.brfalse = node.end + mCp.Size();
//consider register/memory branches as terminal nodes
if(mCp[0].type != X86_OP_IMM)
if(mCp[0].type != ZYDIS_OPERAND_TYPE_IMMEDIATE)
{
//jmp ptr [index * sizeof(duint) + switchTable]
if(mCp[0].type == X86_OP_MEM && mCp[0].mem.base == X86_OP_INVALID && mCp[0].mem.index != X86_OP_INVALID
&& mCp[0].mem.scale == sizeof(duint) && MemIsValidReadPtr(duint(mCp[0].mem.disp)))
if(mCp[0].type == ZYDIS_OPERAND_TYPE_MEMORY && mCp[0].mem.base == ZYDIS_REGISTER_NONE && mCp[0].mem.index != ZYDIS_REGISTER_NONE
&& mCp[0].mem.scale == sizeof(duint) && MemIsValidReadPtr(duint(mCp[0].mem.disp.value)))
{
Memory<duint*> switchTable(512 * sizeof(duint));
duint actualSize, index;
MemRead(duint(mCp[0].mem.disp), switchTable(), 512 * sizeof(duint), &actualSize);
MemRead(duint(mCp[0].mem.disp.value), switchTable(), 512 * sizeof(duint), &actualSize);
actualSize /= sizeof(duint);
for(index = 0; index < actualSize; index++)
if(MemIsCodePage(switchTable()[index], false) == false)
@ -168,11 +168,11 @@ void RecursiveAnalysis::analyzeFunction(duint entryPoint)
break;
}
if(mCp.InGroup(CS_GRP_CALL)) //call
if(mCp.IsCall())
{
//TODO: add this to a queue to be analyzed later
}
if(mCp.InGroup(CS_GRP_RET)) //return
if(mCp.IsRet())
{
node.terminal = true;
graph.AddNode(node);
@ -224,17 +224,17 @@ void RecursiveAnalysis::analyzeFunction(duint entryPoint)
while(addr <= node.end) //disassemble all instructions
{
auto size = mCp.Disassemble(addr, translateAddr(addr)) ? mCp.Size() : 1;
if(mCp.InGroup(CS_GRP_CALL) && mCp.OpCount()) //call reg / call [reg+X]
if(mCp.IsCall() && mCp.OpCount()) //call reg / call [reg+X]
{
auto & op = mCp[0];
switch(op.type)
{
case X86_OP_REG:
case ZYDIS_OPERAND_TYPE_REGISTER:
node.indirectcall = true;
break;
case X86_OP_MEM:
node.indirectcall |= op.mem.base != X86_REG_RIP &&
(op.mem.base != X86_REG_INVALID || op.mem.index != X86_REG_INVALID);
case ZYDIS_OPERAND_TYPE_MEMORY:
node.indirectcall |= op.mem.base != ZYDIS_REGISTER_RIP &&
(op.mem.base != ZYDIS_REGISTER_NONE || op.mem.index != ZYDIS_REGISTER_NONE);
break;
default:
break;

View File

@ -21,7 +21,7 @@ void XrefsAnalysis::Analyse()
xref.from = mCp.Address();
for(auto i = 0; i < mCp.OpCount(); i++)
{
duint dest = mCp.ResolveOpValue(i, [](x86_reg)->size_t
duint dest = mCp.ResolveOpValue(i, [](ZydisRegister)->size_t
{
return 0;
});

View File

@ -570,8 +570,8 @@ static bool cbModCallFind(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo, R
}
switch(disasm->GetId())
{
case X86_INS_CALL: //call dword ptr: [&api]
case X86_INS_MOV: //mov reg, dword ptr:[&api]
case ZYDIS_MNEMONIC_CALL: //call dword ptr: [&api]
case ZYDIS_MNEMONIC_MOV: //mov reg, dword ptr:[&api]
if(!foundaddr && basicinfo->memory.value)
{
duint memaddr;

View File

@ -7,7 +7,7 @@
#include "debugger.h"
#include "variable.h"
#include "loop.h"
#include "capstone_wrapper.h"
#include "zydis_wrapper.h"
#include "mnemonichelp.h"
#include "value.h"
#include "symbolinfo.h"
@ -209,6 +209,9 @@ bool cbInstrCopystr(int argc, char* argv[])
bool cbInstrCapstone(int argc, char* argv[])
{
return false;
/*
if(IsArgumentsLessThan(argc, 2))
return false;
@ -237,10 +240,8 @@ bool cbInstrCapstone(int argc, char* argv[])
return false;
}
const cs_insn* instr = cp.GetInstr();
const cs_detail* detail = instr->detail;
const cs_x86 & x86 = cp.x86();
int argcount = x86.op_count;
auto instr = cp.GetInstr();
int argcount = instr->operandCount;
dprintf_untranslated("%s %s | %s\n", instr->mnemonic, instr->op_str, cp.InstructionText(true).c_str());
dprintf_untranslated("size: %d, id: %d, opcount: %d\n", cp.Size(), cp.GetId(), cp.OpCount());
if(detail->regs_read_count)
@ -301,6 +302,7 @@ bool cbInstrCapstone(int argc, char* argv[])
}
return true;
*/
}
bool cbInstrVisualize(int argc, char* argv[])
@ -357,10 +359,10 @@ bool cbInstrVisualize(int argc, char* argv[])
if(addr + _cp.Size() > maxaddr) //we went past the maximum allowed address
break;
const cs_x86_op & operand = _cp.x86().operands[0];
if((_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) && operand.type == X86_OP_IMM) //jump
const auto & operand = _cp[0];
if((_cp.IsJump() || _cp.IsLoop()) && operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) //jump
{
duint dest = (duint)operand.imm;
duint dest = (duint)operand.imm.value.u;
if(dest >= maxaddr) //jump across function boundaries
{
@ -370,12 +372,12 @@ bool cbInstrVisualize(int argc, char* argv[])
{
fardest = dest;
}
else if(end && dest < end && _cp.GetId() == X86_INS_JMP) //save the last JMP backwards
else if(end && dest < end && _cp.GetId() == ZYDIS_MNEMONIC_JMP) //save the last JMP backwards
{
jumpback = addr;
}
}
else if(_cp.InGroup(CS_GRP_RET)) //possible function end?
else if(_cp.IsRet()) //possible function end?
{
end = addr;
if(fardest < addr) //we stop if the farthest JXX destination forward is before this RET

View File

@ -2,7 +2,7 @@
#include "encodemap.h"
#include "stringutils.h"
#include "value.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
#include <algorithm>
std::unordered_map<ENCODETYPE, std::string> disasmMap;

View File

@ -27,7 +27,7 @@
#include "taskthread.h"
#include "animate.h"
#include "simplescript.h"
#include "capstone_wrapper.h"
#include "zydis_wrapper.h"
#include "cmd-watch-control.h"
#include "filemap.h"
#include "jit.h"
@ -1164,7 +1164,7 @@ void cbRtrStep()
unsigned char data[MAX_DISASM_BUFFER];
memset(data, 0, sizeof(data));
MemRead(cip, data, MAX_DISASM_BUFFER);
if(cp.Disassemble(cip, data) && cp.GetId() == X86_INS_RET)
if(cp.Disassemble(cip, data) && cp.IsRet())
cbRtrFinalStep(true);
else
StepOver((void*)cbRtrStep);

View File

@ -34,53 +34,53 @@ void fillbasicinfo(Capstone* cp, BASIC_INSTRUCTION_INFO* basicinfo, bool instrTe
//instruction size
basicinfo->size = cp->Size();
//branch/call info
if(cp->InGroup(CS_GRP_CALL))
if(cp->IsCall())
{
basicinfo->branch = true;
basicinfo->call = true;
}
else if(cp->InGroup(CS_GRP_JUMP) || cp->IsLoop())
else if(cp->IsJump() || cp->IsLoop())
{
basicinfo->branch = true;
}
//handle operands
for(int i = 0; i < cp->x86().op_count; i++)
for(int i = 0; i < cp->OpCount(); i++)
{
const cs_x86_op & op = cp->x86().operands[i];
const auto & op = (*cp)[i];
switch(op.type)
{
case X86_OP_IMM:
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
{
if(basicinfo->branch)
{
basicinfo->type |= TYPE_ADDR;
basicinfo->addr = duint(op.imm);
basicinfo->value.value = duint(op.imm);
basicinfo->addr = duint(op.imm.value.u);
basicinfo->value.value = duint(op.imm.value.u);
}
else
{
basicinfo->type |= TYPE_VALUE;
basicinfo->value.size = VALUE_SIZE(op.size);
basicinfo->value.value = duint(op.imm);
basicinfo->value.value = duint(op.imm.value.u);
}
}
break;
case X86_OP_MEM:
case ZYDIS_OPERAND_TYPE_MEMORY:
{
const x86_op_mem & mem = op.mem;
const auto & mem = op.mem;
if(instrText)
strcpy_s(basicinfo->memory.mnemonic, cp->OperandText(i).c_str());
basicinfo->memory.size = MEMORY_SIZE(op.size);
if(op.mem.base == X86_REG_RIP) //rip-relative
if(op.mem.base == ZYDIS_REGISTER_RIP) //rip-relative
{
basicinfo->memory.value = ULONG_PTR(cp->Address() + op.mem.disp + basicinfo->size);
basicinfo->memory.value = ULONG_PTR(cp->Address() + op.mem.disp.value + basicinfo->size);
basicinfo->type |= TYPE_MEMORY;
}
else if(mem.disp)
else if(mem.disp.value)
{
basicinfo->type |= TYPE_MEMORY;
basicinfo->memory.value = ULONG_PTR(mem.disp);
basicinfo->memory.value = ULONG_PTR(mem.disp.value);
}
}
break;

View File

@ -2,7 +2,7 @@
#define _DISASM_FAST_H
#include "_global.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
void fillbasicinfo(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo, bool instrText = true);
bool disasmfast(duint addr, BASIC_INSTRUCTION_INFO* basicinfo, bool cache = false);

View File

@ -11,7 +11,7 @@
#include "debugger.h"
#include "value.h"
#include "encodemap.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
#include "datainst_helper.h"
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n)
@ -113,7 +113,7 @@ duint disasmnext(unsigned char* data, duint base, duint size, duint ip, int n)
static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg, bool getregs)
{
auto value = cp.ResolveOpValue(opindex, [&cp, getregs](x86_reg reg)
auto value = cp.ResolveOpValue(opindex, [&cp, getregs](ZydisRegister reg)
{
auto regName = getregs ? cp.RegName(reg) : nullptr;
return regName ? getregister(nullptr, regName) : 0; //TODO: temporary needs enums + caching
@ -123,34 +123,34 @@ static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg, b
strcpy_s(arg->mnemonic, cp.OperandText(opindex).c_str());
switch(op.type)
{
case X86_OP_REG:
case ZYDIS_OPERAND_TYPE_REGISTER:
{
arg->type = arg_normal;
arg->value = value;
}
break;
case X86_OP_IMM:
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
{
arg->type = arg_normal;
arg->constant = arg->value = value;
}
break;
case X86_OP_MEM:
case ZYDIS_OPERAND_TYPE_MEMORY:
{
arg->type = arg_memory;
const x86_op_mem & mem = op.mem;
if(mem.base == X86_REG_RIP) //rip-relative
arg->constant = cp.Address() + duint(mem.disp) + cp.Size();
const auto & mem = op.mem;
if(mem.base == ZYDIS_REGISTER_RIP) //rip-relative
arg->constant = cp.Address() + duint(mem.disp.value) + cp.Size();
else
arg->constant = duint(mem.disp);
arg->constant = duint(mem.disp.value);
#ifdef _WIN64
if(mem.segment == X86_REG_GS)
if(mem.segment == ZYDIS_REGISTER_GS)
{
arg->segment = SEG_GS;
#else //x86
if(mem.segment == X86_REG_FS)
if(mem.segment == ZYDIS_REGISTER_FS)
{
arg->segment = SEG_FS;
#endif
@ -199,16 +199,16 @@ void disasmget(Capstone & cp, unsigned char* buffer, duint addr, DISASM_INSTR* i
instr->argcount = 0;
return;
}
const cs_insn* cpInstr = cp.GetInstr();
sprintf_s(instr->instruction, "%s %s", cpInstr->mnemonic, cpInstr->op_str);
instr->instr_size = cpInstr->size;
if(cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL))
auto cpInstr = cp.GetInstr();
strcpy_s(instr->instruction, cp.InstructionText().c_str());
instr->instr_size = cpInstr->length;
if(cp.IsBranchType(Capstone::BT_Jmp | Capstone::BT_Loop | Capstone::BT_Ret | Capstone::BT_Call))
instr->type = instr_branch;
else if(strstr(cpInstr->op_str, "sp") || strstr(cpInstr->op_str, "bp"))
else if(strstr(instr->instruction, "sp") || strstr(instr->instruction, "bp"))
instr->type = instr_stack;
else
instr->type = instr_normal;
instr->argcount = cp.x86().op_count <= 3 ? cp.x86().op_count : 3;
instr->argcount = cp.OpCount() <= 3 ? cp.OpCount() : 3;
for(int i = 0; i < instr->argcount; i++)
HandleCapstoneOperand(cp, i, &instr->arg[i], getregs);
}

View File

@ -2,7 +2,7 @@
#define _DISASM_HELPER_H
#include "_global.h"
#include "capstone_wrapper.h"
#include "zydis_wrapper.h"
//functions
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n);

View File

@ -1,7 +1,7 @@
#include "encodemap.h"
#include <unordered_map>
#include "addrinfo.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
struct ENCODEMAP : AddrInfo
{

View File

@ -16,7 +16,7 @@
#include "watch.h"
#include "plugin_loader.h"
#include "_dbgfunctions.h"
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
#include "_scriptapi_gui.h"
#include "filehelper.h"
#include "database.h"

View File

@ -389,13 +389,13 @@
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x64\</OutDir>
<TargetName>x64dbg</TargetName>
<IncludePath>$(ProjectDir)..\capstone_wrapper;$(ProjectDir);$(ProjectDir)analysis;$(ProjectDir)commands;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)..\zydis_wrapper;$(ProjectDir)..\capstone_wrapper;$(ProjectDir);$(ProjectDir)analysis;$(ProjectDir)commands;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\..\bin\x64d\</OutDir>
<TargetName>x64dbg</TargetName>
<IncludePath>$(ProjectDir)..\capstone_wrapper;$(ProjectDir);$(ProjectDir)analysis;$(ProjectDir)commands;$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)..\zydis_wrapper;$(ProjectDir)..\capstone_wrapper;$(ProjectDir);$(ProjectDir)analysis;$(ProjectDir)commands;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -467,7 +467,7 @@
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ntdll\ntdll_x64.lib;keystone\keystone_x64.lib;$(ProjectDir)..\capstone_wrapper\bin\x64\capstone_wrapper.lib;$(ProjectDir)..\capstone_wrapper\capstone\capstone_x64.lib;yara\yara_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64\x64bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(ProjectDir)..\zydis_wrapper\bin\x64\zydis_wrapper.lib;$(ProjectDir)..\zydis_wrapper\Zydis\Zydis_x64.lib;$(ProjectDir)..\capstone_wrapper\bin\x64\capstone_wrapper.lib;$(ProjectDir)..\capstone_wrapper\capstone\capstone_x64.lib;ntdll\ntdll_x64.lib;keystone\keystone_x64.lib;yara\yara_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64\x64bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -491,7 +491,7 @@
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>false</EnableCOMDATFolding>
<OptimizeReferences>false</OptimizeReferences>
<AdditionalDependencies>ntdll\ntdll_x64.lib;keystone\keystone_x64.lib;$(ProjectDir)..\capstone_wrapper\bin\x64d\capstone_wrapper.lib;$(ProjectDir)..\capstone_wrapper\capstone\capstone_x64.lib;yara\yara_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64d\x64bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(ProjectDir)..\zydis_wrapper\bin\x64d\zydis_wrapper.lib;$(ProjectDir)..\zydis_wrapper\Zydis\Zydis_x64.lib;$(ProjectDir)..\capstone_wrapper\bin\x64d\capstone_wrapper.lib;$(ProjectDir)..\capstone_wrapper\capstone\capstone_x64.lib;ntdll\ntdll_x64.lib;keystone\keystone_x64.lib;yara\yara_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64d\x64bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;ws2_32.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -200,23 +200,15 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint origBase
auto branchType = Instruction_t::None;
Instruction_t wInst;
if(success && (cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_CALL) || cp.InGroup(CS_GRP_RET)))
if(success && (cp.IsBranchType(Capstone::BT_Jmp | Capstone::BT_Call | Capstone::BT_Ret | Capstone::BT_Loop)))
{
wInst.branchDestination = DbgGetBranchDestination(origBase + origInstRVA);
switch(cp.GetId())
{
case X86_INS_JMP:
case X86_INS_LJMP:
if(cp.IsBranchType(Capstone::BT_UncondJmp))
branchType = Instruction_t::Unconditional;
break;
case X86_INS_CALL:
case X86_INS_LCALL:
else if(cp.IsBranchType(Capstone::BT_Call))
branchType = Instruction_t::Call;
break;
default:
branchType = cp.InGroup(CS_GRP_RET) ? Instruction_t::None : Instruction_t::Conditional;
break;
}
else if(cp.IsBranchType(Capstone::BT_CondJmp))
branchType = Instruction_t::Conditional;
}
else
wInst.branchDestination = 0;
@ -233,8 +225,9 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint origBase
if(success)
{
/* TODO
auto instr = cp.GetInstr();
cp.RegInfo(reginfo);
cp.FlagInfo(flaginfo);
auto flaginfo2reginfo = [](uint8_t info)
{
@ -253,14 +246,15 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint origBase
for(uint8_t i = Capstone::FLAG_INVALID; i < Capstone::FLAG_ENDING; i++)
if(flaginfo[i])
{
reginfo[X86_REG_EFLAGS] = Capstone::None;
reginfo[ZYDIS_REGISTER_FLAGS] = Capstone::None;
wInst.regsReferenced.push_back({cp.FlagName(Capstone::Flag(i)), flaginfo2reginfo(flaginfo[i])});
}
reginfo[ArchValue(X86_REG_EIP, X86_REG_RIP)] = Capstone::None;
for(uint8_t i = X86_REG_INVALID; i < X86_REG_ENDING; i++)
reginfo[ArchValue(ZYDIS_REGISTER_EIP, ZYDIS_REGISTER_RIP)] = Capstone::None;
for(uint8_t i = ZYDIS_REGISTER_NONE; i < ZYDIS_REGISTER_ENUM_COUNT; i++)
if(reginfo[i])
wInst.regsReferenced.push_back({cp.RegName(x86_reg(i)), reginfo[i]});
*/
}
return wInst;

View File

@ -67,8 +67,8 @@ private:
bool _bLongDataInst;
EncodeMap* mEncodeMap;
CodeFoldingHelper* mCodeFoldingManager;
uint8_t reginfo[X86_REG_ENDING];
uint8_t flaginfo[Capstone::FLAG_ENDING];
uint8_t reginfo[ZYDIS_REGISTER_ENUM_COUNT];
uint8_t flaginfo[ZYDIS_CPUFLAG_ENUM_COUNT];
};
#endif // QBEAENGINE_H

View File

@ -362,21 +362,26 @@ bool CapstoneTokenizer::tokenizePrefix()
{
bool hasPrefix = true;
QString prefixText;
//TODO: look at multiple prefixes on one instruction (https://github.com/aquynh/capstone/blob/921904888d7c1547c558db3a24fa64bcf97dede4/arch/X86/X86DisassemblerDecoder.c#L540)
switch(_cp.x86().prefix[0])
{
case X86_PREFIX_LOCK:
//TODO: look at multiple prefixes on one instruction
auto attr = _cp.GetInstr()->attributes;
if(attr & ZYDIS_ATTRIB_HAS_LOCK)
prefixText = "lock";
break;
case X86_PREFIX_REP:
else if(attr & ZYDIS_ATTRIB_HAS_REP)
prefixText = "rep";
break;
case X86_PREFIX_REPNE:
else if(attr & ZYDIS_ATTRIB_HAS_REPNE)
prefixText = "repe";
else if(attr & ZYDIS_ATTRIB_HAS_REPNE)
prefixText = "repne";
break;
default:
else if(attr & ZYDIS_ATTRIB_HAS_BOUND)
prefixText = "bnd";
else if(attr & ZYDIS_ATTRIB_HAS_XACQUIRE)
prefixText = "xacquire";
else if(attr & ZYDIS_ATTRIB_HAS_XRELEASE)
prefixText = "xrelease";
else
hasPrefix = false;
}
if(hasPrefix)
{
@ -391,52 +396,25 @@ bool CapstoneTokenizer::tokenizeMnemonic()
{
QString mnemonic = QString(_cp.Mnemonic().c_str());
_mnemonicType = TokenType::MnemonicNormal;
auto id = _cp.GetId();
if(isNop)
_mnemonicType = TokenType::MnemonicNop;
else if(_cp.InGroup(CS_GRP_CALL))
else if(_cp.IsCall())
_mnemonicType = TokenType::MnemonicCall;
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
else if(_cp.IsJump() || _cp.IsLoop())
{
switch(id)
{
case X86_INS_JMP:
case X86_INS_LJMP:
_mnemonicType = TokenType::MnemonicUncondJump;
break;
default:
_mnemonicType = TokenType::MnemonicCondJump;
break;
}
_mnemonicType = (id == ZYDIS_MNEMONIC_JMP) ?
TokenType::MnemonicUncondJump : TokenType::MnemonicCondJump;
}
else if(_cp.IsInt3())
_mnemonicType = TokenType::MnemonicInt3;
else if(_cp.IsUnusual())
_mnemonicType = TokenType::MnemonicUnusual;
else if(_cp.InGroup(CS_GRP_RET))
else if(_cp.IsRet())
_mnemonicType = TokenType::MnemonicRet;
else
{
switch(id)
{
case X86_INS_PUSH:
case X86_INS_PUSHF:
case X86_INS_PUSHFD:
case X86_INS_PUSHFQ:
case X86_INS_PUSHAL:
case X86_INS_PUSHAW:
case X86_INS_POP:
case X86_INS_POPF:
case X86_INS_POPFD:
case X86_INS_POPFQ:
case X86_INS_POPAL:
case X86_INS_POPAW:
_mnemonicType = TokenType::MnemonicPushPop;
break;
default:
break;
}
}
else if(_cp.IsPushPop())
_mnemonicType = TokenType::MnemonicPushPop;
tokenizeMnemonic(_mnemonicType, mnemonic);
@ -459,57 +437,65 @@ bool CapstoneTokenizer::tokenizeMnemonic(TokenType type, const QString & mnemoni
return true;
}
bool CapstoneTokenizer::tokenizeOperand(const cs_x86_op & op)
bool CapstoneTokenizer::tokenizeOperand(const ZydisDecodedOperand & op)
{
switch(op.type)
{
case X86_OP_REG:
case ZYDIS_OPERAND_TYPE_REGISTER:
return tokenizeRegOperand(op);
case X86_OP_IMM:
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
return tokenizeImmOperand(op);
case X86_OP_MEM:
case ZYDIS_OPERAND_TYPE_MEMORY:
return tokenizeMemOperand(op);
case X86_OP_INVALID:
case ZYDIS_OPERAND_TYPE_UNUSED:
return tokenizeInvalidOperand(op);
default:
return false;
}
}
bool CapstoneTokenizer::tokenizeRegOperand(const cs_x86_op & op)
bool CapstoneTokenizer::tokenizeRegOperand(const ZydisDecodedOperand & op)
{
auto registerType = TokenType::GeneralRegister;
auto reg = op.reg;
if(reg >= X86_REG_FP0 && reg <= X86_REG_FP7)
registerType = TokenType::FpuRegister;
else if(reg >= X86_REG_ST0 && reg <= X86_REG_ST7)
registerType = TokenType::FpuRegister;
else if(reg >= X86_REG_MM0 && reg <= X86_REG_MM7)
registerType = TokenType::MmxRegister;
else if(reg >= X86_REG_XMM0 && reg <= X86_REG_XMM31)
registerType = TokenType::XmmRegister;
else if(reg >= X86_REG_YMM0 && reg <= X86_REG_YMM31)
registerType = TokenType::YmmRegister;
else if(reg >= X86_REG_ZMM0 && reg <= X86_REG_ZMM31)
registerType = TokenType::ZmmRegister;
else if(reg == ArchValue(X86_REG_FS, X86_REG_GS))
auto regClass = ZydisRegisterGetClass(reg);
switch(regClass)
{
case ZYDIS_REGCLASS_X87: registerType = TokenType::FpuRegister; break;
case ZYDIS_REGCLASS_MMX: registerType = TokenType::MmxRegister; break;
case ZYDIS_REGCLASS_XMM: registerType = TokenType::XmmRegister; break;
case ZYDIS_REGCLASS_YMM: registerType = TokenType::YmmRegister; break;
case ZYDIS_REGCLASS_ZMM: registerType = TokenType::ZmmRegister; break;
}
if(reg == ArchValue(ZYDIS_REGISTER_FS, ZYDIS_REGISTER_GS))
registerType = TokenType::MnemonicUnusual;
addToken(registerType, _cp.RegName(reg));
return true;
}
bool CapstoneTokenizer::tokenizeImmOperand(const cs_x86_op & op)
bool CapstoneTokenizer::tokenizeImmOperand(const ZydisDecodedOperand & op)
{
auto value = duint(op.imm) & (duint(-1) >> (op.size ? 8 * (sizeof(duint) - op.size) : 0));
auto valueType = TokenType::Value;
if(_cp.InGroup(CS_GRP_JUMP) || _cp.InGroup(CS_GRP_CALL) || _cp.IsLoop())
duint value;
TokenType valueType;
if(_cp.IsBranchType(Capstone::BT_Jmp | Capstone::BT_Call | Capstone::BT_Loop))
{
value = _cp.BranchDestination();
valueType = TokenType::Address;
}
else
{
value = duint(op.imm.value.u) & (duint(-1) >> (op.size ? (8 * sizeof(duint) - op.size) : 0));
valueType = TokenType::Value;
}
auto tokenValue = TokenValue(op.size, value);
addToken(valueType, printValue(tokenValue, true, _maxModuleLength), tokenValue);
return true;
}
bool CapstoneTokenizer::tokenizeMemOperand(const cs_x86_op & op)
bool CapstoneTokenizer::tokenizeMemOperand(const ZydisDecodedOperand & op)
{
//memory size
const char* sizeText = _cp.MemSizeName(op.size);
@ -520,37 +506,19 @@ bool CapstoneTokenizer::tokenizeMemOperand(const cs_x86_op & op)
//memory segment
const auto & mem = op.mem;
const char* segmentText = _cp.RegName(mem.segment);
if(mem.segment == X86_REG_INVALID) //segment not set
{
switch(mem.base)
{
#ifdef _WIN64
case X86_REG_RSP:
case X86_REG_RBP:
#else //x86
case X86_REG_ESP:
case X86_REG_EBP:
#endif //_WIN64
segmentText = "ss";
break;
default:
segmentText = "ds";
break;
}
}
auto segmentType = op.reg == ArchValue(X86_REG_FS, X86_REG_GS) ? TokenType::MnemonicUnusual : TokenType::MemorySegment;
addToken(segmentType, segmentText);
auto segmentType = op.reg == ArchValue(ZYDIS_REGISTER_FS, ZYDIS_REGISTER_GS)
? TokenType::MnemonicUnusual : TokenType::MemorySegment;
addToken(segmentType, _cp.RegName(mem.segment));
addToken(TokenType::Uncategorized, ":");
//memory opening bracket
auto bracketsType = TokenType::MemoryBrackets;
switch(mem.base)
{
case X86_REG_ESP:
case X86_REG_RSP:
case X86_REG_EBP:
case X86_REG_RBP:
case ZYDIS_REGISTER_ESP:
case ZYDIS_REGISTER_RSP:
case ZYDIS_REGISTER_EBP:
case ZYDIS_REGISTER_RBP:
bracketsType = TokenType::MemoryStackBrackets;
default:
break;
@ -558,9 +526,9 @@ bool CapstoneTokenizer::tokenizeMemOperand(const cs_x86_op & op)
addToken(bracketsType, "[");
//stuff inside the brackets
if(mem.base == X86_REG_RIP) //rip-relative (#replacement)
if(mem.base == ZYDIS_REGISTER_RIP) //rip-relative (#replacement)
{
duint addr = _cp.Address() + duint(mem.disp) + _cp.Size();
duint addr = _cp.Address() + duint(mem.disp.value) + _cp.Size();
TokenValue value = TokenValue(op.size, addr);
auto displacementType = DbgMemIsValidReadPtr(addr) ? TokenType::Address : TokenType::Value;
addToken(displacementType, printValue(value, false, _maxModuleLength), value);
@ -568,12 +536,12 @@ bool CapstoneTokenizer::tokenizeMemOperand(const cs_x86_op & op)
else //#base + #index * #scale + #displacement
{
bool prependPlus = false;
if(mem.base != X86_REG_INVALID) //base register
if(mem.base != ZYDIS_REGISTER_NONE) //base register
{
addToken(TokenType::MemoryBaseRegister, _cp.RegName(mem.base));
prependPlus = true;
}
if(mem.index != X86_REG_INVALID) //index register
if(mem.index != ZYDIS_REGISTER_NONE) //index register
{
if(prependPlus)
addMemoryOperator('+');
@ -585,16 +553,16 @@ bool CapstoneTokenizer::tokenizeMemOperand(const cs_x86_op & op)
}
prependPlus = true;
}
if(mem.disp)
if(mem.disp.value)
{
char operatorText = '+';
TokenValue value(op.size, duint(mem.disp));
auto displacementType = DbgMemIsValidReadPtr(duint(mem.disp)) ? TokenType::Address : TokenType::Value;
TokenValue value(op.size, duint(mem.disp.value));
auto displacementType = DbgMemIsValidReadPtr(duint(mem.disp.value)) ? TokenType::Address : TokenType::Value;
QString valueText;
if(mem.disp < 0)
if(mem.disp.value < 0)
{
operatorText = '-';
valueText = printValue(TokenValue(op.size, duint(mem.disp * -1)), false, _maxModuleLength);
valueText = printValue(TokenValue(op.size, duint(mem.disp.value * -1)), false, _maxModuleLength);
}
else
valueText = printValue(value, false, _maxModuleLength);
@ -611,7 +579,7 @@ bool CapstoneTokenizer::tokenizeMemOperand(const cs_x86_op & op)
return true;
}
bool CapstoneTokenizer::tokenizeInvalidOperand(const cs_x86_op & op)
bool CapstoneTokenizer::tokenizeInvalidOperand(const ZydisDecodedOperand & op)
{
addToken(TokenType::MnemonicUnusual, "???");
return true;

View File

@ -1,7 +1,7 @@
#ifndef _CAPSTONE_GUI_H
#define _CAPSTONE_GUI_H
#include <capstone_wrapper.h>
#include <zydis_wrapper.h>
#include "RichTextPainter.h"
#include "Configuration.h"
#include <map>
@ -187,11 +187,11 @@ private:
bool tokenizePrefix();
bool tokenizeMnemonic();
bool tokenizeMnemonic(TokenType type, const QString & mnemonic);
bool tokenizeOperand(const cs_x86_op & op);
bool tokenizeRegOperand(const cs_x86_op & op);
bool tokenizeImmOperand(const cs_x86_op & op);
bool tokenizeMemOperand(const cs_x86_op & op);
bool tokenizeInvalidOperand(const cs_x86_op & op);
bool tokenizeOperand(const ZydisDecodedOperand & op);
bool tokenizeRegOperand(const ZydisDecodedOperand & op);
bool tokenizeImmOperand(const ZydisDecodedOperand & op);
bool tokenizeMemOperand(const ZydisDecodedOperand & op);
bool tokenizeInvalidOperand(const ZydisDecodedOperand & op);
};
#endif //_CAPSTONE_GUI_H

View File

@ -1,5 +1,5 @@
#include "LocalVarsView.h"
#include "capstone_wrapper.h"
#include "zydis_wrapper.h"
#include "CPUMultiDump.h"
#include "MiscUtil.h"
#include "WordEditDialog.h"
@ -210,18 +210,22 @@ void LocalVarsView::updateSlot()
}
for(int i = 0; i < dis.OpCount(); i++)
{
if(dis[i].type != X86_OP_MEM)
if(dis[i].type != ZYDIS_OPERAND_TYPE_MEMORY)
continue;
if(dis[i].mem.base == X86_REG_INVALID) //mov eax, [10000000], global variable
if(dis[i].mem.base == ZYDIS_REGISTER_NONE) //mov eax, [10000000], global variable
continue;
if(dis[i].mem.index != X86_REG_INVALID) //mov eax, dword ptr ds:[ebp+ecx*4-10], indexed array
if(dis[i].mem.index != ZYDIS_REGISTER_NONE) //mov eax, dword ptr ds:[ebp+ecx*4-10], indexed array
continue;
const x86_reg registers[] =
const ZydisRegister registers[] =
{
#ifdef _WIN64
X86_REG_RAX, X86_REG_RBX, X86_REG_RCX, X86_REG_RDX, X86_REG_RBP, X86_REG_RSP, X86_REG_RSI, X86_REG_RDI, X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11, X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15
ZYDIS_REGISTER_RAX, ZYDIS_REGISTER_RBX, ZYDIS_REGISTER_RCX, ZYDIS_REGISTER_RDX,
ZYDIS_REGISTER_RBP, ZYDIS_REGISTER_RSP, ZYDIS_REGISTER_RSI, ZYDIS_REGISTER_RDI,
ZYDIS_REGISTER_R8, ZYDIS_REGISTER_R9, ZYDIS_REGISTER_R10, ZYDIS_REGISTER_R11,
ZYDIS_REGISTER_R12, ZYDIS_REGISTER_R13, ZYDIS_REGISTER_R14, ZYDIS_REGISTER_R15
#else //x86
X86_REG_EAX, X86_REG_EBX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBP, X86_REG_ESP, X86_REG_ESI, X86_REG_EDI
ZYDIS_REGISTER_EAX, ZYDIS_REGISTER_EBX, ZYDIS_REGISTER_ECX, ZYDIS_REGISTER_EDX,
ZYDIS_REGISTER_EBP, ZYDIS_REGISTER_ESP, ZYDIS_REGISTER_ESI, ZYDIS_REGISTER_EDI
#endif //_WIN64
};
for(char j = 0; j < ArchValue(8, 16); j++)
@ -229,7 +233,7 @@ void LocalVarsView::updateSlot()
if(!baseRegisters[j]->isChecked())
continue;
if(dis[i].mem.base == registers[j])
usedOffsets[j].insert(dis[i].mem.disp);
usedOffsets[j].insert(dis[i].mem.disp.value);
}
}
address += dis.Size();

View File

@ -1,5 +1,5 @@
#include "main.h"
#include "capstone_wrapper.h"
#include "zydis_wrapper.h"
#include "MainWindow.h"
#include "Configuration.h"
#include <QTextCodec>

View File

@ -67,7 +67,8 @@ INCLUDEPATH += \
Src/Utils \
Src/ThirdPartyLibs/snowman \
Src/ThirdPartyLibs/ldconvert \
../capstone_wrapper
../capstone_wrapper \
../zydis_wrapper
# Resources, sources, headers, and forms
RESOURCES += \
@ -347,15 +348,15 @@ LIBS += -luser32 -ladvapi32 -lwinmm -lshell32
!contains(QMAKE_HOST.arch, x86_64) {
# Windows x86 (32bit) specific build
LIBS += -L"$$PWD/../capstone_wrapper/capstone" -lcapstone_x86
LIBS += -L"$$PWD/../capstone_wrapper/bin/x32$${DIR_SUFFIX}" -lcapstone_wrapper
LIBS += -L"$$PWD/../zydis_wrapper/Zydis" -lZydis_x86
LIBS += -L"$$PWD/../zydis_wrapper/bin/x32$${DIR_SUFFIX}" -lzydis_wrapper
LIBS += -L"$$PWD/Src/ThirdPartyLibs/snowman" -lsnowman_x86
LIBS += -L"$$PWD/Src/ThirdPartyLibs/ldconvert" -lldconvert_x86
LIBS += -L"$${X64_BIN_DIR}" -lx32bridge
} else {
# Windows x64 (64bit) specific build
LIBS += -L"$$PWD/../capstone_wrapper/capstone" -lcapstone_x64
LIBS += -L"$$PWD/../capstone_wrapper/bin/x64$${DIR_SUFFIX}" -lcapstone_wrapper
LIBS += -L"$$PWD/../zydis_wrapper/Zydis" -lZydis_x64
LIBS += -L"$$PWD/../zydis_wrapper/bin/x64$${DIR_SUFFIX}" -lzydis_wrapper
LIBS += -L"$$PWD/Src/ThirdPartyLibs/snowman" -lsnowman_x64
LIBS += -L"$$PWD/Src/ThirdPartyLibs/ldconvert" -lldconvert_x64
LIBS += -L"$${X64_BIN_DIR}" -lx64bridge

1
src/zydis_wrapper Submodule

@ -0,0 +1 @@
Subproject commit 093fbde4acbe897ecd080ed157b3d4bfb95323f3