1
0
Fork 0

Merge pull request #476 from Herz3h/graph_ogdf_dev

Graph : Move controlFlowGraph into it's own class to allow for stuff …
This commit is contained in:
Duncan Ogilvie 2015-12-25 23:59:55 +01:00
commit b8f1ae0756
11 changed files with 611 additions and 552 deletions

View File

@ -1,7 +1,7 @@
#ifndef _GLOBAL_H
#define _GLOBAL_H
#define _WIN32_WINNT 0x0501
#define _WIN32_WINNT 0x0601
#define WINVER 0x0501
#define _WIN32_IE 0x0500

View File

@ -82,6 +82,7 @@ void ControlFlowAnalysis::Analyse()
dprintf("Analysis finished!\n");
// TODO : Fix this
PARENTMAP *_parentsTemp = new PARENTMAP(_parentMap);
BASICBLOCKMAP *_blocksTemp = new BASICBLOCKMAP(_blocks);

View File

@ -1414,6 +1414,7 @@ const dsint Disassembly::currentEIP() const
void Disassembly::disassembleAt(dsint parVA, dsint parCIP)
{
emit drawGraphAtAddress(parVA);
disassembleAt(parVA, parCIP, true, -1);
}

View File

@ -7,11 +7,11 @@ GraphNode::GraphNode() : QFrame()
}
GraphNode::GraphNode(std::vector<Instruction_t> &instructionsVector, duint address)
:
mAddress(address),
mInstructionsVector(instructionsVector),
mHighlightInstructionAt(-1)
{
mAddress = address;
mInstructionsVector = instructionsVector;
mHighlightInstructionAt = -1;
updateTokensVector();
setAttribute(Qt::WA_TranslucentBackground);

View File

@ -9,58 +9,59 @@ class Node
{
public:
explicit Node(ogdf::Graph* G, ogdf::GraphAttributes* GA, ogdf::node ogdfNode, T data)
{
this->_G = G;
this->_GA = GA;
this->_ogdfNode = ogdfNode;
this->_data = data;
this->_left = nullptr;
this->_right = nullptr;
}
:
mG(G),
mGA(GA),
mData(data),
mOgdfNode(ogdfNode),
mLeft(nullptr),
mRight(nullptr)
{}
Node<T>* setLeft(Node* left)
{
return left ? this->_left = makeNodeWithEdge(left) : nullptr;
return left ? mLeft = makeNodeWithEdge(left) : nullptr;
}
Node<T>* setRight(Node* right)
{
return right ? this->_right = makeNodeWithEdge(right) : nullptr;
return right ? mRight = makeNodeWithEdge(right) : nullptr;
}
Node<T>* setData(T data)
{
this->_data = data;
mData = data;
return this;
}
Node<T>* left()
Node<T>* left() const
{
return this->_left;
return mLeft;
}
Node<T>* right()
Node<T>* right() const
{
return this->_right;
return mRight;
}
T data()
T data() const
{
return this->_data;
return mData;
}
ogdf::node ogdfNode()
ogdf::node ogdfNode() const
{
return this->_ogdfNode;
return mOgdfNode;
}
private:
Node<T>* _left;
Node<T>* _right;
T _data;
ogdf::Graph* _G;
ogdf::GraphAttributes* _GA;
ogdf::node _ogdfNode;
T mData;
Node<T>* mLeft;
Node<T>* mRight;
ogdf::Graph* mG;
ogdf::GraphAttributes* mGA;
ogdf::node mOgdfNode;
Node* makeNodeWithEdge(Node<T>* node)
{
auto edge = this->_G->newEdge(this->_ogdfNode, node->_ogdfNode);
this->_GA->arrowType(edge) = ogdf::EdgeArrow::eaLast;
auto edge = mG->newEdge(mOgdfNode, node->mOgdfNode);
mGA->arrowType(edge) = ogdf::EdgeArrow::eaLast;
return node;
}
};

View File

@ -11,39 +11,36 @@
#include <ogdf/basic/GraphAttributes.h>
#include "Imports.h"
using namespace std;
template <typename T>
class Tree
{
public:
explicit Tree(ogdf::Graph* G, ogdf::GraphAttributes* GA)
{
this->_G = G;
this->_GA = GA;
}
explicit Tree(ogdf::Graph* G, ogdf::GraphAttributes* GA) : mG(G), mGA(GA)
{}
Node<T>* newNode(T data)
{
ogdf::node ogdfNode = _G->newNode();
Node<T> *node = new Node<T>(_G, _GA, ogdfNode, data);
_ogdfDataMap[ogdfNode] = node;
_nodePool.push_back(unique_ptr<Node<T>>(node));
ogdf::node ogdfNode = mG->newNode();
auto node = new Node<T>(mG, mGA, ogdfNode, data);
mOgdfDataMap[ogdfNode] = node;
mNodePool.push_back(std::unique_ptr<Node<T>>(node));
return node;
}
Node<T>* findNode(ogdf::node ogdfNode)
{
auto found = _ogdfDataMap.find(ogdfNode);
return found != _ogdfDataMap.end() ? found->second : nullptr;
auto found = mOgdfDataMap.find(ogdfNode);
return found != mOgdfDataMap.end() ? found->second : nullptr;
}
Node<T>* findNodeByAddress(duint address)
{
auto it = std::find_if(_ogdfDataMap.begin(), _ogdfDataMap.end(), [address](const pair<ogdf::node, Node<T>* > &itr)
auto it = std::find_if(mOgdfDataMap.begin(), mOgdfDataMap.end(), [address](const std::pair<ogdf::node, Node<T>* > &itr)
{
return itr.second->data()->address() == address;
return itr.second && itr.second->data() && itr.second->data()->address() == address;
});
// If found
if(it != _ogdfDataMap.end())
if(it != mOgdfDataMap.end())
{
return it->second;
}
@ -55,23 +52,18 @@ public:
void clear()
{
for(duint i=0; i < _nodePool.size(); i++)
_nodePool[i].reset();
for(duint i=0; i < mNodePool.size(); i++)
mNodePool[i].reset();
_nodePool.clear();
map<ogdf::node, Node<T>*>::iterator it = _ogdfDataMap.begin();
for(it; it != _ogdfDataMap.end(); it++)
delete it->second;
_ogdfDataMap.clear();
mNodePool.clear();
mOgdfDataMap.clear();
}
private:
ogdf::Graph* _G;
ogdf::GraphAttributes* _GA;
vector<unique_ptr<Node<T>>> _nodePool;
map<ogdf::node, Node<T>*> _ogdfDataMap;
ogdf::Graph* mG;
ogdf::GraphAttributes* mGA;
std::vector<std::unique_ptr<Node<T>>> mNodePool;
std::map<ogdf::node, Node<T>*> mOgdfDataMap;
};
#endif //_TREE_H

View File

@ -0,0 +1,408 @@
#include "ControlFlowGraph.h"
#include "Configuration.h"
void deleteGraphNodeVector(GRAPHNODEVECTOR* graphNodeVector)
{
for(auto& ptr : *graphNodeVector)
ptr->deleteLater();
}
ControlFlowGraph::ControlFlowGraph(QWidget *parent) : QWidget(parent),
mParentsInfo(nullptr),
mBasicBlockInfo(nullptr),
mDisas(new QBeaEngine(-1)),
mScene(new QGraphicsScene()),
mGraphicsView(new QGraphicsView()),
bProgramInitialized(false),
mVLayout(new QVBoxLayout()),
mGraphNodeVector(new GRAPHNODEVECTOR, deleteGraphNodeVector)
{
mScene->setBackgroundBrush(ConfigColor("DisassemblyBackgroundColor"));
mGraphicsView->setScene(mScene);
mVLayout->addWidget(mGraphicsView);
setLayout(mVLayout);
connect(Bridge::getBridge(), SIGNAL(setControlFlowInfos(duint*)), this, SLOT(setControlFlowInfosSlot(duint*)));
connect(Bridge::getBridge(), SIGNAL(disassembleAt(dsint,dsint)), this, SLOT(disassembleAtSlot(dsint, dsint)));
}
void ControlFlowGraph::startControlFlowAnalysis()
{
DbgCmdExec(QString("cfanalyze").toUtf8().constData());
}
void ControlFlowGraph::setUnconditionalBranchEdgeColor()
{
for(auto const &nodeGraphEdge : mNodeGraphEdge)
{
if(nodeGraphEdge.second.size() == 1)
nodeGraphEdge.second.at(0)->setEdgeColor(Qt::blue);
}
}
ControlFlowGraph::~ControlFlowGraph()
{
mGraphNodeVector.reset();
mGraphicsView->deleteLater();
mScene->deleteLater();
mVLayout->deleteLater();
mTree.reset();
mOHL.reset();
mSL.reset();
mGA.reset();
delete mBasicBlockInfo;
delete mParentsInfo;
delete mDisas;
}
void ControlFlowGraph::setupGraph()
{
using namespace ogdf;
using namespace std;
//initialize graph
mGA = make_unique<GraphAttributes>(mG, GraphAttributes::nodeGraphics |
GraphAttributes::edgeGraphics |
GraphAttributes::nodeLabel |
GraphAttributes::nodeStyle |
GraphAttributes::edgeType |
GraphAttributes::edgeArrow |
GraphAttributes::edgeStyle);
//add nodes
mTree = make_unique<Tree<GraphNode*>>(&mG, mGA.get());
setupTree();
addGraphToScene();
// Make sure there is some spacing
QRectF sceneRect = mGraphicsView->sceneRect();
sceneRect.adjust(-20, -20, 20, 20);
mGraphicsView->setSceneRect(sceneRect);
mGraphicsView->show();
}
void ControlFlowGraph::setupTree(duint va)
{
using namespace ogdf;
using namespace std;
QTextStream out(stdout);
BASICBLOCKMAP::iterator it;
std::vector<Instruction_t> instructionsVector;
// Clear graph and tree
mG.clear();
mTree->clear();
mGraphNodeVector->clear();
if(!va)
it = mBasicBlockInfo->begin();
else
it = mBasicBlockInfo->find(va);
// Couldn't find the basic block of the VA
if(it == mBasicBlockInfo->end())
return;
// Disassemble the instruction at the address
readBasicBlockInstructions(it, instructionsVector);
// Add root node first
duint addr = it->first;
mGraphNodeVector->push_back( make_unique<GraphNode>(instructionsVector, addr) );
connect(mGraphNodeVector->back().get(), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
Node<GraphNode *> *rootNode = mTree->newNode(mGraphNodeVector->back().get());
addAllNodes(it, rootNode);
}
void ControlFlowGraph::setupGraphLayout()
{
using namespace ogdf;
using namespace std;
// TODO : Better way to do this
if(mOHL.get() && mSL.get())
{
mSL->call(*mGA);
return;
}
mOHL = make_unique<OptimalHierarchyLayout>();
mOHL->nodeDistance(25.0);
mOHL->layerDistance(50.0);
mOHL->fixedLayerDistance(false);
mOHL->weightBalancing(0.0);
mOHL->weightSegments(0.0);
mSL = make_unique<SugiyamaLayout>();
mSL->setRanking(new OptimalRanking);
mSL->setCrossMin(new MedianHeuristic);
mSL->alignSiblings(false);
mSL->setLayout(mOHL.get());
mSL->call(*mGA);
}
void ControlFlowGraph::adjustNodesSize()
{
// Adjust node size
ogdf::node v;
forall_nodes(v, mG)
{
Node<GraphNode* > *node = mTree->findNode(v);
if (node)
{
QRectF rect = node->data()->boundingRect();
mGA->width(v) = rect.width();
mGA->height(v) = rect.height();
}
}
}
void ControlFlowGraph::addGraphToScene()
{
using namespace ogdf;
mNodeGraphEdge.clear();
mScene->clear();
adjustNodesSize();
// Apply the graph layout after we've set the nodes sizes
setupGraphLayout();
addNodesToScene();
addEdgesToScene();
// Change unconditionalBranches colors to something different than for conditional branches
setUnconditionalBranchEdgeColor();
mGraphicsView->ensureVisible(mScene->itemsBoundingRect());
// Make sure there is some spacing
mScene->sceneRect().adjust(-20, -20, 20, 20);
mGraphicsView->setSceneRect(mScene->sceneRect());
}
void ControlFlowGraph::addNodesToScene()
{
ogdf::node v;
forall_nodes(v, mG)
{
Node<GraphNode* > *node = mTree->findNode(v);
if (node)
{
//draw node using x,y
QRectF rect = node->data()->boundingRect();
qreal x = mGA->x(v) - (rect.width()/2);
qreal y = mGA->y(v) - (rect.height()/2);
node->data()->setGeometry(x, y, rect.width(), rect.height());
mScene->addWidget(node->data());
}
}
}
void ControlFlowGraph::addEdgesToScene()
{
//draw edges
ogdf::edge e;
forall_edges(e, mG)
{
const auto bends = mGA->bends(e);
const auto source = e->source();
const auto target = e->target();
GraphNode* sourceGraphNode = mTree->findNode(source)->data();
GraphNode* targetGraphNode = mTree->findNode(target)->data();
QRectF sourceRect = sourceGraphNode->geometry();
QRectF targetRect = targetGraphNode->geometry();
sourceRect.adjust(-4, -4, 4, 4);
targetRect.adjust(-4, -4, 4, 4);
QPointF start(mGA->x(source), mGA->y(source));
QPointF end(mGA->x(target), mGA->y(target));
GraphEdge* edge = nullptr;
auto const sourceNodeLeft = mTree->findNode(source)->left();
if(sourceNodeLeft && sourceNodeLeft->data()->address() == targetGraphNode->address())
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, GraphEdge::EDGE_LEFT);
else
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, GraphEdge::EDGE_RIGHT);
mNodeGraphEdge[source].push_back(std::unique_ptr<GraphEdge>(edge));
mScene->addItem(edge);
}
}
void ControlFlowGraph::addAllNodes(BASICBLOCKMAP::iterator it, Node<GraphNode *> *parentNode)
{
using namespace std;
QByteArray byteArray(MAX_STRING_SIZE, 0);
duint left = it->second.left; // Left child addr
duint right = it->second.right; // Right child addr
// No childs
if(!left && !right)
return;
for(int i=0; i < 2; i++)
{
// If not left or right child continue..
if((i == 0 && !left) || (i == 1 && !right))
continue;
BASICBLOCKMAP::iterator itChild;
Node<GraphNode*>* node = nullptr;
// Left
if(i == 0)
{
itChild = mBasicBlockInfo->find(left);
node = mTree->findNodeByAddress(left);
}
//Right
else
{
itChild = mBasicBlockInfo->find(right);
node = mTree->findNodeByAddress(right);
}
// If we found the basicblock for left or right
if(itChild != mBasicBlockInfo->end())
{
duint childNodeAddr;
if(i == 0) // Add node to left of parentNode
childNodeAddr = left;
else // Add node to right of parentNode
childNodeAddr = right;
// Node does not exist, create it
if(node == nullptr)
{
std::vector<Instruction_t> instructionsVector;
readBasicBlockInstructions(itChild, instructionsVector);
mGraphNodeVector->push_back( make_unique<GraphNode>(instructionsVector, childNodeAddr) );
node = mTree->newNode(mGraphNodeVector->back().get());
connect(mGraphNodeVector->back().get(), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
}
Node<GraphNode*>* newParentNode = nullptr;
Node <GraphNode*>* parentNodeLeftRight = nullptr;
if(i == 0)
parentNodeLeftRight = parentNode->left();
else
parentNodeLeftRight = parentNode->right();
// Edge already exists between parentNode and left / right, we've been here before..
if(parentNodeLeftRight && (parentNodeLeftRight->data()->address() == left || parentNodeLeftRight->data()->address() == right))
return;
if(i == 0)
newParentNode = parentNode->setLeft(node);
else
newParentNode = parentNode->setRight(node);
addAllNodes(itChild, newParentNode);
}
}
}
void ControlFlowGraph::setControlFlowInfosSlot(duint *controlFlowInfos)
{
if(controlFlowInfos)
{
mParentsInfo = (PARENTMAP*)(((CONTROLFLOWINFOS*)controlFlowInfos)->parents);
mBasicBlockInfo = (BASICBLOCKMAP*)(((CONTROLFLOWINFOS*)controlFlowInfos)->blocks);
setupGraph();
}
}
bool ControlFlowGraph::findBasicBlock(duint& va)
{
if(mBasicBlockInfo == nullptr)
return false;
if(!mBasicBlockInfo->size())
return false;
bool bFound = false;
BASICBLOCKMAP::iterator it = mBasicBlockInfo->find(va);
// If the block was not found by addr, check if it belongs to a basic block
if(it == mBasicBlockInfo->end())
{
for(it = mBasicBlockInfo->begin(); it != mBasicBlockInfo->end(); it++)
{
if(va >= it->second.start && va <= it->second.end)
{
va = it->first;
bFound = true;
break;
}
}
}
else
bFound = true;
return bFound;
}
void ControlFlowGraph::readBasicBlockInstructions(BASICBLOCKMAP::iterator it, std::vector<Instruction_t> &instructionsVector)
{
duint addr = it->first;
duint startAddr = it->second.start;
duint endAddr = it->second.end;
duint baseAddr = DbgMemFindBaseAddr(addr, 0);
QByteArray byteArray(MAX_STRING_SIZE, 0);
// Read basic block instructions
for(startAddr; startAddr <= endAddr;)
{
if(!DbgMemRead(startAddr, reinterpret_cast<unsigned char*>(byteArray.data()), 16))
return;
// Add instruction to the vector
Instruction_t wInstruction = mDisas->DisassembleAt(reinterpret_cast<byte_t*>(byteArray.data()), byteArray.length(), 0, baseAddr, startAddr-baseAddr);
instructionsVector.push_back(wInstruction);
startAddr += wInstruction.length;
}
}
void ControlFlowGraph::drawGraphAtSlot(duint va)
{
bool bFound = findBasicBlock(va);
if(!bFound)
return;
setupTree(va);
addGraphToScene();
}

View File

@ -0,0 +1,107 @@
#ifndef CONTROLFLOWGRAPH_H
#define CONTROLFLOWGRAPH_H
#include <set>
#include <map>
#include <QWidget>
#include <QWheelEvent>
#include <QGraphicsScene>
#include <QGraphicsView>
#include "Bridge.h"
#include "Tree.h"
#include "GraphNode.h"
#include "GraphEdge.h"
#include "QBeaEngine.h"
#include "capstone_gui.h"
#include <ogdf/fileformats/GraphIO.h>
#include <ogdf/layered/SugiyamaLayout.h>
#include <ogdf/layered/OptimalRanking.h>
#include <ogdf/layered/MedianHeuristic.h>
#include <ogdf/layered/OptimalHierarchyLayout.h>
struct BasicBlock
{
duint start;
duint end;
duint left;
duint right;
duint function;
BasicBlock()
{
this->start = 0;
this->end = 0;
this->left = 0;
this->right = 0;
this->function = 0;
}
BasicBlock(duint start, duint end, duint left, duint right)
{
this->start = start;
this->end = end;
this->left = std::min(left, right);
this->right = std::max(left, right);
this->function = 0;
}
std::string toString()
{
char buffer[MAX_STRING_SIZE];
sprintf_s(buffer, "start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
return std::string(buffer);
}
};
typedef std::map<duint, BasicBlock> BASICBLOCKMAP;
typedef std::map<duint, std::set<duint> > PARENTMAP;
typedef std::map<duint, Node<GraphNode *> * > NODEMAP;
typedef std::vector<std::unique_ptr<GraphNode>> GRAPHNODEVECTOR;
typedef std::map<ogdf::node, std::vector<std::unique_ptr<GraphEdge>> > GRAPHEDGEMAP;
class ControlFlowGraph : public QWidget
{
Q_OBJECT
public:
explicit ControlFlowGraph(QWidget *parent = 0);
void startControlFlowAnalysis();
void setUnconditionalBranchEdgeColor();
~ControlFlowGraph();
private:
void setupGraph();
void setupGraphLayout();
void setupTree(duint va = 0);
void adjustNodesSize();
void addGraphToScene();
void addNodesToScene();
void addEdgesToScene();
void addAllNodes(BASICBLOCKMAP::iterator it, Node<GraphNode *> *parentNode);
bool findBasicBlock(duint& va);
void readBasicBlockInstructions(BASICBLOCKMAP::iterator it, std::vector<Instruction_t>& instructionsVector);
public slots:
void drawGraphAtSlot(duint va);
void setControlFlowInfosSlot(duint *controlFlowInfos);
private:
bool bProgramInitialized;
QBeaEngine *mDisas;
PARENTMAP *mParentsInfo;
BASICBLOCKMAP *mBasicBlockInfo;
std::unique_ptr<GRAPHNODEVECTOR, std::function<void(GRAPHNODEVECTOR*)>> mGraphNodeVector;
GRAPHEDGEMAP mNodeGraphEdge;
ogdf::Graph mG;
std::unique_ptr<ogdf::GraphAttributes> mGA;
std::unique_ptr<ogdf::SugiyamaLayout> mSL;
std::unique_ptr<ogdf::OptimalHierarchyLayout> mOHL;
std::unique_ptr<Tree<GraphNode*>> mTree;
QVBoxLayout *mVLayout;
QGraphicsScene *mScene;
QGraphicsView *mGraphicsView;
};
#endif // CONTROLFLOWGRAPH_H

View File

@ -1,429 +1,56 @@
#include "GraphView.h"
#include "ui_GraphView.h"
#include "Configuration.h"
#include <QDebug>
void deleteControlFlowGraph(ControlFlowGraph* ctrlFlowGraph)
{
ctrlFlowGraph->deleteLater();
}
GraphView::GraphView(QWidget *parent) :
QWidget(parent),
ui(new Ui::GraphView)
bProgramInitialized(false),
mVLayout(new QVBoxLayout()),
mControlFlowGraph(new ControlFlowGraph, deleteControlFlowGraph)
{
ui->setupUi(this);
mG = nullptr;
mGA = nullptr;
mSL = nullptr;
mOHL = nullptr;
mTree = nullptr;
mDisas = new QBeaEngine(-1);
mScene = new QGraphicsScene(this);
mParentsInfo = nullptr;
mBasicBlockInfo = nullptr;
mGraphNodeVector = new GRAPHNODEVECTOR;
// mNodeGraphEdge = new GRAPHEDGEMAP;
bProgramInitialized = false;
mVLayout->addWidget(mControlFlowGraph.get());
setLayout(mVLayout);
mScene->setBackgroundBrush(ConfigColor("DisassemblyBackgroundColor"));
// ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
// ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
ui->graphicsView->setScene(mScene);
connect(mScene, SIGNAL(changed(QList<QRectF>)), this, SLOT(sceneChangedSlot(QList<QRectF>)));
connect(Bridge::getBridge(), SIGNAL(setControlFlowInfos(duint*)), this, SLOT(setControlFlowInfosSlot(duint*)));
connect(Bridge::getBridge(), SIGNAL(disassembleAt(dsint,dsint)), this, SLOT(disassembleAtSlot(dsint, dsint)));
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(dbgStateChangedSlot(DBGSTATE)));
}
void GraphView::startControlFlowAnalysis()
{
DbgCmdExec(QString("cfanalyze").toUtf8().constData());
}
void GraphView::showEvent(QShowEvent *event)
{
// ui->graphicsView->fitInView(mScene->itemsBoundingRect(), Qt::KeepAspectRatio);
}
void GraphView::setUnconditionalBranchEdgeColor()
{
for(auto const &nodeGraphEdge : mNodeGraphEdge)
{
if(nodeGraphEdge.second.size() == 1)
nodeGraphEdge.second.at(0)->setEdgeColor(Qt::blue);
}
}
void GraphView::setupGraph()
{
using namespace ogdf;
//initialize graph
mG = new Graph;
mGA = new GraphAttributes(*mG, GraphAttributes::nodeGraphics |
GraphAttributes::edgeGraphics |
GraphAttributes::nodeLabel |
GraphAttributes::nodeStyle |
GraphAttributes::edgeType |
GraphAttributes::edgeArrow |
GraphAttributes::edgeStyle);
//add nodes
mTree = new Tree<GraphNode*>(mG, mGA);
setupTree();
addGraphToScene();
//make sure there is some spacing
QRectF sceneRect = ui->graphicsView->sceneRect();
sceneRect.adjust(-20, -20, 20, 20);
ui->graphicsView->setSceneRect(sceneRect);
ui->graphicsView->show();
}
void GraphView::setupTree(duint va)
{
using namespace ogdf;
QTextStream out(stdout);
BASICBLOCKMAP::iterator it;
QByteArray byteArray(MAX_STRING_SIZE, 0);
std::vector<Instruction_t> instructionsVector;
// Clear graph and tree
mG->clear();
mTree->clear();
if(!va)
it = mBasicBlockInfo->begin();
else
it = mBasicBlockInfo->find(va);
// Couldn't find the basic block of the VA
if(it == mBasicBlockInfo->end())
return;
// Disassemble the instruction at the address
duint addr = it->first;
duint startAddr = it->second.start;
duint endAddr = it->second.end;
duint baseAddr = DbgMemFindBaseAddr(addr, 0);
// Read basic block instructions
for(startAddr; startAddr <= endAddr;)
{
if(!DbgMemRead(startAddr, (unsigned char*)byteArray.data(), 16))
return;
Instruction_t wInstruction = mDisas->DisassembleAt((byte_t*)byteArray.data(), byteArray.length(), 0, baseAddr, startAddr-baseAddr);
// Add instruction to the vector
instructionsVector.push_back(wInstruction);
startAddr += wInstruction.length;
}
// Add root node first
mGraphNodeVector->push_back(new GraphNode(instructionsVector, addr));
connect(mGraphNodeVector->back(), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
Node<GraphNode *> *rootNode = mTree->newNode(mGraphNodeVector->back());
addAllNodes(it, rootNode);
}
void GraphView::setupGraphLayout()
{
using namespace ogdf;
// TODO : Better way to do this
if(mOHL && mSL)
{
mSL->call(*mGA);
return;
}
mOHL = new OptimalHierarchyLayout;
mOHL->nodeDistance(25.0);
mOHL->layerDistance(50.0);
mOHL->fixedLayerDistance(false);
mOHL->weightBalancing(0.0);
mOHL->weightSegments(0.0);
mSL = new SugiyamaLayout;
mSL->setRanking(new OptimalRanking);
mSL->setCrossMin(new MedianHeuristic);
mSL->alignSiblings(false);
mSL->setLayout(mOHL);
mSL->call(*mGA);
}
void GraphView::addGraphToScene()
{
using namespace ogdf;
mNodeGraphEdge.clear();
mScene->clear();
// adjust node size
node v;
forall_nodes(v, *mG)
{
Node<GraphNode* > *node = mTree->findNode(v);
if (node)
{
QRectF rect = node->data()->boundingRect();
mGA->width(v) = rect.width();
mGA->height(v) = rect.height();
}
}
// Apply the graph layout after we've set the nodes sizes
setupGraphLayout();
//draw widget contents (nodes)
forall_nodes(v, *mG)
{
Node<GraphNode* > *node = mTree->findNode(v);
if (node)
{
//draw node using x,y
QRectF rect = node->data()->boundingRect();
qreal x = mGA->x(v) - (rect.width()/2);
qreal y = mGA->y(v) - (rect.height()/2);
node->data()->setGeometry(x, y, rect.width(), rect.height());
mScene->addWidget(node->data());
}
}
//draw edges
edge e;
forall_edges(e, *mG)
{
const auto bends = mGA->bends(e);
const auto source = e->source();
const auto target = e->target();
GraphNode* sourceGraphNode = mTree->findNode(source)->data();
GraphNode* targetGraphNode = mTree->findNode(target)->data();
QRectF sourceRect = sourceGraphNode->geometry();
sourceRect.adjust(-4, -4, 4, 4);
QRectF targetRect = targetGraphNode->geometry();
targetRect.adjust(-4, -4, 4, 4);
QPointF start(mGA->x(source), mGA->y(source));
QPointF end(mGA->x(target), mGA->y(target));
GraphEdge* edge = nullptr;
if(mTree->findNode(source)->left() && mTree->findNode(source)->left()->data()->address() == targetGraphNode->address())
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, GraphEdge::EDGE_LEFT);
else
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, GraphEdge::EDGE_RIGHT);
mNodeGraphEdge[source].push_back(edge);
mScene->addItem(edge);
}
// Change unconditionalBranches colors to something different than for conditional branches
setUnconditionalBranchEdgeColor();
ui->graphicsView->ensureVisible(mScene->itemsBoundingRect());
ui->graphicsView->setSceneRect(mScene->sceneRect());
}
void GraphView::addAllNodes(BASICBLOCKMAP::iterator it, Node<GraphNode *> *parentNode)
{
QTextStream out(stdout);
QByteArray byteArray(MAX_STRING_SIZE, 0);
duint addr = it->first; // Parent Basic Block addr
duint left = it->second.left; // Left child addr
duint right = it->second.right; // Right child addr
// No childs
if(!left && !right)
return;
for(int i=0; i < 2; i++)
{
if((i == 0 && !left) || (i == 1 && !right))
continue;
BASICBLOCKMAP::iterator itChild;
Node<GraphNode *> *node = nullptr;
// Left
if(i == 0)
{
itChild = mBasicBlockInfo->find(left);
node = mTree->findNodeByAddress(left);
}
//Right
else
{
itChild = mBasicBlockInfo->find(right);
node = mTree->findNodeByAddress(right);
}
// If we found the basicblock for left or right
if(itChild != mBasicBlockInfo->end())
{
std::vector<Instruction_t> instructionsVector;
// If the Node doesn't exist yet;
if(node == nullptr)
{
duint startAddr = itChild->second.start;
duint endAddr = itChild->second.end;
// BaseAddr..
duint baseAddr = DbgMemFindBaseAddr(addr, 0);
// Disassemble the BasicBlock instructions
for(startAddr; startAddr <= endAddr;)
{
DbgMemRead(startAddr, (unsigned char*)byteArray.data(), 16);
Instruction_t wInstruction = mDisas->DisassembleAt((byte_t*)byteArray.data(), MAX_STRING_SIZE,0, baseAddr, startAddr-baseAddr);
instructionsVector.push_back(wInstruction);
startAddr += wInstruction.length;
}
}
// Add node to left of parentNode
if(i == 0)
{
// Node does not exist, create it
if(node == nullptr)
{
mGraphNodeVector->push_back(new GraphNode(instructionsVector, left));
node = mTree->newNode(mGraphNodeVector->back());
connect(mGraphNodeVector->back(), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
}
Node<GraphNode *> *newParentNode = nullptr;
// Edge already exists between parentNode and left / right, we've been here before..
if(parentNode->left() && (parentNode->left()->data()->address() == left || parentNode->left()->data()->address() == right))
return;
else
newParentNode = parentNode->setLeft(node);
addAllNodes(itChild, newParentNode);
}
// Add node to right of parentNode
else if(i == 1)
{
// Node does not exist, create it
if(node == nullptr)
{
mGraphNodeVector->push_back(new GraphNode(instructionsVector, right));
node = mTree->newNode(mGraphNodeVector->back());
connect((GraphNode*)(mGraphNodeVector->back()), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
}
Node<GraphNode *> *newParentNode = nullptr;
// Edge already exists between parentNode and left / right
if(parentNode->right() && (parentNode->right()->data()->address() == right || parentNode->right()->data()->address() == left))
return;
else
newParentNode = parentNode->setRight(node);
addAllNodes(itChild, newParentNode);
}
}
}
}
GraphView::~GraphView()
{
mScene->clear();
if(mOHL)
delete mOHL;
if(mSL)
delete mSL;
if(mTree)
mTree->clear();
if(mG)
delete mG;
if(mGA)
delete mGA;
delete ui;
mVLayout->deleteLater();
}
void GraphView::setControlFlowInfosSlot(duint *controlFlowInfos)
void GraphView::drawGraphAtSlot(duint va)
{
if(controlFlowInfos)
// TODO : Fix this, start analysis from debugger rather than from GUI
if(!bProgramInitialized)
{
mParentsInfo = (PARENTMAP*)(((CONTROLFLOWINFOS*)controlFlowInfos)->parents);
mBasicBlockInfo = (BASICBLOCKMAP*)(((CONTROLFLOWINFOS*)controlFlowInfos)->blocks);
setupGraph();
mControlFlowGraph->startControlFlowAnalysis();
bProgramInitialized = true;
}
mControlFlowGraph->drawGraphAtSlot(va);
}
void GraphView::dbgStateChangedSlot(DBGSTATE state)
{
if(state == initialized)
{
if(mControlFlowGraph.get() == nullptr)
mControlFlowGraph = std::make_unique<ControlFlowGraph>();
mVLayout->addWidget(mControlFlowGraph.get());
}
else if(state == stopped)
{
mVLayout->removeWidget(mControlFlowGraph.get());
mControlFlowGraph.reset();
bProgramInitialized = false;
}
bool GraphView::findBasicBlock(duint &va)
{
if(!mBasicBlockInfo)
return false;
if(!mBasicBlockInfo->size())
return false;
bool bFound = false;
BASICBLOCKMAP::iterator it = mBasicBlockInfo->find(va);
// If the block was not found by addr, check if it belongs to a basic block
if(it == mBasicBlockInfo->end())
{
for(it = mBasicBlockInfo->begin(); it != mBasicBlockInfo->end(); it++)
{
if(va >= it->second.start && va <= it->second.end)
{
va = it->first;
bFound = true;
break;
}
}
}
else
bFound = true;
return bFound;
}
void GraphView::drawGraphAtSlot(duint va)
{
bool bFound = findBasicBlock(va);
if(!bFound)
return;
setupTree(va);
addGraphToScene();
}
void GraphView::disassembleAtSlot(dsint parVA, dsint CIP)
{
Q_UNUSED(CIP)
Q_UNUSED(parVA)
if(!bProgramInitialized)
{
startControlFlowAnalysis();
bProgramInitialized = true;
}
}

View File

@ -1,68 +1,9 @@
#ifndef GRAPHVIEW_H
#define GRAPHVIEW_H
#include <set>
#include <map>
#include <QWidget>
#include <QWheelEvent>
#include <QGraphicsScene>
#include "QBeaEngine.h"
#include "Bridge.h"
#include "Tree.h"
#include "GraphNode.h"
#include "capstone_gui.h"
#include <ogdf/fileformats/GraphIO.h>
#include <ogdf/layered/SugiyamaLayout.h>
#include <ogdf/layered/OptimalRanking.h>
#include <ogdf/layered/MedianHeuristic.h>
#include <ogdf/layered/OptimalHierarchyLayout.h>
#include "GraphEdge.h"
namespace Ui
{
class GraphView;
}
struct BasicBlock
{
duint start;
duint end;
duint left;
duint right;
duint function;
BasicBlock()
{
this->start = 0;
this->end = 0;
this->left = 0;
this->right = 0;
this->function = 0;
}
BasicBlock(duint start, duint end, duint left, duint right)
{
this->start = start;
this->end = end;
this->left = std::min(left, right);
this->right = std::max(left, right);
this->function = 0;
}
std::string toString()
{
char buffer[MAX_STRING_SIZE];
sprintf_s(buffer, "start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
return std::string(buffer);
}
};
typedef std::map<duint, BasicBlock> BASICBLOCKMAP; //start of block -> block
typedef std::map<duint, std::set<duint> > PARENTMAP; //start child -> parents
typedef std::vector<GraphNode* > GRAPHNODEVECTOR;
typedef std::map<duint, Node<GraphNode *> * > NODEMAP;
typedef std::map<ogdf::node, std::vector<GraphEdge *> > GRAPHEDGEMAP;
#include <QVBoxLayout>
#include "ControlFlowGraph.h"
class GraphView : public QWidget
{
@ -70,37 +11,16 @@ class GraphView : public QWidget
public:
explicit GraphView(QWidget *parent = 0);
void startControlFlowAnalysis();
void showEvent(QShowEvent *event);
void setUnconditionalBranchEdgeColor();
~GraphView();
public slots:
void drawGraphAtSlot(duint va);
void disassembleAtSlot(dsint parVA, dsint CIP);
void setControlFlowInfosSlot(duint *controlFlowInfos);
void dbgStateChangedSlot(DBGSTATE state);
void drawGraphAtSlot(duint va);
private:
void setupGraph();
void setupGraphLayout();
void setupTree(duint va = 0);
void addGraphToScene();
void addAllNodes(BASICBLOCKMAP::iterator it, Node<GraphNode *> *parentNode);
bool findBasicBlock(duint &va);
QBeaEngine *mDisas;
PARENTMAP *mParentsInfo;
BASICBLOCKMAP *mBasicBlockInfo;
GRAPHNODEVECTOR *mGraphNodeVector;
GRAPHEDGEMAP mNodeGraphEdge;
ogdf::Graph *mG;
ogdf::GraphAttributes *mGA;
ogdf::SugiyamaLayout *mSL;
ogdf::OptimalHierarchyLayout *mOHL;
QGraphicsScene *mScene;
Tree<GraphNode*> *mTree;
Ui::GraphView *ui;
QVBoxLayout *mVLayout;
bool bProgramInitialized;
std::unique_ptr<ControlFlowGraph, std::function<void(ControlFlowGraph *ctrlFlowGraph)>> mControlFlowGraph;
};
#endif // GRAPHVIEW_H

View File

@ -151,7 +151,8 @@ SOURCES += \
Src/Graph/QGraphScene.cpp \
Src/Graph/QGraphView.cpp \
Src/Graph/GraphEdge.cpp \
Src/Graph/GraphNode.cpp
Src/Graph/GraphNode.cpp \
Src/Gui/ControlFlowGraph.cpp
HEADERS += \
@ -242,7 +243,8 @@ HEADERS += \
Src/Graph/Tree.h \
Src/Gui/GraphView.h \
Src/Graph/QGraphScene.h \
Src/Graph/QGraphView.h
Src/Graph/QGraphView.h \
Src/Gui/ControlFlowGraph.h
FORMS += \
Src/Gui/MainWindow.ui \
@ -281,11 +283,11 @@ LIBS += -luser32
LIBS += -L"$$PWD/../dbg/capstone/" -lcapstone_x86
LIBS += -L"$$PWD/Src/ThirdPartyLibs/snowman/" -lsnowman_x86
LIBS += -L"$${X64_BIN_DIR}/" -lx32bridge -lcapstone_wrapper
LIBS += -L"$${OGDF_BIN_DIR}/" -logdf
LIBS += -L"$${OGDF_BIN_DIR}/" -logdf -lcoin
} else {
# Windows x64 (64bit) specific build
LIBS += -L"$$PWD/../dbg/capstone/" -lcapstone_x64
LIBS += -L"$$PWD/Src/ThirdPartyLibs/snowman/" -lsnowman_x64
LIBS += -L"$${X64_BIN_DIR}/" -lx64bridge -lcapstone_wrapper
LIBS += -L"$${OGDF_BIN_DIR}/" -logdf
LIBS += -L"$${OGDF_BIN_DIR}/" -logdf -lcoin
}