DBG: AStyle
This commit is contained in:
parent
5fc4d90d8b
commit
fa2db57799
|
@ -1,373 +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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,152 +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);
|
||||
#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);
|
||||
};
|
|
@ -1,309 +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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -1,12 +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);
|
||||
|
||||
#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);
|
|
@ -702,7 +702,7 @@ CMDRESULT cbDebugGetBPXMemoryHitCount(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugSetBPGoto(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
if(argc != 3)
|
||||
{
|
||||
dputs("argument count mismatch!\n");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1297,7 +1297,7 @@ CMDRESULT cbDebugRunToParty(int argc, char* argv[])
|
|||
for(auto j : i.sections)
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if (!BpGet(j.addr, BPMEMORY, nullptr, &bp))
|
||||
if(!BpGet(j.addr, BPMEMORY, nullptr, &bp))
|
||||
{
|
||||
RunToUserCodeBreakpoints.push_back(std::make_pair(j.addr, j.size));
|
||||
SetMemoryBPXEx(j.addr, j.size, UE_MEMORY_EXECUTE, false, (void*)cbRunToUserCodeBreakpoint);
|
||||
|
|
|
@ -1,381 +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();
|
||||
}
|
||||
#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();
|
||||
}
|
||||
|
|
|
@ -1,26 +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();
|
||||
|
||||
#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);
|
|
@ -110,7 +110,7 @@ bool ModLoad(duint Base, duint Size, const char* FullPath)
|
|||
GetEnvironmentVariableW(L"windir", sysdir, sizeof(sysdir));
|
||||
String Utf8Sysdir = StringUtils::Utf16ToUtf8(sysdir);
|
||||
Utf8Sysdir.append("\\");
|
||||
if (_memicmp(Utf8Sysdir.c_str(), FullPath, Utf8Sysdir.size()) == 0)
|
||||
if(_memicmp(Utf8Sysdir.c_str(), FullPath, Utf8Sysdir.size()) == 0)
|
||||
{
|
||||
info.party = 1;
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ int ModGetParty(duint Address)
|
|||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
// If the module is not found, it is an user module
|
||||
if (!module)
|
||||
if(!module)
|
||||
return 0;
|
||||
|
||||
return module->party;
|
||||
|
@ -436,7 +436,7 @@ void ModSetParty(duint Address, int Party)
|
|||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
// If the module is not found, it is an user module
|
||||
if (!module)
|
||||
if(!module)
|
||||
return;
|
||||
|
||||
module->party = Party;
|
||||
|
|
|
@ -159,7 +159,7 @@ static void registercommands()
|
|||
dbgcmdnew("SetMemoryBreakpointFastResume", cbDebugSetBPXMemoryFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetMemoryGetBreakpointHitCount", cbDebugGetBPXMemoryHitCount, true); //get breakpoint hit count
|
||||
dbgcmdnew("ResetMemoryBreakpointHitCount", cbDebugResetBPXMemoryHitCount, true); //reset breakpoint hit count
|
||||
|
||||
|
||||
dbgcmdnew("bpgoto", cbDebugSetBPGoto, true);
|
||||
|
||||
//variables
|
||||
|
|
|
@ -1,204 +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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -1,32 +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
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue