1
0
Fork 0

BRIDGE+DBG+GUI: basics of analysis plugins

This commit is contained in:
mrexodia 2016-10-18 17:21:31 +02:00
parent d0c755e3f8
commit 9138a3410e
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
13 changed files with 106 additions and 32 deletions

View File

@ -51,7 +51,15 @@ struct BridgeCFNode
std::vector<duint> exits; //exits (including brtrue and brfalse)
std::vector<BridgeCFInstruction> instrs; //block instructions
explicit BridgeCFNode(BridgeCFNodeList* nodeList, bool freedata = true)
static void Free(const BridgeCFNodeList* nodeList)
{
if(!BridgeList<duint>::Free(&nodeList->exits))
__debugbreak();
if(!BridgeList<BridgeCFInstruction>::Free(&nodeList->instrs))
__debugbreak();
}
explicit BridgeCFNode(const BridgeCFNodeList* nodeList, bool freedata)
{
if(!nodeList)
__debugbreak();
@ -113,7 +121,17 @@ struct BridgeCFGraph
std::unordered_map<duint, BridgeCFNode> nodes; //CFNode.start -> CFNode
std::unordered_map<duint, std::unordered_set<duint>> parents; //CFNode.start -> parents
explicit BridgeCFGraph(BridgeCFGraphList* graphList, bool freedata = true)
static void Free(const BridgeCFGraphList* graphList)
{
if(!graphList || graphList->nodes.size != graphList->nodes.count * sizeof(BridgeCFNodeList))
__debugbreak();
auto data = (BridgeCFNodeList*)graphList->nodes.data;
for(int i = 0; i < graphList->nodes.count; i++)
BridgeCFNode::Free(&data[i]);
BridgeFree(data);
}
explicit BridgeCFGraph(const BridgeCFGraphList* graphList, bool freedata)
{
if(!graphList || graphList->nodes.size != graphList->nodes.count * sizeof(BridgeCFNodeList))
__debugbreak();

View File

@ -120,6 +120,14 @@ public:
return true;
}
static bool Free(const ListInfo* listInfo)
{
if(!listInfo || listInfo->size != listInfo->count * sizeof(Type) || (listInfo->count && !listInfo->data))
return false;
BridgeFree(listInfo->data);
return true;
}
static bool ToVector(const ListInfo* listInfo, std::vector<Type> & listData, bool freedata = true)
{
if(!listInfo || listInfo->size != listInfo->count * sizeof(Type) || (listInfo->count && !listInfo->data))

View File

@ -1463,9 +1463,9 @@ BRIDGE_IMPEXP void GuiLoadGraph(BridgeCFGraphList* graph, duint addr)
_gui_sendmessage(GUI_LOAD_GRAPH, graph, (void*)addr);
}
BRIDGE_IMPEXP bool GuiGraphAt(duint addr)
BRIDGE_IMPEXP duint GuiGraphAt(duint addr)
{
return !!_gui_sendmessage(GUI_GRAPH_AT, (void*)addr, nullptr);
return (duint)_gui_sendmessage(GUI_GRAPH_AT, (void*)addr, nullptr);
}
BRIDGE_IMPEXP void GuiUpdateGraphView()

View File

@ -1102,7 +1102,7 @@ BRIDGE_IMPEXP bool GuiIsUpdateDisabled();
BRIDGE_IMPEXP void GuiUpdateEnable(bool updateNow);
BRIDGE_IMPEXP void GuiUpdateDisable();
BRIDGE_IMPEXP void GuiLoadGraph(BridgeCFGraphList* graph, duint addr);
BRIDGE_IMPEXP bool GuiGraphAt(duint addr);
BRIDGE_IMPEXP duint GuiGraphAt(duint addr);
BRIDGE_IMPEXP void GuiUpdateGraphView();
BRIDGE_IMPEXP void GuiDisableLog();
BRIDGE_IMPEXP void GuiEnableLog();

View File

@ -194,6 +194,11 @@ typedef struct
duint VA;
} PLUG_CB_SELCHANGED;
typedef struct
{
BridgeCFGraphList graph;
} PLUG_CB_ANALYZE;
//enums
typedef enum
{
@ -223,6 +228,7 @@ typedef enum
CB_FILTERSYMBOL, //PLUG_CB_FILTERSYMBOL
CB_TRACEEXECUTE, //PLUG_CB_TRACEEXECUTE
CB_SELCHANGED, //PLUG_CB_SELCHANGED
CB_ANALYZE, //PLUG_CB_ANALYZE
CB_LAST
} CBTYPE;

View File

@ -4,11 +4,13 @@
#include "filehelper.h"
#include "function.h"
#include "xrefs.h"
#include "plugin_loader.h"
RecursiveAnalysis::RecursiveAnalysis(duint base, duint size, duint entryPoint, duint maxDepth, bool dump)
RecursiveAnalysis::RecursiveAnalysis(duint base, duint size, duint entryPoint, duint maxDepth, bool usePlugins, bool dump)
: Analysis(base, size),
mEntryPoint(entryPoint),
mMaxDepth(maxDepth),
mUsePlugins(usePlugins),
mDump(dump)
{
}
@ -200,5 +202,13 @@ void RecursiveAnalysis::analyzeFunction(duint entryPoint)
addr += size;
}
}
//fourth pass: allow plugins to manipulate the graph
if(mUsePlugins && !plugincbempty(CB_ANALYZE))
{
PLUG_CB_ANALYZE info;
info.graph = graph.ToGraphList();
plugincbcall(CB_ANALYZE, &info);
graph = BridgeCFGraph(&info.graph, true);
}
mFunctions.push_back(graph);
}

View File

@ -5,7 +5,7 @@
class RecursiveAnalysis : public Analysis
{
public:
explicit RecursiveAnalysis(duint base, duint size, duint entryPoint, duint maxDepth, bool dump = false);
explicit RecursiveAnalysis(duint base, duint size, duint entryPoint, duint maxDepth, bool usePlugins, bool dump = false);
void Analyse() override;
void SetMarkers() override;
@ -83,6 +83,7 @@ protected:
private:
duint mMaxDepth;
bool mUsePlugins;
bool mDump;
struct XREF

View File

@ -92,7 +92,7 @@ bool cbInstrAnalrecur(int argc, char* argv[])
auto base = MemFindBaseAddr(entry, &size);
if(!base)
return false;
RecursiveAnalysis analysis(base, size, entry, 0);
RecursiveAnalysis analysis(base, size, entry, 0, true);
analysis.Analyse();
analysis.SetMarkers();
return true;

View File

@ -94,6 +94,9 @@ bool cbDebugMemmapdump(int argc, char* argv[])
bool cbInstrGraph(int argc, char* argv[])
{
auto options = argc > 2 ? argv[2] : "";
auto force = !!strstr(options, "force");
auto silent = !!strstr(options, "silent");
duint entry;
if(argc < 2 || !valfromstring(argv[1], &entry))
entry = GetContextDataEx(hActiveThread, UE_CIP);
@ -103,21 +106,25 @@ bool cbInstrGraph(int argc, char* argv[])
auto base = MemFindBaseAddr(entry, &size);
if(!base || !MemIsValidReadPtr(entry))
{
if(argc <= 2) //undocumented silent option
if(!silent)
dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid address %p!\n"), entry);
return false;
}
if(!GuiGraphAt(sel))
auto curEntry = GuiGraphAt(sel);
if(curEntry)
entry = curEntry;
if(!curEntry || force)
{
auto modbase = ModBaseFromAddr(base);
if(modbase)
base = modbase, size = ModSizeFromAddr(modbase);
RecursiveAnalysis analysis(base, size, entry, 0);
RecursiveAnalysis analysis(base, size, entry, 0, true);
analysis.Analyse();
auto graph = analysis.GetFunctionGraph(entry);
if(!graph)
{
dputs(QT_TRANSLATE_NOOP("DBG", "No graph generated..."));
if(!silent)
dputs(QT_TRANSLATE_NOOP("DBG", "No graph generated..."));
return false;
}
auto graphList = graph->ToGraphList();

View File

@ -163,6 +163,7 @@ bool pluginload(const char* pluginName, bool loadall)
regExport("CBSAVEDB", CB_SAVEDB);
regExport("CBFILTERSYMBOL", CB_FILTERSYMBOL);
regExport("CBTRACEEXECUTE", CB_TRACEEXECUTE);
regExport("CBANALYZE", CB_ANALYZE);
//init plugin
if(!pluginData.pluginit(&pluginData.initStruct))
@ -489,15 +490,25 @@ bool pluginunregistercallback(int pluginHandle, CBTYPE cbType)
*/
void plugincbcall(CBTYPE cbType, void* callbackInfo)
{
SHARED_ACQUIRE(LockPluginCallbackList);
if(pluginCallbackList[cbType].empty())
return;
SHARED_ACQUIRE(LockPluginCallbackList);
auto cbList = pluginCallbackList[cbType]; //copy for thread-safety reasons
SHARED_RELEASE();
for(const auto & currentCallback : cbList)
currentCallback.cbPlugin(cbType, callbackInfo);
}
/**
\brief Checks if any callbacks are registered
\param cbType The type of the callback.
\return true if no callbacks are registered.
*/
bool plugincbempty(CBTYPE cbType)
{
return pluginCallbackList[cbType].empty();
}
/**
\brief Register a plugin command.
\param pluginHandle Handle of the plugin to register a command for.

View File

@ -62,6 +62,7 @@ void pluginexprfuncunregisterall(int pluginHandle);
void pluginregistercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin);
bool pluginunregistercallback(int pluginHandle, CBTYPE cbType);
void plugincbcall(CBTYPE cbType, void* callbackInfo);
bool plugincbempty(CBTYPE cbType);
bool plugincmdregister(int pluginHandle, const char* command, CBPLUGINCOMMAND cbCommand, bool debugonly);
bool plugincmdunregister(int pluginHandle, const char* command);
int pluginmenuadd(int hMenu, const char* title);

View File

@ -17,7 +17,8 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
disasm(ConfigUint("Disassembler", "MaxModuleSize")),
mCip(0),
mGoto(nullptr),
syncOrigin(false)
syncOrigin(false),
forceCenter(false)
{
this->status = "Loading...";
@ -606,7 +607,7 @@ void DisassemblerGraphView::mouseReleaseEvent(QMouseEvent* event)
void DisassemblerGraphView::mouseDoubleClickEvent(QMouseEvent* event)
{
duint instr = this->getInstrForMouseEvent(event);
DbgCmdExec(QString("graph dis.branchdest(%1), 1").arg(ToPtrString(instr)).toUtf8().constData());
DbgCmdExec(QString("graph dis.branchdest(%1), silent").arg(ToPtrString(instr)).toUtf8().constData());
}
void DisassemblerGraphView::prepareGraphNode(DisassemblerBlock & block)
@ -1199,7 +1200,10 @@ void DisassemblerGraphView::renderFunction(Function & func)
this->verticalScrollBar()->setValue(this->desired_pos[1]);
}
else if(this->cur_instr != 0)
this->show_cur_instr();
{
this->show_cur_instr(this->forceCenter);
this->forceCenter = false;
}
else
{
//Ensure start node is visible
@ -1245,7 +1249,7 @@ void DisassemblerGraphView::updateTimerEvent()
}
}
void DisassemblerGraphView::show_cur_instr()
void DisassemblerGraphView::show_cur_instr(bool force)
{
for(auto & blockIt : this->blocks)
{
@ -1261,8 +1265,8 @@ void DisassemblerGraphView::show_cur_instr()
QRect viewportRect = this->viewport()->rect();
QPoint translation(this->renderXOfs - xofs, this->renderYOfs - yofs);
viewportRect.translate(-translation.x(), -translation.y());
if(!viewportRect.contains(QRect(block.x + this->charWidth , block.y + this->charWidth,
block.width - (2 * this->charWidth), block.height - (2 * this->charWidth))))
if(force || !viewportRect.contains(QRect(block.x + this->charWidth , block.y + this->charWidth,
block.width - (2 * this->charWidth), block.height - (2 * this->charWidth))))
{
auto x = block.x + int(block.width / 2);
auto y = block.y + (2 * this->charWidth) + int((row + 0.5) * this->charHeight);
@ -1347,7 +1351,7 @@ void DisassemblerGraphView::loadCurrentGraph()
{
const BridgeCFNode & node = nodeIt.second;
Block block;
block.entry = node.start;
block.entry = node.instrs.empty() ? node.start : node.instrs[0].addr;
block.exits = node.exits;
block.false_path = node.brfalse;
block.true_path = node.brtrue;
@ -1439,16 +1443,17 @@ QString DisassemblerGraphView::getSymbolicName(duint addr)
void DisassemblerGraphView::loadGraphSlot(BridgeCFGraphList* graphList, duint addr)
{
currentGraph = BridgeCFGraph(graphList);
currentGraph = BridgeCFGraph(graphList, true);
currentBlockMap.clear();
loadCurrentGraph();
this->cur_instr = addr ? addr : this->function;
this->forceCenter = true;
loadCurrentGraph();
Bridge::getBridge()->setResult();
}
void DisassemblerGraphView::graphAtSlot(duint addr)
{
Bridge::getBridge()->setResult(this->navigate(addr));
Bridge::getBridge()->setResult(this->navigate(addr) ? this->currentGraph.entryPoint : 0);
}
void DisassemblerGraphView::updateGraphSlot()
@ -1471,7 +1476,7 @@ void DisassemblerGraphView::setupContextMenu()
mMenuBuilder->addAction(mToggleOverview = makeShortcutAction(DIcon("graph.png"), tr("&Overview"), SLOT(toggleOverviewSlot()), "ActionGraphToggleOverview"));
mMenuBuilder->addAction(mToggleSyncOrigin = makeShortcutAction(DIcon("lock.png"), tr("&Sync with origin"), SLOT(toggleSyncOriginSlot()), "ActionGraphSyncOrigin"));
mMenuBuilder->addAction(makeShortcutAction(DIcon("sync.png"), tr("&Refresh"), SLOT(loadCurrentGraph()), "ActionGraphRefresh"));
mMenuBuilder->addAction(makeShortcutAction(DIcon("sync.png"), tr("&Refresh"), SLOT(refreshSlot()), "ActionGraphRefresh"));
MenuBuilder* gotoMenu = new MenuBuilder(this);
gotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto.png"), tr("Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression"));
gotoMenu->addAction(makeShortcutAction(DIcon("cbp.png"), tr("Origin"), SLOT(gotoOriginSlot()), "ActionGotoOrigin"));
@ -1486,15 +1491,15 @@ void DisassemblerGraphView::keyPressEvent(QKeyEvent* event)
return;
int key = event->key();
if(key == Qt::Key_Up)
DbgCmdExec(QString("graph dis.prev(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
DbgCmdExec(QString("graph dis.prev(%1), silent").arg(ToPtrString(cur_instr)).toUtf8().constData());
else if(key == Qt::Key_Down)
DbgCmdExec(QString("graph dis.next(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
DbgCmdExec(QString("graph dis.next(%1), silent").arg(ToPtrString(cur_instr)).toUtf8().constData());
else if(key == Qt::Key_Left)
DbgCmdExec(QString("graph dis.brtrue(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
DbgCmdExec(QString("graph dis.brtrue(%1), silent").arg(ToPtrString(cur_instr)).toUtf8().constData());
else if(key == Qt::Key_Right)
DbgCmdExec(QString("graph dis.brfalse(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
DbgCmdExec(QString("graph dis.brfalse(%1), silent").arg(ToPtrString(cur_instr)).toUtf8().constData());
if(key == Qt::Key_Return || key == Qt::Key_Enter)
DbgCmdExec(QString("graph dis.branchdest(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
DbgCmdExec(QString("graph dis.branchdest(%1), silent").arg(ToPtrString(cur_instr)).toUtf8().constData());
}
void DisassemblerGraphView::followDisassemblerSlot()
@ -1575,13 +1580,13 @@ void DisassemblerGraphView::gotoExpressionSlot()
if(mGoto->exec() == QDialog::Accepted)
{
duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData());
DbgCmdExec(QString().sprintf("graph %p, 1", value).toUtf8().constData());
DbgCmdExec(QString().sprintf("graph %p, silent", value).toUtf8().constData());
}
}
void DisassemblerGraphView::gotoOriginSlot()
{
DbgCmdExec("graph cip, 1");
DbgCmdExec("graph cip, silent");
}
void DisassemblerGraphView::toggleSyncOriginSlot()
@ -1592,3 +1597,8 @@ void DisassemblerGraphView::toggleSyncOriginSlot()
if(syncOrigin)
gotoOriginSlot();
}
void DisassemblerGraphView::refreshSlot()
{
DbgCmdExec(QString("graph %1, force").arg(ToPtrString(this->cur_instr)).toUtf8().constData());
}

View File

@ -248,7 +248,7 @@ public:
int findVertEdgeIndex(EdgesVector & edges, int col, int min_row, int max_row);
DisassemblerEdge routeEdge(EdgesVector & horiz_edges, EdgesVector & vert_edges, Matrix<bool> & edge_valid, DisassemblerBlock & start, DisassemblerBlock & end, QColor color);
void renderFunction(Function & func);
void show_cur_instr();
void show_cur_instr(bool force = false);
bool navigate(duint addr);
void fontChanged();
QString getSymbolicName(duint addr);
@ -270,6 +270,7 @@ public slots:
void gotoExpressionSlot();
void gotoOriginSlot();
void toggleSyncOriginSlot();
void refreshSlot();
private:
QString status;
@ -305,6 +306,7 @@ private:
int overviewYOfs;
qreal overviewScale;
duint mCip;
bool forceCenter;
QAction* mToggleOverview;
QAction* mToggleSyncOrigin;