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:
parent
b3d71c2265
commit
899a1c235c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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("");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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[]);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ enum SectionLock
|
|||
LockCrossReferences,
|
||||
LockDebugStartStop,
|
||||
LockArguments,
|
||||
LockEncodeMaps,
|
||||
LockCallstackCache,
|
||||
|
||||
// Number of elements in this enumeration. Must always be the last
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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[] =
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
Loading…
Reference in New Issue