DBG: initial commit for control flow analysis
This commit is contained in:
parent
53fd990c83
commit
6779900c44
|
|
@ -0,0 +1,186 @@
|
|||
#include "controlflowanalysis.h"
|
||||
#include "memory.h"
|
||||
#include "console.h"
|
||||
|
||||
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size)
|
||||
{
|
||||
_base = base;
|
||||
_size = size;
|
||||
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
|
||||
MemRead((void*)_base, _data, _size, 0);
|
||||
}
|
||||
|
||||
ControlFlowAnalysis::~ControlFlowAnalysis()
|
||||
{
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
bool ControlFlowAnalysis::IsValidAddress(uint addr)
|
||||
{
|
||||
return addr >= _base && addr < _base + _size;
|
||||
}
|
||||
|
||||
const unsigned char* ControlFlowAnalysis::TranslateAddress(uint addr)
|
||||
{
|
||||
return IsValidAddress(addr) ? _data + (addr - _base) : nullptr;
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::Analyse()
|
||||
{
|
||||
dputs("Starting analysis...");
|
||||
DWORD ticks = GetTickCount();
|
||||
|
||||
BasicBlockStarts();
|
||||
BasicBlocks();
|
||||
|
||||
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::SetMarkers()
|
||||
{
|
||||
dprintf("digraph ControlFlow {\n");
|
||||
int i = 0;
|
||||
std::map<uint, int> nodeMap;
|
||||
for(auto block : _blocks)
|
||||
{
|
||||
nodeMap.insert({ block.start, i });
|
||||
dprintf(" node%u [label=\"start=%p, end=%p\"];\n", i, block.start, block.end);
|
||||
i++;
|
||||
}
|
||||
for(auto block : _blocks)
|
||||
{
|
||||
int startNode = nodeMap[block.start];
|
||||
if(block.left)
|
||||
{
|
||||
if(nodeMap.count(block.left))
|
||||
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.left]);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf(" node%u [shape=point];\n", i);
|
||||
dprintf(" node%u -> node%u;\n", startNode, i);
|
||||
i++;
|
||||
}
|
||||
if(block.right)
|
||||
{
|
||||
if(nodeMap.count(block.right))
|
||||
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.right]);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf(" node%u [shape=point];\n", i);
|
||||
dprintf(" node%u -> node%u;\n", startNode, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
dprintf("}\n");
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::BasicBlockStarts()
|
||||
{
|
||||
bool bSkipFilling = false;
|
||||
for(uint i = 0; i < _size;)
|
||||
{
|
||||
uint addr = _base + i;
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
if(bSkipFilling) //handle filling skip mode
|
||||
{
|
||||
if(!_cp.IsFilling()) //do nothing until the filling stopped
|
||||
{
|
||||
bSkipFilling = false;
|
||||
_blockStarts.insert(addr);
|
||||
}
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_RET))
|
||||
{
|
||||
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest2 = 0;
|
||||
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
|
||||
dest2 = addr + _cp.Size();
|
||||
|
||||
if(!dest1 && !dest2)
|
||||
bSkipFilling = true;
|
||||
if(dest1)
|
||||
_blockStarts.insert(dest1);
|
||||
if(dest2)
|
||||
_blockStarts.insert(dest2);
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_CALL))
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
if(dest1)
|
||||
_blockStarts.insert(dest1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
if(dest1)
|
||||
_blockStarts.insert(dest1);
|
||||
}
|
||||
i += _cp.Size();
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::BasicBlocks()
|
||||
{
|
||||
for(auto i = _blockStarts.begin(); i != _blockStarts.end(); i++)
|
||||
{
|
||||
uint start = *i;
|
||||
if(!IsValidAddress(start))
|
||||
continue;
|
||||
uint nextStart = _base + _size;
|
||||
auto next = std::next(i);
|
||||
if(next != _blockStarts.end())
|
||||
nextStart = *next;
|
||||
for(uint addr = start, prevaddr = 0; addr < _base + _size;)
|
||||
{
|
||||
prevaddr = addr;
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
if(_cp.InGroup(CS_GRP_RET))
|
||||
{
|
||||
_blocks.push_back(BasicBlock(start, addr, 0, 0)); //leaf block
|
||||
break;
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0;
|
||||
_blocks.push_back(BasicBlock(start, addr, dest1, dest2));
|
||||
break;
|
||||
}
|
||||
addr += _cp.Size();
|
||||
}
|
||||
else
|
||||
addr++;
|
||||
if(addr == nextStart) //special case handling overlapping blocks
|
||||
{
|
||||
_blocks.push_back(BasicBlock(start, prevaddr, 0, nextStart));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint ControlFlowAnalysis::GetBranchOperand()
|
||||
{
|
||||
for(int i = 0; i < _cp.x86().op_count; i++)
|
||||
{
|
||||
const cs_x86_op & operand = _cp.x86().operands[i];
|
||||
if(operand.type == X86_OP_IMM)
|
||||
{
|
||||
uint dest = (uint)operand.imm;
|
||||
if(dest >= _base && dest < _base + _size)
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef _CONTROLFLOWANALYSIS_H
|
||||
#define _CONTROLFLOWANALYSIS_H
|
||||
|
||||
#include "_global.h"
|
||||
#include "capstone_wrapper.h"
|
||||
|
||||
class ControlFlowAnalysis
|
||||
{
|
||||
public:
|
||||
explicit ControlFlowAnalysis(uint base, uint size);
|
||||
ControlFlowAnalysis(const ControlFlowAnalysis & that) = delete;
|
||||
~ControlFlowAnalysis();
|
||||
bool IsValidAddress(uint addr);
|
||||
const unsigned char* TranslateAddress(uint addr);
|
||||
void Analyse();
|
||||
void SetMarkers();
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
uint start;
|
||||
uint end;
|
||||
|
||||
bool operator<(const FunctionInfo & b) const
|
||||
{
|
||||
return start < b.start;
|
||||
}
|
||||
|
||||
bool operator==(const FunctionInfo & b) const
|
||||
{
|
||||
return start == b.start;
|
||||
}
|
||||
};
|
||||
|
||||
struct BasicBlock
|
||||
{
|
||||
uint start;
|
||||
uint end;
|
||||
uint left;
|
||||
uint right;
|
||||
|
||||
BasicBlock()
|
||||
{
|
||||
this->start = 0;
|
||||
this->end = 0;
|
||||
this->left = 0;
|
||||
this->right = 0;
|
||||
}
|
||||
|
||||
BasicBlock(uint start, uint end, uint left, uint right)
|
||||
{
|
||||
this->start = start;
|
||||
this->end = end;
|
||||
this->left = min(left, right);
|
||||
this->right = max(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
uint _base;
|
||||
uint _size;
|
||||
unsigned char* _data;
|
||||
std::set<uint> _blockStarts;
|
||||
std::vector<BasicBlock> _blocks;
|
||||
Capstone _cp;
|
||||
|
||||
void BasicBlockStarts();
|
||||
void BasicBlocks();
|
||||
uint GetBranchOperand();
|
||||
};
|
||||
|
||||
#endif //_CONTROLFLOWANALYSIS_H
|
||||
|
|
@ -26,6 +26,8 @@
|
|||
#include "module.h"
|
||||
#include "stringformat.h"
|
||||
#include "filereader.h"
|
||||
#include "functionanalysis.h"
|
||||
#include "controlflowanalysis.h"
|
||||
|
||||
static bool bRefinit = false;
|
||||
|
||||
|
|
@ -1877,8 +1879,6 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
#include "functionanalysis.h"
|
||||
|
||||
CMDRESULT cbInstrAnalyse(int argc, char* argv[])
|
||||
{
|
||||
SELECTIONDATA sel;
|
||||
|
|
@ -1892,6 +1892,19 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrCfanalyse(int argc, char* argv[])
|
||||
{
|
||||
SELECTIONDATA sel;
|
||||
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
|
||||
uint size = 0;
|
||||
uint base = MemFindBaseAddr(sel.start, &size);
|
||||
ControlFlowAnalysis anal(base, size);
|
||||
anal.Analyse();
|
||||
anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrVisualize(int argc, char* argv[])
|
||||
{
|
||||
if(argc < 3)
|
||||
|
|
@ -1950,7 +1963,7 @@ CMDRESULT cbInstrVisualize(int argc, char* argv[])
|
|||
break;
|
||||
|
||||
const cs_x86_op & operand = _cp.x86().operands[0];
|
||||
if(_cp.InGroup(CS_GRP_JUMP) && operand.type == X86_OP_IMM) //jump
|
||||
if((_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) && operand.type == X86_OP_IMM) //jump
|
||||
{
|
||||
uint dest = (uint)operand.imm;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,5 +70,6 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[]);
|
|||
CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrVisualize(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrMeminfo(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrCfanalyse(int argc, char* argv[]);
|
||||
|
||||
#endif // _INSTRUCTIONS_H
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ static void registercommands()
|
|||
dbgcmdnew("capstone", cbInstrCapstone, true); //disassemble using capstone
|
||||
dbgcmdnew("visualize", cbInstrVisualize, true); //visualize analysis
|
||||
dbgcmdnew("meminfo", cbInstrMeminfo, true); //command to debug memory map bugs
|
||||
dbgcmdnew("cfanal\1cfanalyse\1cfanalyze", cbInstrCfanalyse, true); //control flow analysis
|
||||
}
|
||||
|
||||
static bool cbCommandProvider(char* cmd, int maxlen)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
<ClCompile Include="commandparser.cpp" />
|
||||
<ClCompile Include="comment.cpp" />
|
||||
<ClCompile Include="console.cpp" />
|
||||
<ClCompile Include="controlflowanalysis.cpp" />
|
||||
<ClCompile Include="dbghelp_safe.cpp" />
|
||||
<ClCompile Include="debugger.cpp" />
|
||||
<ClCompile Include="debugger_commands.cpp" />
|
||||
|
|
@ -92,6 +93,7 @@
|
|||
<ClInclude Include="commandparser.h" />
|
||||
<ClInclude Include="comment.h" />
|
||||
<ClInclude Include="console.h" />
|
||||
<ClInclude Include="controlflowanalysis.h" />
|
||||
<ClInclude Include="dbghelp\dbghelp.h" />
|
||||
<ClInclude Include="dbghelp_safe.h" />
|
||||
<ClInclude Include="debugger.h" />
|
||||
|
|
|
|||
|
|
@ -243,6 +243,9 @@
|
|||
<ClCompile Include="_scriptapi_gui.cpp">
|
||||
<Filter>Source Files\Interfaces/Exports\_scriptapi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="controlflowanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
|
@ -563,5 +566,8 @@
|
|||
<ClInclude Include="_scriptapi_gui.h">
|
||||
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="controlflowanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue