1
0
Fork 0

GUI: added a very simple entropy graph in the dump (selection), memory map (page) and symbol view (file)

This commit is contained in:
Mr. eXoDia 2015-08-14 02:17:46 +02:00
parent 0c80b46056
commit fd044407a7
15 changed files with 359 additions and 4 deletions

View File

@ -7,6 +7,7 @@
#include "HexEditDialog.h"
#include "YaraRuleSelectionDialog.h"
#include "DataCopyDialog.h"
#include "EntropyDialog.h"
CPUDump::CPUDump(CPUDisassembly* disas, QWidget* parent) : HexDump(parent)
{
@ -158,6 +159,10 @@ void CPUDump::setupContextMenu()
#endif //_WIN64
connect(mFollowDataDump, SIGNAL(triggered()), this, SLOT(followDataDumpSlot()));
//Entropy
mEntropy = new QAction(QIcon(":/icons/images/entropy.png"), "Entropy...", this);
connect(mEntropy, SIGNAL(triggered()), this, SLOT(entropySlot()));
//Label
mSetLabelAction = new QAction("Set Label", this);
mSetLabelAction->setShortcutContext(Qt::WidgetShortcut);
@ -536,6 +541,7 @@ void CPUDump::contextMenuEvent(QContextMenuEvent* event)
wMenu->addAction(mYaraAction);
wMenu->addAction(mDataCopyAction);
wMenu->addMenu(mGotoMenu);
wMenu->addAction(mEntropy);
wMenu->addSeparator();
wMenu->addMenu(mHexMenu);
wMenu->addMenu(mTextMenu);
@ -1447,3 +1453,18 @@ void CPUDump::dataCopySlot()
DataCopyDialog dataDialog(&data, this);
dataDialog.exec();
}
void CPUDump::entropySlot()
{
int_t selStart = getSelectionStart();
int_t selSize = getSelectionEnd() - selStart + 1;
QVector<byte_t> data;
data.resize(selSize);
mMemPage->read(data.data(), selStart, selSize);
EntropyDialog entropyDialog(this);
entropyDialog.setWindowTitle(QString().sprintf("Entropy (Address: %p, Size: %p)", selStart, selSize));
entropyDialog.show();
entropyDialog.GraphMemory(data.constData(), data.size());
entropyDialog.exec();
}

View File

@ -86,6 +86,7 @@ public slots:
void selectionUpdatedSlot();
void yaraSlot();
void dataCopySlot();
void entropySlot();
private:
QMenu* mBreakpointMenu;
@ -175,6 +176,7 @@ private:
QAction* mUndoSelection;
QAction* mFollowData;
QAction* mFollowDataDump;
QAction* mEntropy;
QMenu* mSpecialMenu;
QMenu* mCustomMenu;

View File

@ -0,0 +1,42 @@
#include "EntropyDialog.h"
#include "ui_EntropyDialog.h"
EntropyDialog::EntropyDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::EntropyDialog)
{
ui->setupUi(this);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint);
#endif
setFixedSize(this->size()); //fixed size
mBlockSize = 128;
mPointCount = 300;
mInitialized = false;
}
EntropyDialog::~EntropyDialog()
{
delete ui;
}
void EntropyDialog::GraphMemory(const unsigned char* data, int dataSize, QColor color)
{
initializeGraph();
ui->entropyView->GraphMemory(data, dataSize, mBlockSize, mPointCount, color);
}
void EntropyDialog::GraphFile(const QString & fileName, QColor color)
{
initializeGraph();
ui->entropyView->GraphFile(fileName, mBlockSize, mPointCount, color);
}
void EntropyDialog::initializeGraph()
{
if(mInitialized)
return;
mInitialized = true;
ui->entropyView->InitializeGraph();
}

View File

@ -0,0 +1,30 @@
#ifndef ENTROPYDIALOG_H
#define ENTROPYDIALOG_H
#include <QDialog>
namespace Ui
{
class EntropyDialog;
}
class EntropyDialog : public QDialog
{
Q_OBJECT
public:
explicit EntropyDialog(QWidget* parent = 0);
~EntropyDialog();
void GraphMemory(const unsigned char* data, int dataSize, QColor color = Qt::darkGreen);
void GraphFile(const QString & fileName, QColor color = Qt::darkGreen);
private:
Ui::EntropyDialog* ui;
int mBlockSize;
int mPointCount;
bool mInitialized;
void initializeGraph();
};
#endif // ENTROPYDIALOG_H

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EntropyDialog</class>
<widget class="QDialog" name="EntropyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>744</width>
<height>226</height>
</rect>
</property>
<property name="windowTitle">
<string>Entropy</string>
</property>
<property name="windowIcon">
<iconset resource="../../resource.qrc">
<normaloff>:/icons/images/entropy.png</normaloff>:/icons/images/entropy.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QEntropyView" name="entropyView"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QEntropyView</class>
<extends>QGraphicsView</extends>
<header>QEntropyView\QEntropyView.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../resource.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -3,6 +3,7 @@
#include "Bridge.h"
#include "PageMemoryRights.h"
#include "YaraRuleSelectionDialog.h"
#include "EntropyDialog.h"
MemoryMapView::MemoryMapView(StdTable* parent) : StdTable(parent)
{
@ -97,6 +98,10 @@ void MemoryMapView::setupContextMenu()
this->addAction(mMemoryExecuteSingleshootToggle);
connect(mMemoryExecuteSingleshootToggle, SIGNAL(triggered()), this, SLOT(memoryExecuteSingleshootToggleSlot()));
//Entropy
mEntropy = new QAction(QIcon(":/icons/images/entropy.png"), "Entropy...", this);
connect(mEntropy, SIGNAL(triggered()), this, SLOT(entropy()));
refreshShortcutsSlot();
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot()));
}
@ -116,6 +121,7 @@ void MemoryMapView::contextMenuSlot(const QPoint & pos)
wMenu->addAction(mFollowDisassembly);
wMenu->addAction(mFollowDump);
wMenu->addAction(mYara);
wMenu->addAction(mEntropy);
wMenu->addAction(mSwitchView);
wMenu->addSeparator();
wMenu->addAction(mPageMemoryRights);
@ -400,3 +406,19 @@ void MemoryMapView::switchView()
setTableOffset(0);
stateChangedSlot(paused);
}
void MemoryMapView::entropy()
{
uint_t addr = getCellContent(getInitialSelection(), 0).toULongLong(0, 16);
uint_t size = getCellContent(getInitialSelection(), 1).toULongLong(0, 16);
unsigned char* data = new unsigned char[size];
DbgMemRead(addr, data, size);
EntropyDialog entropyDialog(this);
entropyDialog.setWindowTitle(QString().sprintf("Entropy (Address: %p, Size: %p)", addr, size));
entropyDialog.show();
entropyDialog.GraphMemory(data, size);
entropyDialog.exec();
delete[] data;
}

View File

@ -33,6 +33,7 @@ public slots:
void switchView();
void pageMemoryRights();
void refreshMap();
void entropy();
private:
QString getProtectionString(DWORD Protect);
@ -55,7 +56,7 @@ private:
QAction* mMemoryExecuteRestore;
QAction* mMemoryRemove;
QAction* mMemoryExecuteSingleshootToggle;
QAction* mEntropy;
};
#endif // MEMORYMAPVIEW_H

View File

@ -4,6 +4,7 @@
#include "Configuration.h"
#include "Bridge.h"
#include "YaraRuleSelectionDialog.h"
#include "EntropyDialog.h"
SymbolView::SymbolView(QWidget* parent) : QWidget(parent), ui(new Ui::SymbolView)
{
@ -127,6 +128,9 @@ void SymbolView::setupContextMenu()
mYaraAction = new QAction(QIcon(":/icons/images/yara.png"), "&Yara...", this);
connect(mYaraAction, SIGNAL(triggered()), this, SLOT(moduleYara()));
mEntropyAction = new QAction(QIcon(":/icons/images/entropy.png"), "Entropy...", this);
connect(mEntropyAction, SIGNAL(triggered()), this, SLOT(moduleEntropy()));
//Shortcuts
refreshShortcutsSlot();
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot()));
@ -249,6 +253,7 @@ void SymbolView::moduleContextMenu(const QPoint & pos)
if(DbgFunctions()->ModPathFromAddr(modbase, szModPath, _countof(szModPath)))
wMenu->addAction(mCopyPathAction);
wMenu->addAction(mYaraAction);
wMenu->addAction(mEntropyAction);
QMenu wCopyMenu("&Copy", this);
mModuleList->setupCopyMenu(&wCopyMenu);
if(wCopyMenu.actions().length())
@ -359,3 +364,17 @@ void SymbolView::toggleBookmark()
}
GuiUpdateAllViews();
}
void SymbolView::moduleEntropy()
{
int_t modbase = DbgValFromString(mModuleList->getCellContent(mModuleList->getInitialSelection(), 0).toUtf8().constData());
char szModPath[MAX_PATH] = "";
if(DbgFunctions()->ModPathFromAddr(modbase, szModPath, _countof(szModPath)))
{
EntropyDialog entropyDialog(this);
entropyDialog.setWindowTitle(QString("Entropy (%1)").arg(mModuleList->getCellContent(mModuleList->getInitialSelection(), 1)));
entropyDialog.show();
entropyDialog.GraphFile(QString(szModPath));
entropyDialog.exec();
}
}

View File

@ -38,6 +38,7 @@ private slots:
void toggleBreakpoint();
void toggleBookmark();
void refreshShortcutsSlot();
void moduleEntropy();
signals:
void showCpu();
@ -61,6 +62,7 @@ private:
QAction* mDownloadAllSymbolsAction;
QAction* mCopyPathAction;
QAction* mYaraAction;
QAction* mEntropyAction;
static void cbSymbolEnum(SYMBOLINFO* symbol, void* user);
};

View File

@ -0,0 +1,66 @@
#ifndef ENTROPY_H
#define ENTROPY_H
#include <cmath>
#include <vector>
class Entropy
{
public:
static double MeasureData(const unsigned char* data, int dataSize)
{
int occurrences[256] = {};
for(int i = 0; i < dataSize; i++)
occurrences[data[i]]++;
double entropy = 0.0;
double logBase = log(256);
for(int i = 0; i < 256; i++)
{
if(occurrences[i] == 0)
continue;
double p = (double)occurrences[i] / (double)dataSize;
entropy += p * log(p) / logBase;
}
return -entropy;
}
static double MeasureByte(const unsigned char* data, int dataSize, int index, unsigned char* block, int blockSize)
{
if(dataSize < blockSize)
return -1;
int start = index - blockSize / 2;
int end = index + blockSize / 2;
if(start < 0)
{
end += -start;
start = 0;
}
else if(end > dataSize)
{
start -= end - dataSize;
end = dataSize;
}
for(int i = start; i < end; i++)
block[i - start] = data[i];
return MeasureData(block, blockSize);
}
static void MeasurePoints(const unsigned char* data, int dataSize, int blockSize, std::vector<double> & points, int pointCount)
{
points.clear();
if(dataSize < pointCount)
return;
if(dataSize % pointCount != 0)
pointCount += dataSize % pointCount;
unsigned char* block = new unsigned char[blockSize];
int interval = dataSize / pointCount;
points.reserve(pointCount);
for(int i = 0; i < dataSize; i += interval)
points.push_back(MeasureByte(data, dataSize, i, block, blockSize));
delete[] block;
}
};
#endif // ENTROPY_H

View File

@ -0,0 +1,83 @@
#include "QEntropyView.h"
#include <QFile>
#include "Entropy.h"
QEntropyView::QEntropyView(QWidget* parent) : QGraphicsView(parent)
{
mScene = new QGraphicsScene(this);
}
void QEntropyView::InitializeGraph(int penSize)
{
//initialize scene
qreal width = this->width() - 5;
qreal height = this->height() - 5;
mRect = QRectF(25, 10, width - 35, height - 20);
mPenSize = penSize;
mScene->clear();
//draw bounding box
mScene->addRect(QRectF(1, 1, width, height), QPen(Qt::black));
//draw scale
mScene->addLine(15, mRect.top(), 15, mRect.bottom(), QPen(Qt::black, 2));
const int xBegin = 10;
const int xEnd = 20;
qreal intervalY = mRect.height() / 10;
for(int i = 0; i < 11; i++)
{
qreal y = mRect.top() + i * intervalY;
mScene->addLine(xBegin, y, xEnd, y, QPen(Qt::black, 2));
}
//set scene
setRenderHints(QPainter::Antialiasing);
setScene(mScene);
}
void QEntropyView::AddGraph(const std::vector<double> & points, QColor color)
{
int pointCount = (int)points.size();
if(!pointCount)
return;
qreal intervalX = mRect.width() / ((qreal)pointCount - 1);
qreal intervalY = mRect.height() / 1;
QPolygonF polyLine;
for(int i = 0; i < pointCount; i++)
{
qreal x = i * intervalX;
qreal y = points[i] * intervalY;
QPointF point(mRect.x() + x, mRect.bottom() - y); //y direction is inverted...
polyLine.append(point);
}
QPainterPath path;
path.addPolygon(polyLine);
mScene->addPath(path, QPen(color, mPenSize));
}
void QEntropyView::GraphFile(const QString & fileName, int blockSize, int pointCount, QColor color)
{
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly))
return;
QByteArray fileData = file.readAll();
file.close();
GraphMemory((unsigned char*)fileData.constData(), fileData.size(), blockSize, pointCount, color);
}
void QEntropyView::GraphMemory(const unsigned char* data, int dataSize, int blockSize, int pointCount, QColor color)
{
std::vector<double> points;
if(dataSize < blockSize)
{
blockSize = dataSize / 2;
if(!blockSize)
blockSize = 1;
}
if(dataSize < pointCount)
pointCount = (int)dataSize;
Entropy::MeasurePoints(data, dataSize, blockSize, points, pointCount);
AddGraph(points, color);
}

View File

@ -0,0 +1,23 @@
#ifndef QENTROPYVIEW_H
#define QENTROPYVIEW_H
#include <QGraphicsView>
#include <QGraphicsScene>
class QEntropyView : public QGraphicsView
{
Q_OBJECT
public:
explicit QEntropyView(QWidget* parent = 0);
void InitializeGraph(int penSize = 1);
void AddGraph(const std::vector<double> & points, QColor color = Qt::black);
void GraphFile(const QString & fileName, int blockSize, int pointCount, QColor = Qt::black);
void GraphMemory(const unsigned char* data, int dataSize, int blockSize, int pointCount, QColor = Qt::black);
private:
QGraphicsScene* mScene;
QRectF mRect;
int mPenSize;
};
#endif // QENTROPYVIEW_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

View File

@ -62,5 +62,6 @@
<file>images/highlight.png</file>
<file>images/label.png</file>
<file>images/snowman.png</file>
<file>images/entropy.png</file>
</qresource>
</RCC>

View File

@ -94,7 +94,9 @@ SOURCES += \
Src/Utils/ValidateExpressionThread.cpp \
Src/Utils/MainWindowCloseThread.cpp \
Src/Gui/TimeWastedCounter.cpp \
Src/Utils/FlickerThread.cpp
Src/Utils/FlickerThread.cpp \
Src/QEntropyView/QEntropyView.cpp \
Src/Gui/EntropyDialog.cpp
HEADERS += \
@ -168,7 +170,10 @@ HEADERS += \
Src/Utils/ValidateExpressionThread.h \
Src/Utils/MainWindowCloseThread.h \
Src/Gui/TimeWastedCounter.h \
Src/Utils/FlickerThread.h
Src/Utils/FlickerThread.h \
Src/QEntropyView/Entropy.h \
Src/QEntropyView/QEntropyView.h \
Src/Gui/EntropyDialog.h
INCLUDEPATH += \
@ -205,7 +210,8 @@ FORMS += \
Src/Gui/PageMemoryRights.ui \
Src/Gui/SelectFields.ui \
Src/Gui/YaraRuleSelectionDialog.ui \
Src/Gui/DataCopyDialog.ui
Src/Gui/DataCopyDialog.ui \
Src/Gui/EntropyDialog.ui
INCLUDEPATH += $$PWD/Src/Bridge
INCLUDEPATH += $$PWD/Src/ThirdPartyLibs/snowman