1
0
Fork 0

Data Instruction support (#758)

* Added data instruction support

* Fixed project file

* Add advanced analysis

* Add assembler, fixed various bugs

* Fixed various bugs, better float analysis

* Add project file

* Fixed follow menu display

* Added support for temp code list

* Fixed size for invalid instructions
This commit is contained in:
Yun Wei 2016-06-22 08:45:34 -04:00 committed by Duncan Ogilvie
parent b3d71c2265
commit 899a1c235c
40 changed files with 2113 additions and 40 deletions

View File

@ -16,6 +16,7 @@ DBGISDEBUGGING _dbg_isdebugging;
DBGISJUMPGOINGTOEXECUTE _dbg_isjumpgoingtoexecute;
DBGADDRINFOGET _dbg_addrinfoget;
DBGADDRINFOSET _dbg_addrinfoset;
DBGENCODETYPESET _dbg_encodetypeset;
DBGBPGETTYPEAT _dbg_bpgettypeat;
DBGGETREGDUMP _dbg_getregdump;
DBGVALTOSTRING _dbg_valtostring;

View File

@ -27,6 +27,7 @@ typedef bool (*DBGISDEBUGGING)();
typedef bool (*DBGISJUMPGOINGTOEXECUTE)(duint addr);
typedef bool (*DBGADDRINFOGET)(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo);
typedef bool (*DBGADDRINFOSET)(duint addr, ADDRINFO* addrinfo);
typedef bool(*DBGENCODETYPESET)(duint addr, duint size, ENCODETYPE type);
typedef BPXTYPE(*DBGBPGETTYPEAT)(duint addr);
typedef bool (*DBGGETREGDUMP)(REGDUMP* regdump);
typedef bool (*DBGVALTOSTRING)(const char* string, duint value);
@ -49,6 +50,7 @@ extern DBGISDEBUGGING _dbg_isdebugging;
extern DBGISJUMPGOINGTOEXECUTE _dbg_isjumpgoingtoexecute;
extern DBGADDRINFOGET _dbg_addrinfoget;
extern DBGADDRINFOSET _dbg_addrinfoset;
extern DBGENCODETYPESET _dbg_encodetypeset;
extern DBGBPGETTYPEAT _dbg_bpgettypeat;
extern DBGGETREGDUMP _dbg_getregdump;
extern DBGVALTOSTRING _dbg_valtostring;

View File

@ -80,6 +80,7 @@ BRIDGE_IMPEXP const char* BridgeInit()
LOADEXPORT(_dbg_isjumpgoingtoexecute);
LOADEXPORT(_dbg_addrinfoget);
LOADEXPORT(_dbg_addrinfoset);
LOADEXPORT(_dbg_encodetypeset);
LOADEXPORT(_dbg_bpgettypeat);
LOADEXPORT(_dbg_getregdump);
LOADEXPORT(_dbg_valtostring);
@ -752,7 +753,7 @@ BRIDGE_IMPEXP XREFTYPE DbgGetXrefTypeAt(duint addr)
return (XREFTYPE)_dbg_sendmessage(DBG_GET_XREF_TYPE_AT, (void*)addr, 0);
}
BRIDGE_IMPEXP bool DbgXrefAdd(duint addr, duint from, bool iscall)
BRIDGE_IMPEXP bool DbgXrefAdd(duint addr, duint from)
{
if(!_dbg_sendmessage(DBG_XREF_ADD, (void*)addr, (void*)from))
return false;
@ -882,6 +883,41 @@ BRIDGE_IMPEXP ARGTYPE DbgGetArgTypeAt(duint addr)
return ARG_NONE;
}
BRIDGE_IMPEXP void* DbgGetEncodeTypeBuffer(duint addr)
{
return (void*)_dbg_sendmessage(DBG_GET_ENCODE_TYPE_BUFFER, (void*)addr, nullptr);
}
BRIDGE_IMPEXP void DbgReleaseEncodeTypeBuffer(void* buffer)
{
_dbg_sendmessage(DBG_RELEASE_ENCODE_TYPE_BUFFER, buffer, nullptr);
}
BRIDGE_IMPEXP ENCODETYPE DbgGetEncodeTypeAt(duint addr, duint size)
{
return (ENCODETYPE)_dbg_sendmessage(DBG_ENCODE_TYPE_GET, (void*)addr, (void*)size);
}
BRIDGE_IMPEXP duint DbgGetEncodeSizeAt(duint addr, duint codesize)
{
return _dbg_sendmessage(DBG_ENCODE_SIZE_GET, (void*)addr, (void*)codesize);
}
BRIDGE_IMPEXP bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type)
{
return _dbg_encodetypeset(addr, size, type);
}
BRIDGE_IMPEXP void DbgDelEncodeTypeRange(duint start, duint end)
{
_dbg_sendmessage(DBG_DELETE_ENCODE_TYPE_RANGE, (void*)start, (void*)end);
}
BRIDGE_IMPEXP void DbgDelEncodeTypeSegment(duint start)
{
_dbg_sendmessage(DBG_DELETE_ENCODE_TYPE_SEG, (void*)start, 0);
}
BRIDGE_IMPEXP void GuiDisasmAt(duint addr, duint cip)
{
_gui_sendmessage(GUI_DISASSEMBLE_AT, (void*)addr, (void*)cip);

View File

@ -202,6 +202,12 @@ typedef enum
DBG_XREF_ADD, // param1=duint addr, param2=duint from
DBG_XREF_DEL_ALL, // param1=duint addr, param2=unused
DBG_XREF_GET, // param1=duint addr, param2=XREF_INFO* info
DBG_GET_ENCODE_TYPE_BUFFER, // param1=duint addr, param2=unused
DBG_ENCODE_TYPE_GET, // param1=duint addr, param2=duint size
DBG_DELETE_ENCODE_TYPE_RANGE, // param1=duint start, param2=duint end
DBG_ENCODE_SIZE_GET, // param1=duint addr, param2=duint codesize
DBG_DELETE_ENCODE_TYPE_SEG, // param1=duint addr, param2=unused
DBG_RELEASE_ENCODE_TYPE_BUFFER, // param1=void* buffer, param2=unused
} DBGMSG;
typedef enum
@ -307,6 +313,32 @@ typedef enum
size_qword = 8
} MEMORY_SIZE;
typedef enum
{
enc_unknown, //must be 0
enc_byte, //1 byte
enc_word, //2 bytes
enc_dword, //4 bytes
enc_fword, //6 bytes
enc_qword, //8 bytes
enc_tbyte, //10 bytes
enc_oword, //16 bytes
enc_mmword, //8 bytes
enc_xmmword, //16 bytes
enc_ymmword, //32 bytes
enc_zmmword, //64 bytes avx512 not supported
enc_real4, //4 byte float
enc_real8, //8 byte double
enc_real10, //10 byte decimal
enc_ascii, //ascii sequence
enc_unicode, //unicode sequence
enc_code, //start of code
enc_junk, //junk code
enc_middle //middle of data
} ENCODETYPE;
//Debugger typedefs
typedef MEMORY_SIZE VALUE_SIZE;
typedef struct SYMBOLINFO_ SYMBOLINFO;
@ -736,7 +768,7 @@ BRIDGE_IMPEXP bool DbgLoopGet(int depth, duint addr, duint* start, duint* end);
BRIDGE_IMPEXP bool DbgLoopOverlaps(int depth, duint start, duint end);
BRIDGE_IMPEXP bool DbgLoopAdd(duint start, duint end);
BRIDGE_IMPEXP bool DbgLoopDel(int depth, duint addr);
BRIDGE_IMPEXP bool DbgXrefAdd(duint addr, duint from, bool iscall);
BRIDGE_IMPEXP bool DbgXrefAdd(duint addr, duint from);
BRIDGE_IMPEXP bool DbgXrefDelAll(duint addr);
BRIDGE_IMPEXP bool DbgXrefGet(duint addr, XREF_INFO* info);
BRIDGE_IMPEXP size_t DbgGetXrefCountAt(duint addr);
@ -758,6 +790,13 @@ BRIDGE_IMPEXP bool DbgWinEventGlobal(MSG* message);
BRIDGE_IMPEXP bool DbgIsRunning();
BRIDGE_IMPEXP duint DbgGetTimeWastedCounter();
BRIDGE_IMPEXP ARGTYPE DbgGetArgTypeAt(duint addr);
BRIDGE_IMPEXP void* DbgGetEncodeTypeBuffer(duint addr);
BRIDGE_IMPEXP void DbgReleaseEncodeTypeBuffer(void* buffer);
BRIDGE_IMPEXP ENCODETYPE DbgGetEncodeTypeAt(duint addr, duint size);
BRIDGE_IMPEXP duint DbgGetEncodeSizeAt(duint addr, duint codesize);
BRIDGE_IMPEXP bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type);
BRIDGE_IMPEXP void DbgDelEncodeTypeRange(duint start, duint end);
BRIDGE_IMPEXP void DbgDelEncodeTypeSegment(duint start);
//Gui defines
#define GUI_PLUGIN_MENU 0

View File

@ -30,6 +30,7 @@
#include "threading.h"
#include "stringformat.h"
#include "xrefs.h"
#include "encodemap.h"
static bool bOnlyCipAutoComments = false;
@ -335,6 +336,11 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo)
return retval;
}
extern "C" DLL_EXPORT bool _dbg_encodetypeset(duint addr, duint size, ENCODETYPE type)
{
return EncodeMapSetType(addr, size, type);
}
extern "C" DLL_EXPORT PROCESS_INFORMATION* _dbg_getProcessInformation()
{
return fdProcessInfo;
@ -691,6 +697,7 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
case DBG_GET_THREAD_LIST:
case DBG_WIN_EVENT:
case DBG_WIN_EVENT_GLOBAL:
case DBG_RELEASE_ENCODE_TYPE_BUFFER:
break;
//the rest is unsafe -> throw an exception when people try to call them
default:
@ -1049,6 +1056,42 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
}
break;
case DBG_GET_ENCODE_TYPE_BUFFER:
{
return (duint)EncodeMapGetBuffer((duint)param1);
}
break;
case DBG_ENCODE_TYPE_GET:
{
return EncodeMapGetType((duint)param1, (duint)param2);
}
break;
case DBG_ENCODE_SIZE_GET:
{
return EncodeMapGetSize((duint)param1, (duint)param2);
}
break;
case DBG_DELETE_ENCODE_TYPE_RANGE:
{
EncodeMapDelRange((duint)param1, (duint)param2);
}
break;
case DBG_DELETE_ENCODE_TYPE_SEG:
{
EncodeMapDelSegment((duint)param1);
}
break;
case DBG_RELEASE_ENCODE_TYPE_BUFFER:
{
EncodeMapReleaseBuffer(param1);
}
break;
case DBG_GET_STRING_AT:
{
auto addr = duint(param1);

View File

@ -18,6 +18,7 @@ DLL_EXPORT bool _dbg_isdebugging();
DLL_EXPORT bool _dbg_isjumpgoingtoexecute(duint addr);
DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo);
DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo);
DLL_EXPORT bool _dbg_encodetypeset(duint addr, duint size, ENCODETYPE type);
DLL_EXPORT int _dbg_bpgettypeat(duint addr);
DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump);
DLL_EXPORT bool _dbg_valtostring(const char* string, duint value);

View File

@ -0,0 +1,373 @@
#include "advancedanalysis.h"
#include <queue>
#include "console.h"
#include "filehelper.h"
#include "function.h"
#include "xrefs.h"
#include "encodemap.h"
AdvancedAnalysis::AdvancedAnalysis(duint base, duint size, bool dump)
: Analysis(base, size),
mDump(dump)
{
mEncMap = new byte[size];
memset(mEncMap, 0, size);
}
void AdvancedAnalysis::Analyse()
{
linearXrefPass();
findEntryPoints();
analyzeCandidateFunctions(true);
findFuzzyEntryPoints();
analyzeCandidateFunctions(true);
findInvalidXrefs();
writeDataXrefs();
}
void AdvancedAnalysis::SetMarkers()
{
if(mDump)
for(const auto & function : mFunctions)
FileHelper::WriteAllText(StringUtils::sprintf("cfgraph_" fhex ".dot", function.entryPoint), function.ToDot());
byte* buffer = (byte*)EncodeMapGetBuffer(mBase, true);
memcpy(buffer, mEncMap, mSize);
EncodeMapReleaseBuffer(buffer);
XrefDelRange(mBase, mBase + mSize - 1);
for(const auto & vec : mXrefs)
{
for(const auto & xref : vec.second)
{
if(xref.valid)
XrefAdd(xref.addr, xref.from);
}
}
FunctionClear();
for(const auto & function : mFunctions)
{
duint start = ~0;
duint end = 0;
duint icount = 0;
for(const auto & node : function.nodes)
{
icount += node.second.icount;
start = min(node.second.start, start);
end = max(node.second.end, end);
}
if(!FunctionAdd(start, end, false, icount))
{
FunctionDelete(start);
FunctionDelete(end);
FunctionAdd(start, end, false, icount);
}
}
GuiUpdateAllViews();
}
void AdvancedAnalysis::analyzeFunction(duint entryPoint, bool writedata)
{
//BFS through the disassembly starting at entryPoint
CFGraph graph(entryPoint);
UintSet visited;
std::queue<duint> queue;
mEntryPoints.insert(entryPoint);
queue.push(graph.entryPoint);
while(!queue.empty())
{
auto start = queue.front();
queue.pop();
if(visited.count(start) || !inRange(start)) //already visited or out of range
continue;
visited.insert(start);
CFNode node(graph.entryPoint, start, start);
while(true)
{
node.icount++;
if(!mCp.Disassemble(node.end, translateAddr(node.end)))
{
if(writedata)
mEncMap[node.end - mBase] = (byte)enc_byte;
node.end++;
continue;
}
if(writedata)
{
mEncMap[node.end - mBase] = (byte)enc_code;
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
{
//set the branch destinations
node.brtrue = mCp.BranchDestination();
if(mCp.GetId() != X86_INS_JMP) //unconditional jumps dont have a brfalse
node.brfalse = node.end + mCp.Size();
//add node to the function graph
graph.AddNode(node);
//enqueue branch destinations
if(node.brtrue)
queue.push(node.brtrue);
if(node.brfalse)
queue.push(node.brfalse);
break;
}
if(mCp.InGroup(CS_GRP_CALL)) //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
{
node.terminal = true;
graph.AddNode(node);
break;
}
node.end += mCp.Size();
}
}
mFunctions.push_back(graph);
}
void AdvancedAnalysis::linearXrefPass()
{
dputs("Starting xref analysis...");
auto ticks = GetTickCount();
for(auto addr = mBase; addr < mBase + mSize;)
{
if(!mCp.Disassemble(addr, translateAddr(addr)))
{
addr++;
continue;
}
addr += mCp.Size();
XREF xref;
xref.valid = true;
xref.addr = 0;
xref.from = mCp.Address();
for(auto i = 0; i < mCp.OpCount(); i++)
{
duint dest = mCp.ResolveOpValue(i, [](x86_reg)->size_t
{
return 0;
});
if(inRange(dest))
{
xref.addr = dest;
break;
}
}
if(xref.addr)
{
if(mCp.InGroup(CS_GRP_CALL))
xref.type = XREF_CALL;
else if(mCp.InGroup(CS_GRP_JUMP))
xref.type = XREF_JMP;
else
xref.type = XREF_DATA;
auto found = mXrefs.find(xref.addr);
if(found == mXrefs.end())
{
std::vector<XREF> vec;
vec.push_back(xref);
mXrefs[xref.addr] = vec;
}
else
{
found->second.push_back(xref);
}
}
}
dprintf("%u xrefs found in %ums!\n", mXrefs.size(), GetTickCount() - ticks);
}
void AdvancedAnalysis::findInvalidXrefs()
{
for(auto & vec : mXrefs)
{
duint jmps = 0, calls = 0;
duint addr = vec.first;
byte desttype = mEncMap[vec.first - mBase];
for(auto & xref : vec.second)
{
byte type = mEncMap[xref.from - mBase];
if(desttype == enc_code && type != enc_unknown && type != enc_code)
xref.valid = false;
else if(desttype == enc_middle)
xref.valid = false;
}
}
}
bool isFloatInstruction(x86_insn 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:
return true;
default:
return false;
}
}
void AdvancedAnalysis::writeDataXrefs()
{
for(auto & vec : mXrefs)
{
for(auto & xref : vec.second)
{
if(xref.type == XREF_DATA && xref.valid)
{
if(!mCp.Disassemble(xref.from, translateAddr(xref.from)))
{
xref.valid = false;
continue;
}
auto opcode = mCp.GetId();
bool isfloat = isFloatInstruction(opcode);
for(auto i = 0; i < mCp.OpCount(); i++)
{
auto & op = mCp[i];
ENCODETYPE type = enc_unknown;
//Todo: Analyze op type and set correct type
if(op.type == X86_OP_MEM)
{
duint datasize = op.size;
duint size = datasize;
duint offset = xref.addr - mBase;
switch(op.size)
{
case 1:
type = enc_byte;
break;
case 2:
type = enc_word;
break;
case 4:
type = isfloat ? enc_real4 : enc_dword;
break;
case 6:
type = enc_fword;
break;
case 8:
type = isfloat ? enc_real8 : enc_qword;
break;
case 10:
type = isfloat ? enc_real10 : enc_tbyte;
break;
case 16:
type = enc_oword;
break;
case 32:
type = enc_ymmword;
break;
//case 64: type = enc_zmmword; break;
}
if(datasize == 1)
{
memset(mEncMap + offset, (byte)type, size);
}
else
{
memset(mEncMap + offset, (byte)enc_middle, size);
for(duint i = offset; i < offset + size; i += datasize)
mEncMap[i] = (byte)type;
}
}
}
}
}
}
}
void AdvancedAnalysis::findFuzzyEntryPoints()
{
for(const auto & entryPoint : mFuzzyEPs)
{
mCandidateEPs.insert(entryPoint);
}
}
void AdvancedAnalysis::findEntryPoints()
{
duint modbase = ModBaseFromAddr(mBase);
if(modbase)
{
apienumexports(modbase, [&](duint Base, const char* Module, const char* Name, duint Address)
{
// If within limits...
if(inRange(Address))
{
mCandidateEPs.insert(Address);
}
});
}
for(const auto & vec : mXrefs)
{
duint jmps = 0, calls = 0;
duint addr = vec.first;
for(const auto & xref : vec.second)
{
if(xref.type == XREF_CALL)
calls++;
else if(xref.type == XREF_JMP)
jmps++;
}
if(calls >= 1 && jmps + calls > 1)
mCandidateEPs.insert(addr);
else if(calls >= 1)
mFuzzyEPs.insert(addr);
}
}
void AdvancedAnalysis::analyzeCandidateFunctions(bool writedata)
{
std::unordered_set<duint> pendingEPs;
while(true)
{
pendingEPs.clear();
if(mCandidateEPs.size() == 0)
return;
for(const auto & entryPoint : mCandidateEPs)
{
pendingEPs.insert(entryPoint);
}
mCandidateEPs.clear();
for(const auto & entryPoint : pendingEPs)
{
if(mEntryPoints.find(entryPoint) == mEntryPoints.end())
{
analyzeFunction(entryPoint, true);
}
}
}
}

152
src/dbg/advancedanalysis.h Normal file
View File

@ -0,0 +1,152 @@
#pragma once
#include "analysis.h"
class AdvancedAnalysis : public Analysis
{
public:
explicit AdvancedAnalysis(duint base, duint size, bool dump = false);
void Analyse() override;
void SetMarkers() override;
using UintSet = std::unordered_set<duint>;
template<class T>
using UintMap = std::unordered_map<duint, T>;
struct CFNode
{
duint parentGraph; //function of which this node is a part
duint start; //start of the block
duint end; //end of the block (inclusive)
duint brtrue; //destination if condition is true
duint brfalse; //destination if condition is false
duint icount; //number of instructions in node
bool terminal; //node is a RET
explicit CFNode(duint parentGraph, duint start, duint end)
: parentGraph(parentGraph),
start(start),
end(end),
brtrue(0),
brfalse(0),
icount(0),
terminal(false)
{
}
explicit CFNode()
: CFNode(0, 0, 0)
{
}
String ToString() const
{
return StringUtils::sprintf("start: " fhex "\nend: " fhex "\nfunction: " fhex, start, end, parentGraph);
}
};
struct CFGraph
{
duint entryPoint; //graph entry point
UintMap<CFNode> nodes; //CFNode.start -> CFNode
UintMap<UintSet> parents; //CFNode.start -> parents
explicit CFGraph(duint entryPoint)
: entryPoint(entryPoint)
{
}
void AddNode(const CFNode & node)
{
nodes[node.start] = node;
AddParent(node.start, node.brtrue);
AddParent(node.start, node.brfalse);
}
void AddParent(duint child, duint parent)
{
if(!child || !parent)
return;
auto found = parents.find(child);
if(found == parents.end())
{
UintSet p;
p.insert(parent);
parents[child] = p;
}
else
found->second.insert(parent);
}
const char* GetNodeColor(const CFNode & node) const
{
if(node.terminal)
return "firebrick";
if(node.start == entryPoint)
return "forestgreen";
return "lightblue";
}
String ToDot() const
{
String result = "digraph CFGraph {\n";
for(const auto & node : nodes)
result += StringUtils::sprintf(" n" fhex "[label=\"%s\" style=filled fillcolor=%s shape=box]\n",
node.second.start,
node.second.ToString().c_str(),
GetNodeColor(node.second));
result += "\n";
for(const auto & node : nodes)
{
if(node.second.brtrue)
result += StringUtils::sprintf(" n" fhex "-> n" fhex " [color=green]\n",
node.second.start,
node.second.brtrue);
if(node.second.brfalse)
result += StringUtils::sprintf(" n" fhex "-> n" fhex " [color=red]\n",
node.second.start,
node.second.brfalse);
}
result += "\n";
for(const auto & parent : parents)
{
for(const auto & node : parent.second)
result += StringUtils::sprintf(" n" fhex "-> n" fhex " [style=dotted color=grey]\n",
node,
parent.first);
}
result += "}";
return result;
}
};
protected:
struct XREF
{
duint addr;
duint from;
XREFTYPE type;
bool valid;
};
std::unordered_set<duint> mEntryPoints;
std::unordered_set<duint> mCandidateEPs;
std::unordered_set<duint> mFuzzyEPs;
std::vector<CFGraph> mFunctions;
std::unordered_map<duint, std::vector<XREF>> mXrefs;
byte* mEncMap;
private:
duint mMaxDepth;
bool mDump;
void linearXrefPass();
void findInvalidXrefs();
void writeDataXrefs();
void findFuzzyEntryPoints();
void findEntryPoints();
void analyzeCandidateFunctions(bool writedata);
void analyzeFunction(duint entryPoint, bool writedata);
};

View File

@ -13,6 +13,7 @@
#include "disasm_helper.h"
#include "memory.h"
#include "keystone\keystone.h"
#include "datainst_helper.h"
AssemblerEngine assemblerEngine = AssemblerEngine::XEDParse;
@ -110,8 +111,12 @@ static bool cbUnknown(const char* text, ULONGLONG* value)
return true;
}
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
bool assemble(duint addr, unsigned char* dest, int destsize, int* size, const char* instruction, char* error)
{
if(isdatainstruction(instruction))
{
return tryassembledata(addr, dest, destsize, size, instruction, error);
}
if(strlen(instruction) >= XEDPARSE_MAXBUFSIZE)
return false;
XEDPARSE parse;
@ -142,6 +147,11 @@ bool assemble(duint addr, unsigned char* dest, int* size, const char* instructio
return true;
}
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
{
return assemble(addr, dest, 16, size, instruction, error);
}
static bool isInstructionPointingToExMemory(duint addr, const unsigned char* dest)
{
BASIC_INSTRUCTION_INFO basicinfo;
@ -180,9 +190,19 @@ static bool isInstructionPointingToExMemory(duint addr, const unsigned char* des
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop)
{
int destSize;
unsigned char dest[16];
if(!assemble(addr, dest, &destSize, instruction, error))
return false;
Memory<unsigned char*> dest(16 * sizeof(unsigned char), "AssembleBuffer");
unsigned char* newbuffer = nullptr;
if(!assemble(addr, dest(), 16, &destSize, instruction, error))
{
if(destSize > 16)
{
dest.realloc(destSize);
if(!assemble(addr, dest(), destSize, &destSize, instruction, error))
{
return false;
}
}
}
//calculate the number of NOPs to insert
int origLen = disasmgetsize(addr);
while(origLen < destSize)
@ -195,10 +215,10 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
*size = destSize;
// Check if the instruction doesn't set IP to non-executable memory
if(!isInstructionPointingToExMemory(addr, dest))
if(!isInstructionPointingToExMemory(addr, dest()))
GuiDisplayWarning("Non-executable memory region", "Assembled branch does not point to an executable memory region!");
bool ret = MemPatch(addr, dest, destSize);
bool ret = MemPatch(addr, dest(), destSize);
if(ret)
{

View File

@ -97,7 +97,8 @@ bool BpNew(duint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE
bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
{
ASSERT_DEBUGGING("Export call");
if(!DbgIsDebugging())
return false;
SHARED_ACQUIRE(LockBreakpoints);
// Name is optional

View File

@ -19,6 +19,7 @@
#include "filehelper.h"
#include "xrefs.h"
#include "TraceRecord.h"
#include "encodemap.h"
/**
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
@ -52,6 +53,7 @@ void DbSave(DbLoadSaveType saveType)
FunctionCacheSave(root);
LoopCacheSave(root);
XrefCacheSave(root);
EncodeMapCacheSave(root);
TraceRecord.saveToDb(root);
BpCacheSave(root);
@ -139,8 +141,9 @@ void DbLoad(DbLoadSaveType loadType)
if(lzmaStatus != LZ4_INVALID_ARCHIVE && useCompression)
LZ4_compress_fileW(databasePathW.c_str(), databasePathW.c_str());
// Deserialize JSON and validate
JSON root = json_loads(databaseText.c_str(), 0, 0);
JSON root = json_loads(databaseText.c_str(), JSON_ALLOW_NUL, 0);
if(!root)
{
@ -163,6 +166,7 @@ void DbLoad(DbLoadSaveType loadType)
FunctionCacheLoad(root);
LoopCacheLoad(root);
XrefCacheLoad(root);
EncodeMapCacheLoad(root);
TraceRecord.loadFromDb(root);
BpCacheLoad(root);
@ -188,6 +192,7 @@ void DbClose()
FunctionClear();
LoopClear();
XrefClear();
EncodeMapClear();
BpClear();
PatchClear();
GuiSetDebuggeeNotes("");

309
src/dbg/datainst_helper.cpp Normal file
View File

@ -0,0 +1,309 @@
#include "datainst_helper.h"
#include "encodemap.h"
#include "stringutils.h"
#include <capstone_wrapper.h>
std::unordered_map<ENCODETYPE, std::string> disasmMap;
std::unordered_map<std::string, ENCODETYPE> assembleMap;
void initDataInstMap()
{
disasmMap.clear();
assembleMap.clear();
#define INSTRUCTION_MAP(type, desc) disasmMap[type] = desc; \
assembleMap[desc] = type;
INSTRUCTION_MAP(enc_byte, "byte")
INSTRUCTION_MAP(enc_word, "word")
INSTRUCTION_MAP(enc_dword, "dword")
INSTRUCTION_MAP(enc_fword, "fword")
INSTRUCTION_MAP(enc_qword, "qword")
INSTRUCTION_MAP(enc_tbyte, "tbyte")
INSTRUCTION_MAP(enc_oword, "oword")
INSTRUCTION_MAP(enc_real4, "real4")
INSTRUCTION_MAP(enc_real8, "real8")
INSTRUCTION_MAP(enc_real10, "real10")
INSTRUCTION_MAP(enc_mmword, "mmword")
INSTRUCTION_MAP(enc_xmmword, "xmmword")
INSTRUCTION_MAP(enc_ymmword, "ymmword")
INSTRUCTION_MAP(enc_ascii, "ascii")
INSTRUCTION_MAP(enc_unicode, "unicode")
#undef INSTRUCTION_MAP
#define INSTRUCTION_ASSEMBLE_MAP(type, desc) assembleMap[desc] = type;
INSTRUCTION_ASSEMBLE_MAP(enc_byte, "db")
INSTRUCTION_ASSEMBLE_MAP(enc_word, "dw")
INSTRUCTION_ASSEMBLE_MAP(enc_dword, "dd")
INSTRUCTION_ASSEMBLE_MAP(enc_qword, "dq")
#undef INSTRUCTION_ASSEMBLE_MAP
}
String GetDataTypeString(void* buffer, duint size, ENCODETYPE type)
{
switch(type)
{
case enc_byte:
return StringUtils::ToIntegralString<unsigned char>(buffer);
case enc_word:
return StringUtils::ToIntegralString<unsigned short>(buffer);
case enc_dword:
return StringUtils::ToIntegralString<unsigned int>(buffer);
case enc_fword:
return StringUtils::ToHex((char*)buffer, 6, true);
case enc_qword:
return StringUtils::ToIntegralString<unsigned long long int>(buffer);
case enc_tbyte:
return StringUtils::ToHex((char*)buffer, 10, true);
case enc_oword:
return StringUtils::ToHex((char*)buffer, 16, true);
case enc_mmword:
case enc_xmmword:
case enc_ymmword:
return StringUtils::ToHex((char*)buffer, size, false);
case enc_real4:
return StringUtils::ToFloatingString<float>(buffer);
case enc_real8:
return StringUtils::ToFloatingString<double>(buffer);
case enc_real10:
return StringUtils::ToHex((char*)buffer, 10, true);
//return ToLongDoubleString(buffer);
case enc_ascii:
return String((const char*)buffer, size);
case enc_unicode:
return StringUtils::Utf16ToUtf8(WString((const wchar_t*)buffer, size / sizeof(wchar_t)));
default:
return StringUtils::ToIntegralString<unsigned char>(buffer);
}
}
String GetDataInstMnemonic(ENCODETYPE type)
{
if(disasmMap.find(type) == disasmMap.end())
type == enc_byte;
if(disasmMap.find(type) == disasmMap.end())
return "???";
return disasmMap[type];
}
String GetDataInstString(void* buffer, duint size, ENCODETYPE type)
{
return GetDataInstMnemonic(type) + " " + GetDataTypeString(buffer, size, type);
}
duint decodesimpledata(const unsigned char* buffer, ENCODETYPE type)
{
switch(type)
{
case enc_byte:
return *((unsigned char*)buffer);
case enc_word:
return *((unsigned short*)buffer);
case enc_dword:
return *((unsigned int*)buffer);
#ifdef _WIN64
case enc_qword:
return *((unsigned long long int*)buffer);
#endif // _WIN64
}
return 0;
}
struct DataInstruction
{
ENCODETYPE type;
String oprand;
};
bool parsedatainstruction(const char* instruction, DataInstruction & di)
{
di.type = enc_unknown;
di.oprand = "";
String instStr = StringUtils::Trim(String(instruction));
size_t pos = instStr.find_first_of(" \t");
String opcode = instStr.substr(0, pos);
std::transform(opcode.begin(), opcode.end(), opcode.begin(), ::tolower);
if(assembleMap.find(opcode) == assembleMap.end())
return false;
di.type = assembleMap[opcode];
pos = instStr.find_first_not_of(" \t", pos);
if(pos == String::npos)
return false;
di.oprand = instStr.substr(pos);
}
bool isdatainstruction(const char* instruction)
{
DataInstruction di;
parsedatainstruction(instruction, di);
return di.type != enc_unknown;
}
bool tryassembledata(duint addr, unsigned char* dest, int destsize, int* size, const char* instruction, char* error)
{
DataInstruction di;
if(!parsedatainstruction(instruction, di))
{
if(di.oprand == "")
strcpy_s(error, MAX_ERROR_SIZE, "Missing oprand");
return false;
}
duint retsize = 0;
String buffer;
try
{
switch(di.type)
{
case enc_byte:
case enc_word:
case enc_dword:
case enc_fword:
case enc_qword:
case enc_tbyte:
case enc_oword:
{
retsize = GetEncodeTypeSize(di.type);
buffer = StringUtils::FromHex(di.oprand, retsize, true);
break;
}
case enc_mmword:
case enc_xmmword:
case enc_ymmword:
{
retsize = GetEncodeTypeSize(di.type);
if(retsize > destsize)
{
strcpy_s(error, MAX_ERROR_SIZE, "insufficient buffer");
if(size)
{
*size = retsize; //return correct size
return dest == nullptr;
}
return false;
}
else
{
buffer = StringUtils::FromHex(di.oprand, retsize, false);
}
break;
}
case enc_real4:
{
retsize = 4;
float f = std::stof(di.oprand);
buffer = String((char*)&f, 4);
break;
}
case enc_real8:
{
retsize = 8;
double d = std::stod(di.oprand);
buffer = String((char*)&d, 8);
break;
}
case enc_real10:
strcpy_s(error, MAX_ERROR_SIZE, "80bit extended float is not supported");
return false; //80 bit float is not supported in MSVC, need to add other library
case enc_ascii:
{
if(di.oprand.size() > destsize)
{
strcpy_s(error, MAX_ERROR_SIZE, "string too long");
if(size)
{
*size = di.oprand.size(); //return correct size
return dest == nullptr;
}
return false;
}
else
{
retsize = di.oprand.size();
buffer = di.oprand;
}
break;
}
case enc_unicode:
{
WString unicode = StringUtils::Utf8ToUtf16(di.oprand);
if(unicode.size()*sizeof(wchar_t) > destsize)
{
strcpy_s(error, MAX_ERROR_SIZE, "string too long");
if(size)
{
retsize = unicode.size() * 2; //return correct size
return dest == nullptr;
}
return false;
}
else
{
retsize = unicode.size() * 2;
buffer = String((char*)unicode.c_str(), retsize);
}
break;
}
default:
return false;
}
}
catch(const std::exception & e)
{
strcpy_s(error, MAX_ERROR_SIZE, e.what());
return false;
}
if(size)
*size = retsize;
if(dest)
memcpy_s((char*)dest, retsize, buffer.c_str(), retsize);
return true;
}
bool trydisasm(const unsigned char* buffer, duint addr, DISASM_INSTR* instr, duint codesize)
{
ENCODETYPE type = EncodeMapGetType(addr, codesize);
duint size = EncodeMapGetSize(addr, codesize);
if(type == enc_unknown || type == enc_code)
return false;
memset(instr, 0, sizeof(DISASM_INSTR));
instr->argcount = 1;
instr->type = instr_normal;
instr->arg[0].type = arg_normal;
instr->arg[0].value = decodesimpledata(buffer, type);
strcpy_s(instr->arg[0].mnemonic, GetDataTypeString((void*)buffer, size, type).c_str());
instr->instr_size = size;
String str = GetDataInstString((void*)buffer, MAX_DISASM_BUFFER, type);
strcpy_s(instr->instruction, str.c_str());
return true;
}
bool trydisasmfast(const unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* basicinfo, duint codesize)
{
ENCODETYPE type = EncodeMapGetType(addr, codesize);
duint size = EncodeMapGetSize(addr, codesize);
if(type == enc_unknown || type == enc_code)
return false;
memset(basicinfo, 0, sizeof(BASIC_INSTRUCTION_INFO));
basicinfo->type = TYPE_VALUE;
basicinfo->size = size;
String str = GetDataInstString((void*)data, MAX_DISASM_BUFFER, type);
strcpy_s(basicinfo->instruction, str.c_str());
basicinfo->value.size = VALUE_SIZE(size);
basicinfo->value.value = decodesimpledata(data, type);
return true;
}

12
src/dbg/datainst_helper.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "_global.h"
void initDataInstMap();
bool isdatainstruction(const char* instruction);
bool tryassembledata(duint addr, unsigned char* dest, int destsize, int* size, const char* instruction, char* error);
bool trydisasm(const unsigned char* buffer, duint addr, DISASM_INSTR* instr, duint codesize);
bool trydisasmfast(const unsigned char* buffer, duint addr, BASIC_INSTRUCTION_INFO* basicinfo, duint codesize);

View File

@ -6,6 +6,7 @@
#include "disasm_fast.h"
#include "memory.h"
#include "datainst_helper.h"
static MEMORY_SIZE argsize2memsize(int argsize)
{
@ -95,7 +96,10 @@ bool disasmfast(const unsigned char* data, duint addr, BASIC_INSTRUCTION_INFO* b
if(!data || !basicinfo)
return false;
Capstone cp;
if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER))
cp.Disassemble(addr, data, MAX_DISASM_BUFFER);
if(trydisasmfast(data, addr, basicinfo, cp.Success() ? cp.Size() : 1))
return true;
if(!cp.Success())
{
strcpy_s(basicinfo->instruction, "???");
basicinfo->size = 1;

View File

@ -10,7 +10,10 @@
#include "memory.h"
#include "debugger.h"
#include "value.h"
#include "encodemap.h"
#include <capstone_wrapper.h>
#include "datainst_helper.h"
duint disasmback(unsigned char* data, duint base, duint size, duint ip, int n)
{
@ -197,7 +200,10 @@ void disasmget(unsigned char* buffer, duint addr, DISASM_INSTR* instr)
}
memset(instr, 0, sizeof(DISASM_INSTR));
Capstone cp;
if(!cp.Disassemble(addr, buffer, MAX_DISASM_BUFFER))
cp.Disassemble(addr, buffer, MAX_DISASM_BUFFER);
if(trydisasm(buffer, addr, instr, cp.Success() ? cp.Size() : 1))
return;
if(!cp.Success())
{
strcpy_s(instr->instruction, "???");
instr->instr_size = 1;
@ -352,7 +358,7 @@ int disasmgetsize(duint addr, unsigned char* data)
Capstone cp;
if(!cp.Disassemble(addr, data, MAX_DISASM_BUFFER))
return 1;
return cp.Size();
return EncodeMapGetSize(addr, cp.Size());
}
int disasmgetsize(duint addr)

381
src/dbg/encodemap.cpp Normal file
View File

@ -0,0 +1,381 @@
#include "encodemap.h"
#include <unordered_map>
#include "addrinfo.h"
#include <algorithm>
#include <capstone_wrapper.h>
struct ENCODEMAP : AddrInfo
{
duint size;
byte* data;
};
std::unordered_map<duint, duint> referenceCount;
void IncreaseReferenceCount(void* buffer, bool lock = true)
{
if(lock)
{
EXCLUSIVE_ACQUIRE(LockEncodeMaps);
}
auto iter = referenceCount.find((duint)buffer);
if(iter == referenceCount.end())
referenceCount[(duint)buffer] = 1;
else
referenceCount[(duint)buffer]++;
}
duint DecreaseReferenceCount(void* buffer, bool lock = true)
{
if(lock)
{
EXCLUSIVE_ACQUIRE(LockEncodeMaps);
}
auto iter = referenceCount.find((duint)buffer);
if(iter == referenceCount.end())
return -1;
if(iter->second == 1)
{
referenceCount.erase(iter->first);
return 0;
}
else
referenceCount[iter->first]--;
return iter->second;
}
struct EncodeMapSerializer : AddrInfoSerializer<ENCODEMAP>
{
bool Save(const ENCODEMAP & value) override
{
AddrInfoSerializer::Save(value);
set("data", json_stringn((const char*)value.data, value.size));
return true;
}
bool Load(ENCODEMAP & value) override
{
if(!AddrInfoSerializer::Load(value))
return false;
auto data = get("data");
value.size = json_string_length(data);
value.data = (byte*)VirtualAlloc(NULL, value.size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(value.data == NULL) return false;
memcpy(value.data, (byte*)json_string_value(data), value.size);
IncreaseReferenceCount(value.data, false);
return true;
}
};
struct EncodeMap : AddrInfoHashMap<LockEncodeMaps, ENCODEMAP, EncodeMapSerializer>
{
const char* jsonKey() const override
{
return "encodemaps";
}
};
static EncodeMap encmaps;
bool EncodeMapGetorCreate(duint addr, ENCODEMAP & map)
{
duint base, segsize;
base = MemFindBaseAddr(addr, &segsize);
if(!base)
return false;
duint key = EncodeMap::VaKey(base);
if(!encmaps.Contains(key))
{
map.size = segsize;
map.data = (byte*)VirtualAlloc(NULL, segsize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(map.data == NULL) return false;
IncreaseReferenceCount(map.data);
encmaps.PrepareValue(map, base, false);
encmaps.Add(map);
}
else
{
if(!encmaps.Get(key, map))
return false;
}
return true;
}
void* EncodeMapGetBuffer(duint addr, bool create)
{
duint base, size;
if(!MemIsValidReadPtr(addr))
return nullptr;
base = MemFindBaseAddr(addr, &size);
ENCODEMAP map;
bool result = create ? EncodeMapGetorCreate(addr, map) : encmaps.Get(EncodeMap::VaKey(base), map);
if(result)
{
duint offset = addr - base;
if(offset >= map.size)
return nullptr;
IncreaseReferenceCount(map.data);
return map.data;
}
return nullptr;
}
void EncodeMapReleaseBuffer(void* buffer, bool lock)
{
if(DecreaseReferenceCount(buffer, lock) == 0)
VirtualFree(buffer, 0, MEM_RELEASE);
}
void EncodeMapReleaseBuffer(void* buffer)
{
EncodeMapReleaseBuffer(buffer, true);
}
bool IsRangeConflict(byte* typebuffer, duint size, duint codesize)
{
if(codesize > size)
return true;
size = min(size, codesize);
if(size <= 0)
return false;
ENCODETYPE type = (ENCODETYPE)typebuffer[0];
if(type == enc_middle)
return true;
for(int i = 1; i < size; i++)
{
if((ENCODETYPE)typebuffer[i] != enc_unknown && (ENCODETYPE)typebuffer[i] != enc_middle)
return true;
}
return false;
}
duint GetEncodeTypeSize(ENCODETYPE type)
{
switch(type)
{
case enc_byte:
return 1;
case enc_word:
return 2;
case enc_dword:
return 4;
case enc_fword:
return 6;
case enc_qword:
return 8;
case enc_tbyte:
return 10;
case enc_oword:
return 16;
case enc_mmword:
return 8;
case enc_xmmword:
return 16;
case enc_ymmword:
return 32;
case enc_real4:
return 4;
case enc_real8:
return 8;
case enc_real10:
return 10;
case enc_ascii:
return 1;
case enc_unicode:
return 2;
default:
return 1;
}
}
bool IsCodeType(ENCODETYPE type)
{
return type == enc_code || type == enc_junk;
}
ENCODETYPE EncodeMapGetType(duint addr, duint codesize)
{
duint base, size;
base = MemFindBaseAddr(addr, &size);
if(!base)
return ENCODETYPE::enc_unknown;
ENCODEMAP map;
if(encmaps.Get(EncodeMap::VaKey(base), map))
{
duint offset = addr - base;
if(offset >= map.size)
return ENCODETYPE::enc_unknown;
ENCODETYPE type = (ENCODETYPE)map.data[offset];
if((type == enc_unknown || type == enc_middle) && IsRangeConflict(map.data + offset, size - offset, codesize))
return enc_byte;
else
return type;
}
return ENCODETYPE::enc_unknown;
}
duint EncodeMapGetSize(duint addr, duint codesize)
{
duint base;
base = MemFindBaseAddr(addr, 0);
if(!base)
return codesize;
ENCODEMAP map;
if(encmaps.Get(EncodeMap::VaKey(base), map))
{
duint offset = addr - base;
if(offset >= map.size)
return 1;
ENCODETYPE type = (ENCODETYPE)map.data[offset];
duint datasize = GetEncodeTypeSize(type);
if(type == enc_unknown || type == enc_code || type == enc_junk)
{
if(IsRangeConflict(map.data + offset, map.size - offset, codesize) || codesize == 0)
return datasize;
else
return codesize;
}
else if(type == enc_ascii || type == enc_unicode)
{
duint totalsize = 0;
for(int i = offset; i < map.size; i += datasize)
{
if(map.data[i] == type)
totalsize += datasize;
else
break;
}
return totalsize;
}
else
return datasize;
}
return codesize;
}
bool EncodeMapSetType(duint addr, duint size, ENCODETYPE type)
{
duint base;
base = MemFindBaseAddr(addr, 0);
if(!base)
return false;
ENCODEMAP map;
if(!EncodeMapGetorCreate(base, map))
return false;
duint offset = addr - base;
size = min(map.size - offset, size);
duint datasize = GetEncodeTypeSize(type);
if(datasize == 1 && !IsCodeType(type))
{
memset(map.data + offset, (byte)type, size);
}
else
{
memset(map.data + offset, (byte)enc_middle, size);
if(IsCodeType(type) && size > 1)
{
Capstone cp;
unsigned char* buffer = new unsigned char[size];
if(!MemRead(addr, buffer, size))
{
delete[] buffer;
return false;
}
int buffersize = size, bufferoffset = 0, cmdsize;
for(int i = offset; i < offset + size;)
{
map.data[i] = (byte)type;
cp.Disassemble(base + i, buffer + bufferoffset, buffersize);
cmdsize = cp.Success() ? cp.Size() : 1;
i += cmdsize;
bufferoffset += cmdsize;
buffersize -= cmdsize;
}
}
else
{
for(int i = offset; i < offset + size; i += datasize)
map.data[i] = (byte)type;
}
}
for(int i = offset + size + 1; i < map.size; i++)
{
if(map.data[i] == enc_middle)
map.data[i] = (byte)enc_unknown;
else
break;
}
return true;
}
void EncodeMapDelSegment(duint Start)
{
duint base = MemFindBaseAddr(Start, 0);
if(!base)
return;
duint key = EncodeMap::VaKey(base);
ENCODEMAP map;
if(encmaps.Contains(key))
{
encmaps.Get(key, map);
EncodeMapReleaseBuffer(map.data);
}
encmaps.Delete(key);
}
void EncodeMapDelRange(duint Start, duint End)
{
EncodeMapSetType(Start, End - Start + 1, enc_unknown);
}
void EncodeMapCacheSave(JSON Root)
{
encmaps.CacheSave(Root);
}
void EncodeMapCacheLoad(JSON Root)
{
encmaps.CacheLoad(Root);
}
void EncodeMapClear()
{
EXCLUSIVE_ACQUIRE(LockEncodeMaps);
for(auto & encmap : encmaps.GetDataUnsafe())
{
EncodeMapReleaseBuffer(encmap.second.data, false);
}
EXCLUSIVE_RELEASE(LockEncodeMaps);
encmaps.Clear();
}

26
src/dbg/encodemap.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "_global.h"
void* EncodeMapGetBuffer(duint addr, bool create = false);
void EncodeMapReleaseBuffer(void* buffer);
ENCODETYPE EncodeMapGetType(duint addr, duint codesize);
duint EncodeMapGetSize(duint addr, duint codesize);
void EncodeMapDelSegment(duint addr);
void EncodeMapDelRange(duint addr, duint size);
bool EncodeMapSetType(duint addr, duint size, ENCODETYPE type);
void EncodeMapDelRange(duint Start, duint End);
void EncodeMapCacheSave(JSON Root);
void EncodeMapCacheLoad(JSON Root);
void EncodeMapClear();
duint GetEncodeTypeSize(ENCODETYPE type);

View File

@ -37,6 +37,7 @@
#include "error.h"
#include "recursiveanalysis.h"
#include "xrefsanalysis.h"
#include "advancedanalysis.h"
#include "exhandlerinfo.h"
#include "symbolinfo.h"
@ -2133,6 +2134,19 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
return STATUS_CONTINUE;
}
CMDRESULT cbInstrAnalyseadv(int argc, char* argv[])
{
SELECTIONDATA sel;
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
duint size = 0;
auto base = MemFindBaseAddr(sel.start, &size);
AdvancedAnalysis anal(base, size);
anal.Analyse();
anal.SetMarkers();
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbInstrCfanalyse(int argc, char* argv[])
{
bool exceptionDirectory = false;

View File

@ -72,6 +72,7 @@ CMDRESULT cbInstrLog(int argc, char* argv[]);
CMDRESULT cbInstrCapstone(int argc, char* argv[]);
CMDRESULT cbInstrAnalyseNukem(int argc, char* argv[]);
CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
CMDRESULT cbInstrAnalyseadv(int argc, char* argv[]);
CMDRESULT cbInstrAnalrecur(int argc, char* argv[]);
CMDRESULT cbInstrAnalxrefs(int argc, char* argv[]);
CMDRESULT cbInstrVisualize(int argc, char* argv[]);

View File

@ -147,6 +147,8 @@ void PatchDelRange(duint Start, duint End, bool Restore)
bool PatchEnum(PATCHINFO* List, size_t* Size)
{
ASSERT_DEBUGGING("Export call");
if(!DbgIsDebugging())
return false;
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockPatches);

View File

@ -1,4 +1,3 @@
#include <sstream>
#include "stringutils.h"
#include "memory.h"
#include "dynamicmem.h"
@ -58,7 +57,7 @@ String StringUtils::Escape(const String & s)
escaped += "\\\"";
break;
default:
if(!isprint(ch)) //unknown unprintable character
if(!isprint(ch)) //unknown unprintable character
{
char buf[16] = "";
sprintf_s(buf, "\\x%02X", ch);
@ -75,20 +74,20 @@ String StringUtils::Escape(const String & s)
//Trim functions taken from: http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring/16743707#16743707
const String StringUtils::WHITESPACE = " \n\r\t";
String StringUtils::Trim(const String & s)
String StringUtils::Trim(const String & s, String delim)
{
return TrimRight(TrimLeft(s));
}
String StringUtils::TrimLeft(const String & s)
String StringUtils::TrimLeft(const String & s, String delim)
{
size_t startpos = s.find_first_not_of(StringUtils::WHITESPACE);
size_t startpos = s.find_first_not_of(delim);
return (startpos == String::npos) ? "" : s.substr(startpos);
}
String StringUtils::TrimRight(const String & s)
String StringUtils::TrimRight(const String & s, String delim)
{
size_t endpos = s.find_last_not_of(StringUtils::WHITESPACE);
size_t endpos = s.find_last_not_of(delim);
return (endpos == String::npos) ? "" : s.substr(0, endpos + 1);
}
@ -202,3 +201,68 @@ bool StringUtils::StartsWith(const String & h, const String & n)
{
return strstr(h.c_str(), n.c_str()) == h.c_str();
}
int char2int(char input)
{
if(input >= '0' && input <= '9')
return input - '0';
if(input >= 'A' && input <= 'F')
return input - 'A' + 10;
if(input >= 'a' && input <= 'f')
return input - 'a' + 10;
throw std::invalid_argument("invalid character");
}
String StringUtils::FromHex(const String & s, size_t size, bool reverse)
{
std::stringstream ss;
bool high = false;
if(s.length() > size * 2)
throw std::invalid_argument("string too long");
char ch = 0;
bool odd = s.size() % 2 == 1;
int cursize = 0;
for(int i = s.size() - 1; i >= 0; i--)
{
ch |= char2int(s[i]) << (high ? 4 : 0);
if(high || odd && i == 0)
{
ss.put(ch);
cursize++;
ch = 0;
}
high = !high;
}
for(int i = cursize; i < size; i++)
ss.put('\0');
String res = ss.str();
if(!reverse)
std::reverse(res.begin(), res.end());
return res;
}
String StringUtils::ToHex(duint value)
{
std::stringstream ss;
ss << std::hex;
ss << value;
return ss.str();
}
String StringUtils::ToHex(void* buffer, size_t size, bool reverse)
{
std::stringstream ss;
ss << std::hex;
if(reverse)
{
for(int i = size - 1; i >= 0; i--)
ss << ((char*)buffer)[i];
}
else
{
for(int i = 0; i < size; i++)
ss << ((char*)buffer)[i];
}
return ss.str();
}

View File

@ -3,6 +3,9 @@
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include "_global.h"
typedef std::string String;
typedef std::wstring WString;
@ -15,9 +18,9 @@ public:
static StringList Split(const String & s, char delim, std::vector<String> & elems);
static StringList Split(const String & s, char delim);
static String Escape(const String & s);
static String Trim(const String & s);
static String TrimLeft(const String & s);
static String TrimRight(const String & s);
static String Trim(const String & s, String delim = StringUtils::WHITESPACE);
static String TrimLeft(const String & s, String delim = StringUtils::WHITESPACE);
static String TrimRight(const String & s, String delim = StringUtils::WHITESPACE);
static String Utf16ToUtf8(const WString & wstr);
static String Utf16ToUtf8(const wchar_t* wstr);
static WString Utf8ToUtf16(const String & str);
@ -28,6 +31,26 @@ public:
static WString sprintf(const wchar_t* format, ...);
static String ToLower(const String & s);
static bool StartsWith(const String & h, const String & n);
static String FromHex(const String & s, size_t size, bool reverse = false);
static String ToHex(duint value);
static String ToHex(void* buffer, size_t size, bool reverse = false);
template<typename T>
static String ToFloatingString(void* buffer)
{
auto value = *(T*)buffer;
std::stringstream wFloatingStr;
wFloatingStr << std::setprecision(std::numeric_limits<T>::digits10) << value;
return wFloatingStr.str();
}
template<typename T>
static String ToIntegralString(void* buffer)
{
auto value = *(T*)buffer;
return ToHex(value);
}
private:
static const String WHITESPACE;

View File

@ -59,6 +59,7 @@ enum SectionLock
LockCrossReferences,
LockDebugStartStop,
LockArguments,
LockEncodeMaps,
LockCallstackCache,
// Number of elements in this enumeration. Must always be the last

View File

@ -22,6 +22,7 @@
#include "filehelper.h"
#include "database.h"
#include "mnemonichelp.h"
#include "datainst_helper.h"
static MESSAGE_STACK* gMsgStack = 0;
static HANDLE hCommandLoopThread = 0;
@ -274,6 +275,7 @@ static void registercommands()
dbgcmdnew("briefcheck", cbInstrBriefcheck, true); //check if mnemonic briefs are missing
dbgcmdnew("analrecur\1analr", cbInstrAnalrecur, true); //analyze a single function
dbgcmdnew("analxrefs\1analx", cbInstrAnalxrefs, true); //analyze xrefs
dbgcmdnew("analadv", cbInstrAnalyseadv, true); //analyze xref,function and data
dbgcmdnew("guiupdatedisable", cbInstrDisableGuiUpdate, true); //disable gui message
dbgcmdnew("guiupdateenable", cbInstrEnableGuiUpdate, true); //enable gui message
dbgcmdnew("exhandlers", cbInstrExhandlers, true); //enumerate exception handlers
@ -425,6 +427,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
strcat_s(scriptDllDir, "\\scripts\\");
DeleteFileW(StringUtils::Utf8ToUtf16(alloctrace).c_str());
setalloctrace(alloctrace);
initDataInstMap();
// Load mnemonic help database
String mnemonicHelpData;

View File

@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="addrinfo.cpp" />
<ClCompile Include="advancedanalysis.cpp" />
<ClCompile Include="analysis.cpp" />
<ClCompile Include="AnalysisPass.cpp" />
<ClCompile Include="analysis_nukem.cpp" />
@ -35,9 +36,11 @@
<ClCompile Include="console.cpp" />
<ClCompile Include="controlflowanalysis.cpp" />
<ClCompile Include="database.cpp" />
<ClCompile Include="datainst_helper.cpp" />
<ClCompile Include="dbghelp_safe.cpp" />
<ClCompile Include="debugger.cpp" />
<ClCompile Include="debugger_commands.cpp" />
<ClCompile Include="encodemap.cpp" />
<ClCompile Include="disasm_fast.cpp" />
<ClCompile Include="disasm_helper.cpp" />
<ClCompile Include="handles.cpp" />
@ -103,6 +106,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="addrinfo.h" />
<ClInclude Include="advancedanalysis.h" />
<ClInclude Include="analysis.h" />
<ClInclude Include="AnalysisPass.h" />
<ClInclude Include="analysis_nukem.h" />
@ -119,10 +123,12 @@
<ClInclude Include="console.h" />
<ClInclude Include="controlflowanalysis.h" />
<ClInclude Include="database.h" />
<ClInclude Include="datainst_helper.h" />
<ClInclude Include="dbghelp\dbghelp.h" />
<ClInclude Include="dbghelp_safe.h" />
<ClInclude Include="debugger.h" />
<ClInclude Include="debugger_commands.h" />
<ClInclude Include="encodemap.h" />
<ClInclude Include="DeviceNameResolver\DeviceNameResolver.h" />
<ClInclude Include="disasm_fast.h" />
<ClInclude Include="disasm_helper.h" />
@ -243,6 +249,7 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{E6548308-401E-3A8A-5819-905DB90522A6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

View File

@ -326,6 +326,15 @@
<ClCompile Include="xrefsanalysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="advancedanalysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="encodemap.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
<ClCompile Include="datainst_helper.cpp">
<Filter>Source Files\Utilities</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="x64_dbg.h">
@ -712,6 +721,12 @@
<ClInclude Include="xrefsanalysis.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="advancedanalysis.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="encodemap.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="keystone\arm.h">
<Filter>Header Files\Third Party\keystone</Filter>
</ClInclude>
@ -739,5 +754,8 @@
<ClInclude Include="keystone\x86.h">
<Filter>Header Files\Third Party\keystone</Filter>
</ClInclude>
<ClInclude Include="datainst_helper.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -47,6 +47,7 @@ Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
backgroundColor = ConfigColor("DisassemblyBackgroundColor");
mXrefInfo.refcount = 0;
mTmpCodeCount = 0;
// Slots
connect(Bridge::getBridge(), SIGNAL(repaintGui()), this, SLOT(reloadData()));
@ -1195,7 +1196,7 @@ dsint Disassembly::getPreviousInstructionRVA(dsint rva, duint count)
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), wBottomByteRealRVA, wMaxByteCountToRead);
dsint addr = mDisasm->DisassembleBack(reinterpret_cast<byte_t*>(wBuffer.data()), rvaToVa(wBottomByteRealRVA), wMaxByteCountToRead, wVirtualRVA, count);
dsint addr = mDisasm->DisassembleBack(reinterpret_cast<byte_t*>(wBuffer.data()), rvaToVa(wBottomByteRealRVA), wMaxByteCountToRead, wVirtualRVA , count, mTmpCodeCount, mTmpCodeList);
addr += rva - wVirtualRVA;
@ -1230,7 +1231,8 @@ dsint Disassembly::getNextInstructionRVA(dsint rva, duint count)
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), rva, wMaxByteCountToRead);
wNewRVA = mDisasm->DisassembleNext(reinterpret_cast<byte_t*>(wBuffer.data()), rvaToVa(rva), wMaxByteCountToRead, 0, count);
wNewRVA = mDisasm->DisassembleNext(reinterpret_cast<byte_t*>(wBuffer.data()), rvaToVa(rva), wMaxByteCountToRead, 0, count, mTmpCodeCount, mTmpCodeList);
wNewRVA += rva;
return wNewRVA;
@ -1292,7 +1294,7 @@ Instruction_t Disassembly::DisassembleAt(dsint rva)
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), rva, wMaxByteCountToRead);
return mDisasm->DisassembleAt(reinterpret_cast<byte_t*>(wBuffer.data()), wMaxByteCountToRead, 0, base, rva);
return mDisasm->DisassembleAt(reinterpret_cast<byte_t*>(wBuffer.data()), wMaxByteCountToRead, 0, base, rva, mTmpCodeCount, mTmpCodeList);
}
@ -1335,7 +1337,7 @@ void Disassembly::setSingleSelection(dsint index)
{
mSelection.firstSelectedIndex = index;
mSelection.fromIndex = index;
mSelection.toIndex = index;
mSelection.toIndex = getInstructionRVA(mSelection.fromIndex, 1) - 1;
emit selectionChanged(rvaToVa(index));
}
@ -1347,7 +1349,7 @@ dsint Disassembly::getInitialSelection()
dsint Disassembly::getSelectionSize()
{
return mSelection.toIndex - mSelection.fromIndex;
return mSelection.toIndex - mSelection.fromIndex + 1;
}
dsint Disassembly::getSelectionStart()
@ -1586,6 +1588,10 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
// Set base and size (Useful when memory page changed)
mMemPage->setAttributes(wBase, wSize);
mDisasm->getEncodeMap()->setMemoryRegion(wBase);
bool cipChanged = rvaToVa(mCipRva) != parCIP;
if(mRvaDisplayEnabled && mMemPage->getBase() != mRvaDisplayPageBase)
mRvaDisplayEnabled = false;
@ -1599,6 +1605,20 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
//set CIP rva
mCipRva = wCipRva;
//add CIP and its jump location to tmp code list so they will always decoded as code
if(cipChanged)
{
mTmpCodeCount = 1;
mTmpCodeList[0] = parCIP;
Instruction_t inst = DisassembleAt(mCipRva);
if(inst.branchType == Instruction_t::Unconditional || inst.branchType == Instruction_t::Conditional && DbgIsJumpGoingToExecute(parCIP))
{
mTmpCodeCount++;
mTmpCodeList[1] = inst.branchDestination;
}
}
if(newTableOffset == -1) //nothing specified
{
// Update table offset depending on the location of the instruction to disassemble
@ -1703,6 +1723,7 @@ void Disassembly::disassembleClear()
mHighlightToken = CapstoneTokenizer::SingleToken();
historyClear();
mMemPage->setAttributes(0, 0);
mDisasm->getEncodeMap()->setMemoryRegion(0);
setRowCount(0);
reloadData();
}

View File

@ -124,8 +124,6 @@ private:
dsint toIndex;
} SelectionData_t;
QBeaEngine* mDisasm;
SelectionData_t mSelection;
bool mIsLastInstDisplayed;
@ -206,9 +204,12 @@ protected:
dsint mRvaDisplayPageBase;
bool mHighlightingMode;
MemoryPage* mMemPage;
QBeaEngine* mDisasm;
bool mShowMnemonicBrief;
XREF_INFO mXrefInfo;
CodeFoldingHelper* mCodeFoldingManager;
duint mTmpCodeCount;
duint mTmpCodeList[3]; //ensure correct disassemble
};
#endif // DISASSEMBLY_H

View File

@ -1,9 +1,17 @@
#include "QBeaEngine.h"
#include "StringUtil.h"
QBeaEngine::QBeaEngine(int maxModuleSize)
: _tokenizer(maxModuleSize), mCodeFoldingManager(nullptr)
{
CapstoneTokenizer::UpdateColors();
UpdateDataInstructionMap();
this->mEncodeMap = new EncodeMap();
}
QBeaEngine::~QBeaEngine()
{
delete this->mEncodeMap;
}
/**
@ -18,7 +26,7 @@ QBeaEngine::QBeaEngine(int maxModuleSize)
*
* @return Return the RVA (Relative to the data pointer) of the nth instruction before the instruction pointed by ip
*/
ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n)
ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n, duint tmpcodecount, duint* tmpcodelist)
{
int i;
uint abuf[128], addr, back, cmdsize;
@ -45,8 +53,8 @@ ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip
if(n == 0)
return ip;
//if(ip < (uint)n)
// return ip;
if(ip < (uint)n)
return ip;
//TODO: buffer overflow due to unchecked "back" value
back = MAX_DISASM_BUFFER * (n + 3); // Instruction length limited to 16
@ -83,11 +91,15 @@ ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip
cmdsize = 2; //heuristic for better output (FF FE or FE FF are usually part of an instruction)
else
cmdsize = cp.Size();
cmdsize = mEncodeMap->getDataSize(base + addr, cmdsize, tmpcodecount, tmpcodelist);
}
pdata += cmdsize;
addr += cmdsize;
//back -= cmdsize; // dead code
back -= cmdsize;
size -= cmdsize;
}
@ -110,7 +122,7 @@ ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip
*
* @return Return the RVA (Relative to the data pointer) of the nth instruction after the instruction pointed by ip
*/
ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip, int n)
ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip, int n, duint tmpcodecount, duint* tmpcodelist)
{
int i;
uint cmdsize;
@ -128,9 +140,12 @@ ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip
if(n <= 0)
return ip;
pdata = data + ip;
size -= ip;
for(i = 0; i < n && size > 0; i++)
{
if(mCodeFoldingManager && mCodeFoldingManager->isFolded(ip + base))
@ -143,8 +158,12 @@ ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip
cmdsize = 1;
else
cmdsize = cp.Size();
cmdsize = mEncodeMap->getDataSize(base + ip, cmdsize, tmpcodecount, tmpcodelist);
}
pdata += cmdsize;
ip += cmdsize;
size -= cmdsize;
@ -165,7 +184,7 @@ ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip
* @return Return the disassembled instruction
*/
Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint instIndex, duint origBase, duint origInstRVA)
Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint instIndex, duint origBase, duint origInstRVA, duint tmpcodecount, duint* tmpcodelist)
{
//tokenize
CapstoneTokenizer::InstructionToken cap;
@ -175,6 +194,14 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint instInde
const auto & cp = _tokenizer.GetCapstone();
bool success = cp.Success();
ENCODETYPE type = enc_code;
type = mEncodeMap->getDataType(origBase + origInstRVA, cp.Success() ? len : 1, tmpcodecount, tmpcodelist);
if(type != enc_unknown && type != enc_code && type != enc_middle)
return DecodeDataAt(data, size, instIndex, origBase, origInstRVA, type);
auto branchType = Instruction_t::None;
if(success && (cp.InGroup(CS_GRP_JUMP) || cp.IsLoop()))
{
@ -204,6 +231,67 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint instInde
return wInst;
}
Instruction_t QBeaEngine::DecodeDataAt(byte_t* data, duint size, duint instIndex, duint origBase, duint origInstRVA, ENCODETYPE type, duint tmpcodecount, duint* tmpcodelist)
{
//tokenize
CapstoneTokenizer::InstructionToken cap;
DataInstructionInfo info;
auto & infoIter = dataInstMap.find(type);
if(infoIter == dataInstMap.end())
{
infoIter = dataInstMap.find(enc_byte);
}
int len = mEncodeMap->getDataSize(origBase + origInstRVA, 1, tmpcodecount, tmpcodelist);
QString mnemonic = _bLongDataInst ? infoIter.value().longName : infoIter.value().shortName;
len = std::min(len, (int)size);
QString datastr = GetDataTypeString(data, len, type);
_tokenizer.TokenizeData(mnemonic, datastr, cap);
Instruction_t wInst;
wInst.instStr = mnemonic + " " + datastr;
wInst.dump = QByteArray((const char*)data, len);
wInst.rva = origInstRVA;
wInst.length = len;
wInst.branchType = Instruction_t::None;
wInst.branchDestination = 0;
wInst.tokens = cap;
return wInst;
}
void QBeaEngine::UpdateDataInstructionMap()
{
dataInstMap.clear();
dataInstMap.insert(enc_byte, {"db", "byte", "int8"});
dataInstMap.insert(enc_word, {"dw", "word", "short"});
dataInstMap.insert(enc_dword, {"dd", "dword", "int"});
dataInstMap.insert(enc_fword, {"df", "fword", "fword"});
dataInstMap.insert(enc_qword, {"dq", "qword", "long"});
dataInstMap.insert(enc_tbyte, {"tbyte", "tbyte", "tbyte"});
dataInstMap.insert(enc_oword, {"oword", "oword", "oword"});
dataInstMap.insert(enc_mmword, {"mmword", "mmword", "long long"});
dataInstMap.insert(enc_xmmword, {"xmmword", "xmmword", "_m128"});
dataInstMap.insert(enc_ymmword, {"ymmword", "ymmword", "_m256"});
dataInstMap.insert(enc_real4, {"real4", "real4", "float"});
dataInstMap.insert(enc_real8, {"real8", "real8", "double"});
dataInstMap.insert(enc_real10, {"real10", "real10", "long double"});
dataInstMap.insert(enc_ascii, {"ascii", "ascii", "string"});
dataInstMap.insert(enc_unicode, {"unicode", "unicode", "wstring"});
}
void QBeaEngine::setCodeFoldingManager(CodeFoldingHelper* CodeFoldingManager)
{
mCodeFoldingManager = CodeFoldingManager;
@ -211,5 +299,6 @@ void QBeaEngine::setCodeFoldingManager(CodeFoldingHelper* CodeFoldingManager)
void QBeaEngine::UpdateConfig()
{
_bLongDataInst = ConfigBool("Disassembler", "LongDataInstruction");
_tokenizer.UpdateConfig();
}

View File

@ -4,6 +4,7 @@
#include <QString>
#include "Imports.h"
#include "capstone_gui.h"
#include "EncodeMap.h"
#include "CodeFolding.h"
struct Instruction_t
@ -37,14 +38,31 @@ class QBeaEngine
{
public:
explicit QBeaEngine(int maxModuleSize);
ulong DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n);
ulong DisassembleNext(byte_t* data, duint base, duint size, duint ip, int n);
Instruction_t DisassembleAt(byte_t* data, duint size, duint instIndex, duint origBase, duint origInstRVA);
~QBeaEngine();
ulong DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
ulong DisassembleNext(byte_t* data, duint base, duint size, duint ip, int n, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
Instruction_t DisassembleAt(byte_t* data, duint size, duint instIndex, duint origBase, duint origInstRVA, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
Instruction_t DecodeDataAt(byte_t* data, duint size, duint instIndex, duint origBase, duint origInstRVA, ENCODETYPE type, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
void setCodeFoldingManager(CodeFoldingHelper* CodeFoldingManager);
void UpdateConfig();
EncodeMap* getEncodeMap() { return mEncodeMap; }
private:
struct DataInstructionInfo
{
QString shortName;
QString longName;
QString cName;
};
void UpdateDataInstructionMap();
CapstoneTokenizer _tokenizer;
QHash<ENCODETYPE, DataInstructionInfo> dataInstMap;
bool _bLongDataInst;
EncodeMap* mEncodeMap;
CodeFoldingHelper* mCodeFoldingManager;
};

View File

@ -122,6 +122,20 @@ bool CapstoneTokenizer::Tokenize(duint addr, const unsigned char* data, int data
return true;
}
bool CapstoneTokenizer::TokenizeData(const QString & datatype, const QString & data, InstructionToken & instruction)
{
_inst = InstructionToken();
if(!tokenizeMnemonic(TokenType::MnemonicNormal, datatype))
return false;
addToken(TokenType::Value, data);
instruction = _inst;
return true;
}
void CapstoneTokenizer::UpdateConfig()
{
SetConfig(ConfigBool("Disassembler", "Uppercase"),
@ -372,6 +386,14 @@ bool CapstoneTokenizer::tokenizeMnemonic()
}
}
QString mnemonic = QString(_cp.Mnemonic().c_str());
tokenizeMnemonic(type, mnemonic);
return true;
}
bool CapstoneTokenizer::tokenizeMnemonic(TokenType type, const QString & mnemonic)
{
addToken(type, mnemonic);
if(_bTabbedMnemonic)
{

View File

@ -137,6 +137,7 @@ public:
CapstoneTokenizer(int maxModuleLength);
bool Tokenize(duint addr, const unsigned char* data, int datasize, InstructionToken & instruction);
bool TokenizeData(const QString & datatype, const QString & data, InstructionToken & instruction);
void UpdateConfig();
void SetConfig(bool bUppercase, bool bTabbedMnemonic, bool bArgumentSpaces, bool bMemorySpaces);
int Size() const;
@ -174,6 +175,7 @@ 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);

View File

@ -404,8 +404,66 @@ void CPUDisassembly::setupRightClickContextMenu()
toggleFunctionAction->setText(tr("Delete function"));
return true;
});
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/analyzesinglefunction.png"), tr("Analyze single function"), SLOT(analyzeSingleFunctionSlot()), "ActionAnalyzeSingleFunction"));
mMenuBuilder->addSeparator();
MenuBuilder* analysisMenu = new MenuBuilder(this);
analysisMenu->addAction(makeShortcutAction(tr("Analyze single function"), SLOT(analyzeSingleFunctionSlot()), "ActionAnalyzeSingleFunction"));
analysisMenu->addAction(makeAction(tr("Remove analysis from module"), SLOT(removeAnalysisModuleSlot())));
analysisMenu->addSeparator();
analysisMenu->addAction(makeAction(tr("Remove analysis from selection"), SLOT(removeAnalysisSelectionSlot())));
QMenu* encodeTypeMenu = makeMenu("Treat selection head as");
QMenu* encodeTypeRangeMenu = makeMenu("Treat selection as");
std::string strTable[] = {"Command", "Byte", "Word", "Dword", "Fword", "Qword", "Tbyte", "Oword", "",
"Float", "Double", "Long Double", "",
"ASCII", "UNICODE", "",
"MMWord", "XMMWord", "YMMWord"
};
ENCODETYPE enctypeTable[] = {enc_code, enc_byte, enc_word, enc_dword, enc_fword, enc_qword, enc_tbyte, enc_oword, enc_middle,
enc_real4, enc_real8, enc_real10 , enc_middle,
enc_ascii, enc_unicode, enc_middle,
enc_mmword, enc_xmmword, enc_ymmword
};
int enctypesize = sizeof(enctypeTable) / sizeof(ENCODETYPE);
for(int i = 0; i < enctypesize; i++)
{
if(enctypeTable[i] == enc_middle)
{
encodeTypeRangeMenu->addSeparator();
encodeTypeMenu->addSeparator();
}
else
{
QAction* action = makeAction(tr(strTable[i].c_str()), SLOT(setEncodeTypeRangeSlot()));
action->setData(enctypeTable[i]);
encodeTypeRangeMenu->addAction(action);
action = makeAction(tr(strTable[i].c_str()), SLOT(setEncodeTypeSlot()));
action->setData(enctypeTable[i]);
encodeTypeMenu->addAction(action);
}
}
analysisMenu->addMenu(encodeTypeMenu);
analysisMenu->addMenu(encodeTypeRangeMenu);
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/analyzesinglefunction.png"), tr("Analysis")), analysisMenu);
mMenuBuilder->addSeparator();
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/compile.png"), tr("Assemble"), SLOT(assembleSlot()), "ActionAssemble"));
removeAction(mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/patch.png"), tr("Patches"), SLOT(showPatchesSlot()), "ViewPatches"))); //prevent conflicting shortcut with the MainWindow
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/yara.png"), tr("&Yara..."), SLOT(yaraSlot()), "ActionYara"));
mMenuBuilder->addSeparator();
@ -1486,3 +1544,29 @@ void CPUDisassembly::analyzeSingleFunctionSlot()
{
DbgCmdExec(QString("analr %1").arg(ToHexString(rvaToVa(getInitialSelection()))).toUtf8().constData());
}
void CPUDisassembly::removeAnalysisSelectionSlot()
{
mDisasm->getEncodeMap()->delRange(rvaToVa(getSelectionStart()), getSelectionSize());
GuiUpdateDisassemblyView();
}
void CPUDisassembly::removeAnalysisModuleSlot()
{
mDisasm->getEncodeMap()->delSegment(rvaToVa(getSelectionStart()));
GuiUpdateDisassemblyView();
}
void CPUDisassembly::setEncodeTypeRangeSlot()
{
QAction* pAction = qobject_cast<QAction*>(sender());
mDisasm->getEncodeMap()->setDataType(rvaToVa(getSelectionStart()), getSelectionSize(), (ENCODETYPE)pAction->data().toUInt());
GuiUpdateDisassemblyView();
}
void CPUDisassembly::setEncodeTypeSlot()
{
QAction* pAction = qobject_cast<QAction*>(sender());
mDisasm->getEncodeMap()->setDataType(rvaToVa(getSelectionStart()), (ENCODETYPE)pAction->data().toUInt());
GuiUpdateDisassemblyView();
}

View File

@ -95,6 +95,10 @@ public slots:
void labelHelpSlot();
void editSoftBpActionSlot();
void analyzeSingleFunctionSlot();
void removeAnalysisSelectionSlot();
void removeAnalysisModuleSlot();
void setEncodeTypeSlot();
void setEncodeTypeRangeSlot();
protected:
void paintEvent(QPaintEvent* event);

View File

@ -176,6 +176,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
disassemblyBool.insert("FindCommandEntireBlock", false);
disassemblyBool.insert("OnlyCipAutoComments", false);
disassemblyBool.insert("TabbedMnemonic", false);
disassemblyBool.insert("LongDataInstruction", false);
defaultBools.insert("Disassembler", disassemblyBool);
QMap<QString, bool> engineBool;

View File

@ -0,0 +1,204 @@
#include "EncodeMap.h"
EncodeMap::EncodeMap(QObject* parent) : QObject(parent), mBase(0), mSize(0), mBuffer(nullptr)
{
}
EncodeMap::~EncodeMap()
{
if(mBuffer)
DbgReleaseEncodeTypeBuffer(mBuffer);
}
void EncodeMap::setMemoryRegion(duint addr)
{
mBase = DbgMemFindBaseAddr(addr, &mSize);
if(!mBase)
return;
if(mBuffer)
DbgReleaseEncodeTypeBuffer(mBuffer);
mBuffer = (byte*)DbgGetEncodeTypeBuffer(addr);
}
bool EncodeMap::isRangeConflict(duint offset, duint size, duint codesize, duint tmpcodecount, duint* tmpcodelist)
{
if(codesize > size)
return true;
size = std::min(size, codesize);
if(size <= 0)
return false;
ENCODETYPE type = (ENCODETYPE)mBuffer[offset];
if(type == enc_middle)
return true;
for(int i = 0; i < tmpcodecount; i++)
{
if(tmpcodelist[i] > offset + mBase && tmpcodelist[i] < offset + size + mBase)
return true;
}
for(int i = 1 + offset; i < size + offset; i++)
{
if((ENCODETYPE)mBuffer[i] != enc_unknown && (ENCODETYPE)mBuffer[i] != enc_middle)
return true;
}
return false;
}
void EncodeMap::setDataType(duint va, ENCODETYPE type)
{
setDataType(va, getEncodeTypeSize(type), type);
}
void EncodeMap::setDataType(duint va, duint size, ENCODETYPE type)
{
DbgSetEncodeType(va, size, type);
if(!mBuffer && va >= mBase && va < mBase + mSize)
setMemoryRegion(va);
}
void EncodeMap::delRange(duint start, duint size)
{
DbgDelEncodeTypeRange(start, size);
}
void EncodeMap::delSegment(duint va)
{
DbgDelEncodeTypeSegment(va);
if(mBuffer && va >= mBase && va < mBase + mSize)
{
mBuffer = nullptr;
DbgReleaseEncodeTypeBuffer(mBuffer);
}
}
duint EncodeMap::getEncodeTypeSize(ENCODETYPE type)
{
switch(type)
{
case enc_byte:
return 1;
case enc_word:
return 2;
case enc_dword:
return 4;
case enc_fword:
return 6;
case enc_qword:
return 8;
case enc_tbyte:
return 10;
case enc_oword:
return 16;
case enc_mmword:
return 8;
case enc_xmmword:
return 16;
case enc_ymmword:
return 32;
case enc_real4:
return 4;
case enc_real8:
return 8;
case enc_real10:
return 10;
case enc_ascii:
return 1;
case enc_unicode:
return 2;
default:
return 1;
}
}
bool EncodeMap::isDataType(ENCODETYPE type)
{
switch(type)
{
case enc_unknown:
case enc_code:
case enc_middle:
case enc_junk:
return false;
default:
return true;
}
}
ENCODETYPE EncodeMap::getDataType(duint addr, duint codesize, duint tmpcodecount, duint* tmpcodelist)
{
if(addr - mBase >= mSize)
return ENCODETYPE::enc_unknown;
for(int i = 0; i < tmpcodecount; i++)
{
if(addr == tmpcodelist[i])
return enc_code;
else if(addr < tmpcodelist[i] && addr + codesize > tmpcodelist[i] && !mBuffer)
return enc_byte;
}
if(!mBuffer)
return ENCODETYPE::enc_unknown;
duint offset = addr - mBase;
ENCODETYPE type = (ENCODETYPE)mBuffer[offset];
bool conflict = isRangeConflict(offset, mSize - offset, codesize, tmpcodecount, tmpcodelist);
if(conflict)
return enc_byte;
else
return type;
}
duint EncodeMap::getDataSize(duint addr, duint codesize, duint tmpcodecount, duint* tmpcodelist)
{
if(addr - mBase >= mSize)
return codesize;
for(int i = 0; i < tmpcodecount; i++)
{
if(addr == tmpcodelist[i])
return codesize;
else if(addr < tmpcodelist[i] && addr + codesize > tmpcodelist[i] && !mBuffer)
return 1;
}
if(!mBuffer)
return codesize;
duint offset = addr - mBase;
ENCODETYPE type = (ENCODETYPE)mBuffer[offset];
duint datasize = getEncodeTypeSize(type);
if(type == enc_unknown || type == enc_code || type == enc_junk)
{
if(isRangeConflict(offset, mSize - offset, codesize, tmpcodecount, tmpcodelist) || codesize == 0)
{
return datasize;
}
else
return codesize;
}
else if(type == enc_ascii || type == enc_unicode)
{
duint totalsize = 0;
for(int i = offset; i < mSize; i += datasize)
{
if(mBuffer[i] == type)
totalsize += datasize;
else
break;
}
return totalsize;
}
else
return datasize;
return codesize;
}

View File

@ -0,0 +1,32 @@
#ifndef ENCODEMAP_H
#define ENCODEMAP_H
#include <QObject>
#include "bridge/bridgemain.h"
class EncodeMap : public QObject
{
Q_OBJECT
public:
explicit EncodeMap(QObject* parent = 0);
~EncodeMap();
void setMemoryRegion(duint va);
duint getDataSize(duint va, duint codesize, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
ENCODETYPE getDataType(duint addr, duint codesize, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
void setDataType(duint va, ENCODETYPE type);
void setDataType(duint va, duint size, ENCODETYPE type);
void delRange(duint start, duint size);
void delSegment(duint va);
bool isRangeConflict(duint offset, duint size, duint codesize, duint tmpcodecount = 0, duint* tmpcodelist = nullptr);
bool isDataType(ENCODETYPE type);
duint getEncodeTypeSize(ENCODETYPE type);
bool isCode(ENCODETYPE type) {return type == enc_unknown || type == enc_code; }
protected:
duint mBase;
duint mSize;
byte* mBuffer;
};
#endif // ENCODEMAP_H

View File

@ -1,6 +1,7 @@
#include <stdint.h>
#include "StringUtil.h"
#include "float128.h"
#include "MiscUtil.h"
dd_real pow2_fast(int exponent, int* exp10)
{
@ -168,6 +169,43 @@ QString ToLongDoubleString(void* buffer)
}
}
QString GetDataTypeString(void* buffer, duint size, ENCODETYPE type)
{
switch(type)
{
case enc_byte:
return ToIntegralString<unsigned char>(buffer);
case enc_word:
return ToIntegralString<unsigned short>(buffer);
case enc_dword:
return ToIntegralString<unsigned int>(buffer);
case enc_fword:
return QString(ByteReverse(QByteArray((char*)buffer, 6)).toHex());
case enc_qword:
return ToIntegralString<unsigned long long int>(buffer);
case enc_tbyte:
return QString(ByteReverse(QByteArray((char*)buffer, 10)).toHex());
case enc_oword:
return QString(ByteReverse(QByteArray((char*)buffer, 16)).toHex());
case enc_mmword:
case enc_xmmword:
case enc_ymmword:
return QString(QByteArray((const char*)buffer, size).toHex());
case enc_real4:
return ToFloatString(buffer);
case enc_real8:
return ToDoubleString(buffer);
case enc_real10:
return ToLongDoubleString(buffer);
case enc_ascii:
return QString::fromLocal8Bit((const char*)buffer, size);
case enc_unicode:
return QString::fromWCharArray((const wchar_t*)buffer, size / sizeof(wchar_t));
default:
return ToIntegralString<unsigned char>(buffer);
}
}
QString ToDateString(const QDate & date)
{
static const char* months[] =

View File

@ -54,6 +54,7 @@ static QString ToDecString(dsint Value)
return QString(temp);
}
template<typename T>
static QString ToFloatingString(void* buffer)
{
@ -63,6 +64,13 @@ static QString ToFloatingString(void* buffer)
return QString::fromStdString(wFloatingStr.str());
}
template<typename T>
static QString ToIntegralString(void* buffer)
{
auto value = *(T*)buffer;
return ToHexString(value);
}
static QString ToFloatString(void* buffer)
{
return ToFloatingString<float>(buffer);
@ -77,6 +85,8 @@ QString ToLongDoubleString(void* buffer);
QString ToDateString(const QDate & date);
QString GetDataTypeString(void* buffer, duint size, ENCODETYPE type);
static QDate GetCompileDate()
{
return QLocale("en_US").toDate(QString(__DATE__).simplified(), "MMM d yyyy");

View File

@ -155,6 +155,7 @@ SOURCES += \
Src/Gui/XrefBrowseDialog.cpp \
Src/Gui/CodepageSelectionDialog.cpp \
Src/Gui/ColumnReorderDialog.cpp \
Src/Utils/EncodeMap.cpp \
Src/Utils/CodeFolding.cpp
@ -252,7 +253,9 @@ HEADERS += \
Src/Gui/CodepageSelectionDialog.h \
Src/Utils/CachedFontMetrics.h \
Src/Gui/ColumnReorderDialog.h \
Src/Utils/EncodeMap.h \
Src/Utils/CodeFolding.h
FORMS += \
Src/Gui/MainWindow.ui \