Add signature widget for flirts (#2881)

* Added flirt view and removed zignature one
* Added menu for apply signature from file and create new sig/pat files
* Updated rizin to dev branch
This commit is contained in:
Giovanni 2022-01-21 09:39:56 +01:00 committed by GitHub
parent 75c334596e
commit 46d29c1e85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 530 additions and 282 deletions

View File

@ -89,8 +89,8 @@ Show VTables
**Steps:** Windows -> Info... -> VTables
Show Zignatures
Show Signatures
----------------------------------------
**Description:** Cutter has its own format of signatures, called Zignatures. This widget lists all the loaded Zignatures.
**Description:** Cutter supports the creation and the utilization of signatures. This widget lists all the signatures available to cutter.
**Steps:** Windows -> Info... -> Zignatures
**Steps:** Windows -> Info... -> Signatures

2
rizin

@ -1 +1 @@
Subproject commit 0e87fbd8107dfe463924b498c84687cfc5fe2b7f
Subproject commit 789a283dd565dadebd17ab33cbfb5ec06d87323b

View File

@ -42,6 +42,7 @@ set(SOURCES
widgets/SymbolsWidget.cpp
menus/DisassemblyContextMenu.cpp
menus/DecompilerContextMenu.cpp
menus/FlirtContextMenu.cpp
widgets/DisassemblyWidget.cpp
widgets/HexdumpWidget.cpp
common/Configuration.cpp
@ -73,7 +74,7 @@ set(SOURCES
common/JsonTreeItem.cpp
common/JsonModel.cpp
dialogs/VersionInfoDialog.cpp
widgets/ZignaturesWidget.cpp
widgets/FlirtWidget.cpp
common/AsyncTask.cpp
dialogs/AsyncTaskDialog.cpp
widgets/StackWidget.cpp
@ -190,6 +191,7 @@ set(HEADER_FILES
widgets/SymbolsWidget.h
menus/DisassemblyContextMenu.h
menus/DecompilerContextMenu.h
menus/FlirtContextMenu.h
widgets/DisassemblyWidget.h
widgets/HexdumpWidget.h
common/Configuration.h
@ -221,7 +223,7 @@ set(HEADER_FILES
common/JsonTreeItem.h
common/JsonModel.h
dialogs/VersionInfoDialog.h
widgets/ZignaturesWidget.h
widgets/FlirtWidget.h
common/AsyncTask.h
dialogs/AsyncTaskDialog.h
widgets/StackWidget.h
@ -341,7 +343,7 @@ set(UI_FILES
widgets/SearchWidget.ui
dialogs/RizinPluginsDialog.ui
dialogs/VersionInfoDialog.ui
widgets/ZignaturesWidget.ui
widgets/FlirtWidget.ui
dialogs/AsyncTaskDialog.ui
dialogs/RizinTaskDialog.ui
widgets/StackWidget.ui

View File

@ -1016,6 +1016,40 @@ RVA CutterCore::getOffset()
return core_->offset;
}
void CutterCore::applySignature(const QString &filepath)
{
CORE_LOCK();
int old_cnt, new_cnt;
const char *arch = rz_config_get(core->config, "asm.arch");
ut8 expected_arch = rz_core_flirt_arch_from_name(arch);
if (expected_arch == RZ_FLIRT_SIG_ARCH_ANY && filepath.endsWith(".sig", Qt::CaseInsensitive)) {
QMessageBox::warning(
nullptr, tr("Signatures"),
tr("Cannot apply signature because the requested arch is not supported by .sig "
"files\n"));
return;
}
old_cnt = rz_flag_count(core->flags, "flirt");
rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch);
new_cnt = rz_flag_count(core->flags, "flirt");
QMessageBox::information(nullptr, tr("Signatures"),
tr("Found %1 signatures!").arg(new_cnt - old_cnt));
}
void CutterCore::createSignature(const QString &filepath)
{
CORE_LOCK();
ut32 n_modules = 0;
if (!rz_core_flirt_create_file(core, filepath.toStdString().c_str(), &n_modules)) {
QMessageBox::warning(
nullptr, tr("Signatures"),
tr("Cannot create signature file (check the console for more details).\n"));
return;
}
QMessageBox::information(nullptr, tr("Signatures"),
tr("Written %1 signatures to %2").arg(n_modules).arg(filepath));
}
ut64 CutterCore::math(const QString &expr)
{
CORE_LOCK();
@ -2967,35 +3001,34 @@ QList<HeaderDescription> CutterCore::getAllHeaders()
return ret;
}
QList<ZignatureDescription> CutterCore::getAllZignatures()
QList<FlirtDescription> CutterCore::getSignaturesDB()
{
CORE_LOCK();
QList<ZignatureDescription> zignatures;
QJsonArray zignaturesArray = cmdj("zj").array();
for (const QJsonValue &value : zignaturesArray) {
QJsonObject zignatureObject = value.toObject();
ZignatureDescription zignature;
zignature.name = zignatureObject[RJsonKey::name].toString();
zignature.bytes = zignatureObject[RJsonKey::bytes].toString();
zignature.offset = zignatureObject[RJsonKey::offset].toVariant().toULongLong();
for (const QJsonValue &ref : zignatureObject[RJsonKey::refs].toArray()) {
zignature.refs << ref.toString();
QList<FlirtDescription> sigdb;
const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path");
if (RZ_STR_ISEMPTY(sigdb_path)) {
return sigdb;
}
QJsonObject graphObject = zignatureObject[RJsonKey::graph].toObject();
zignature.cc = graphObject[RJsonKey::cc].toVariant().toULongLong();
zignature.nbbs = graphObject[RJsonKey::nbbs].toVariant().toULongLong();
zignature.edges = graphObject[RJsonKey::edges].toVariant().toULongLong();
zignature.ebbs = graphObject[RJsonKey::ebbs].toVariant().toULongLong();
RzList *list = rz_sign_sigdb_load_database(sigdb_path, true);
void *ptr = NULL;
RzListIter *iter = NULL;
zignatures << zignature;
rz_list_foreach(list, iter, ptr)
{
RzSigDBEntry *sig = static_cast<RzSigDBEntry *>(ptr);
FlirtDescription flirt;
flirt.bin_name = sig->bin_name;
flirt.arch_name = sig->arch_name;
flirt.base_name = sig->base_name;
flirt.short_path = sig->short_path;
flirt.file_path = sig->file_path;
flirt.details = sig->details;
flirt.n_modules = QString::number(sig->n_modules);
flirt.arch_bits = QString::number(sig->arch_bits);
sigdb << flirt;
}
return zignatures;
return sigdb;
}
QList<CommentDescription> CutterCore::getAllComments(const QString &filterType)

View File

@ -316,6 +316,10 @@ public:
RVA prevOpAddr(RVA startAddr, int count);
RVA nextOpAddr(RVA startAddr, int count);
/* SigDB / Flirt functions */
void applySignature(const QString &filepath);
void createSignature(const QString &filepath);
/* Math functions */
ut64 math(const QString &expr);
ut64 num(const QString &expr);
@ -553,7 +557,7 @@ public:
QList<ExportDescription> getAllExports();
QList<SymbolDescription> getAllSymbols();
QList<HeaderDescription> getAllHeaders();
QList<ZignatureDescription> getAllZignatures();
QList<FlirtDescription> getSignaturesDB();
QList<CommentDescription> getAllComments(const QString &filterType);
QList<RelocDescription> getAllRelocs();
QList<StringDescription> getAllStrings();

View File

@ -60,16 +60,16 @@ struct HeaderDescription
QString name;
};
struct ZignatureDescription
struct FlirtDescription
{
QString name;
QString bytes;
RVA cc;
RVA nbbs;
RVA edges;
RVA ebbs;
RVA offset;
QStringList refs;
QString bin_name;
QString arch_name;
QString arch_bits;
QString base_name;
QString short_path;
QString file_path;
QString details;
QString n_modules;
};
struct TypeDescription
@ -413,7 +413,7 @@ Q_DECLARE_METATYPE(ResourcesDescription)
Q_DECLARE_METATYPE(VTableDescription)
Q_DECLARE_METATYPE(TypeDescription)
Q_DECLARE_METATYPE(HeaderDescription)
Q_DECLARE_METATYPE(ZignatureDescription)
Q_DECLARE_METATYPE(FlirtDescription)
Q_DECLARE_METATYPE(SearchDescription)
Q_DECLARE_METATYPE(SectionDescription)
Q_DECLARE_METATYPE(SegmentDescription)

View File

@ -55,7 +55,7 @@
#include "widgets/ResourcesWidget.h"
#include "widgets/VTablesWidget.h"
#include "widgets/HeadersWidget.h"
#include "widgets/ZignaturesWidget.h"
#include "widgets/FlirtWidget.h"
#include "widgets/DebugActions.h"
#include "widgets/MemoryMapWidget.h"
#include "widgets/BreakpointWidget.h"
@ -399,7 +399,7 @@ void MainWindow::initDocks()
segmentsDock = new SegmentsWidget(this),
symbolsDock = new SymbolsWidget(this),
vTablesDock = new VTablesWidget(this),
zignaturesDock = new ZignaturesWidget(this),
flirtDock = new FlirtWidget(this),
rzGraphDock = new RizinGraphWidget(this),
callGraphDock = new CallGraphWidget(this, false),
globalCallGraphDock = new CallGraphWidget(this, true),
@ -896,7 +896,7 @@ void MainWindow::restoreDocks()
tabifyDockWidget(dashboardDock, typesDock);
tabifyDockWidget(dashboardDock, searchDock);
tabifyDockWidget(dashboardDock, headersDock);
tabifyDockWidget(dashboardDock, zignaturesDock);
tabifyDockWidget(dashboardDock, flirtDock);
tabifyDockWidget(dashboardDock, symbolsDock);
tabifyDockWidget(dashboardDock, classesDock);
tabifyDockWidget(dashboardDock, resourcesDock);
@ -1741,6 +1741,50 @@ void MainWindow::on_actionExport_as_code_triggered()
fileOut << Core()->cmd(cmd + " $s @ 0");
}
void MainWindow::on_actionApplySigFromFile_triggered()
{
QStringList filters;
filters << tr("Signature File (*.sig)");
filters << tr("Pattern File (*.pat)");
QFileDialog dialog(this);
dialog.setWindowTitle(tr("Apply Signature From File"));
dialog.setNameFilters(filters);
if (!dialog.exec()) {
return;
}
const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first());
if (!sigfile.isEmpty()) {
core->applySignature(sigfile);
this->refreshAll();
}
}
void MainWindow::on_actionCreateNewSig_triggered()
{
QStringList filters;
filters << tr("Signature File (*.sig)");
filters << tr("Pattern File (*.pat)");
QFileDialog dialog(this, tr("Create New Signature File"));
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.selectFile("");
dialog.setDefaultSuffix("sig");
if (!dialog.exec())
return;
const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first());
if (!sigfile.isEmpty()) {
core->createSignature(sigfile);
}
}
void MainWindow::on_actionGrouped_dock_dragging_triggered(bool checked)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)

View File

@ -44,7 +44,7 @@ class ResourcesWidget;
class VTablesWidget;
class TypesWidget;
class HeadersWidget;
class ZignaturesWidget;
class FlirtWidget;
class SearchWidget;
class QDockWidget;
class DisassemblyWidget;
@ -190,6 +190,10 @@ private slots:
void on_actionExport_as_code_triggered();
void on_actionApplySigFromFile_triggered();
void on_actionCreateNewSig_triggered();
void on_actionGrouped_dock_dragging_triggered(bool checked);
void updateTasksIndicator();
@ -243,7 +247,7 @@ private:
SdbWidget *sdbDock = nullptr;
SectionsWidget *sectionsDock = nullptr;
SegmentsWidget *segmentsDock = nullptr;
ZignaturesWidget *zignaturesDock = nullptr;
FlirtWidget *flirtDock = nullptr;
ConsoleWidget *consoleDock = nullptr;
ClassesWidget *classesDock = nullptr;
ResourcesWidget *resourcesDock = nullptr;

View File

@ -77,6 +77,9 @@
<addaction name="actionImportPDB"/>
<addaction name="actionAnalyze"/>
<addaction name="separator"/>
<addaction name="actionApplySigFromFile"/>
<addaction name="actionCreateNewSig"/>
<addaction name="separator"/>
<addaction name="menuSetMode"/>
<addaction name="actionCommitChanges"/>
<addaction name="separator"/>
@ -740,6 +743,16 @@
<string>Export as code</string>
</property>
</action>
<action name="actionApplySigFromFile">
<property name="text">
<string>Apply Signature From File</string>
</property>
</action>
<action name="actionCreateNewSig">
<property name="text">
<string>Create New Signature File</string>
</property>
</action>
<action name="actionExtraHexdump">
<property name="text">
<string>Add Hexdump</string>

View File

@ -0,0 +1,62 @@
#include "FlirtContextMenu.h"
#include "MainWindow.h"
#include <QtCore>
#include <QShortcut>
#include <QJsonArray>
#include <QClipboard>
#include <QApplication>
#include <QPushButton>
FlirtContextMenu::FlirtContextMenu(QWidget *parent, MainWindow *mainWindow)
: QMenu(parent), mainWindow(mainWindow)
{
actionCopyLine = new QAction(tr("Copy Line"), this);
actionApplySignature = new QAction(tr("Apply Signature File"), this);
connect(actionCopyLine, &QAction::triggered, this, &FlirtContextMenu::onActionCopyLine);
connect(actionApplySignature, &QAction::triggered, this,
&FlirtContextMenu::onActionApplySignature);
addAction(actionCopyLine);
addSeparator();
addAction(actionApplySignature);
setHasTarget(false);
}
FlirtContextMenu::~FlirtContextMenu() {}
void FlirtContextMenu::setTarget(const FlirtDescription &flirt)
{
this->entry = flirt;
setHasTarget(true);
}
void FlirtContextMenu::clearTarget()
{
setHasTarget(false);
}
void FlirtContextMenu::onActionCopyLine()
{
auto clipboard = QApplication::clipboard();
QString text = entry.bin_name + "\t" + entry.arch_name + "\t" + entry.arch_bits + "\t"
+ entry.n_modules + "\t" + entry.base_name + "\t" + entry.details;
clipboard->setText(text);
}
void FlirtContextMenu::onActionApplySignature()
{
if (this->hasTarget) {
Core()->applySignature(entry.file_path);
}
}
void FlirtContextMenu::setHasTarget(bool hasTarget)
{
this->hasTarget = hasTarget;
for (const auto &action : this->actions()) {
action->setEnabled(hasTarget);
}
}

View File

@ -0,0 +1,40 @@
#ifndef FLIRT_CONTEXTMENU_H
#define FLIRT_CONTEXTMENU_H
#include "core/Cutter.h"
#include <QMenu>
#include <QKeySequence>
class MainWindow;
class CUTTER_EXPORT FlirtContextMenu : public QMenu
{
Q_OBJECT
public:
FlirtContextMenu(QWidget *parent, MainWindow *mainWindow);
~FlirtContextMenu();
public slots:
void setTarget(const FlirtDescription &flirt);
void clearTarget();
private:
void onActionCopyLine();
void onActionApplySignature();
QMenu *pluginMenu;
QAction *pluginMenuAction;
MainWindow *mainWindow;
bool hasTarget = false;
protected:
void setHasTarget(bool hasTarget);
QAction *actionApplySignature;
QAction *actionCopyLine;
QAction *actionShowContents;
FlirtDescription entry;
};
#endif // FlirtCONTEXTMENU_H

188
src/widgets/FlirtWidget.cpp Normal file
View File

@ -0,0 +1,188 @@
#include "FlirtWidget.h"
#include "ui_FlirtWidget.h"
#include "core/MainWindow.h"
#include "common/Helpers.h"
FlirtModel::FlirtModel(QList<FlirtDescription> *sigdb, QObject *parent)
: QAbstractListModel(parent), sigdb(sigdb)
{
}
int FlirtModel::rowCount(const QModelIndex &) const
{
return sigdb->count();
}
int FlirtModel::columnCount(const QModelIndex &) const
{
return FlirtModel::ColumnCount;
}
QVariant FlirtModel::data(const QModelIndex &index, int role) const
{
if (index.row() >= sigdb->count())
return QVariant();
const FlirtDescription &entry = sigdb->at(index.row());
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case BinTypeColumn:
return entry.bin_name;
case ArchNameColumn:
return entry.arch_name;
case ArchBitsColumn:
return entry.arch_bits;
case NumModulesColumn:
return entry.n_modules;
case NameColumn:
return entry.base_name;
case DetailsColumn:
return entry.details;
default:
return QVariant();
}
case FlirtDescriptionRole:
return QVariant::fromValue(entry);
case Qt::ToolTipRole: {
return entry.short_path;
}
default:
return QVariant();
}
}
QVariant FlirtModel::headerData(int section, Qt::Orientation, int role) const
{
switch (role) {
case Qt::DisplayRole:
switch (section) {
case BinTypeColumn:
return tr("Bin");
case ArchNameColumn:
return tr("Arch");
case ArchBitsColumn:
return tr("Bits");
case NumModulesColumn:
return tr("# Funcs");
case NameColumn:
return tr("Name");
case DetailsColumn:
return tr("Details");
default:
return QVariant();
}
default:
return QVariant();
}
}
FlirtProxyModel::FlirtProxyModel(FlirtModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(sourceModel);
}
bool FlirtProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
{
QModelIndex index = sourceModel()->index(row, 0, parent);
FlirtDescription entry = index.data(FlirtModel::FlirtDescriptionRole).value<FlirtDescription>();
return qhelpers::filterStringContains(entry.base_name, this);
}
bool FlirtProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
FlirtDescription leftEntry =
left.data(FlirtModel::FlirtDescriptionRole).value<FlirtDescription>();
FlirtDescription rightEntry =
right.data(FlirtModel::FlirtDescriptionRole).value<FlirtDescription>();
switch (left.column()) {
case FlirtModel::BinTypeColumn:
return leftEntry.bin_name < rightEntry.bin_name;
case FlirtModel::ArchNameColumn:
return leftEntry.arch_name < rightEntry.arch_name;
case FlirtModel::ArchBitsColumn:
return leftEntry.arch_bits < rightEntry.arch_bits;
case FlirtModel::NumModulesColumn:
return leftEntry.n_modules < rightEntry.n_modules;
case FlirtModel::NameColumn:
return leftEntry.base_name < rightEntry.base_name;
case FlirtModel::DetailsColumn:
return leftEntry.details < rightEntry.details;
default:
break;
}
return leftEntry.bin_name < rightEntry.bin_name;
}
FlirtWidget::FlirtWidget(MainWindow *main)
: CutterDockWidget(main),
ui(new Ui::FlirtWidget),
blockMenu(new FlirtContextMenu(this, mainWindow))
{
ui->setupUi(this);
model = new FlirtModel(&sigdb, this);
proxyModel = new FlirtProxyModel(model, this);
ui->flirtTreeView->setModel(proxyModel);
ui->flirtTreeView->sortByColumn(FlirtModel::BinTypeColumn, Qt::AscendingOrder);
setScrollMode();
this->connect(this, &QWidget::customContextMenuRequested, this,
&FlirtWidget::showItemContextMenu);
this->setContextMenuPolicy(Qt::CustomContextMenu);
this->connect(ui->flirtTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
&FlirtWidget::onSelectedItemChanged);
connect(Core(), &CutterCore::refreshAll, this, &FlirtWidget::refreshFlirt);
this->addActions(this->blockMenu->actions());
}
FlirtWidget::~FlirtWidget() {}
void FlirtWidget::refreshFlirt()
{
model->beginResetModel();
sigdb = Core()->getSignaturesDB();
model->endResetModel();
ui->flirtTreeView->resizeColumnToContents(0);
ui->flirtTreeView->resizeColumnToContents(1);
ui->flirtTreeView->resizeColumnToContents(2);
ui->flirtTreeView->resizeColumnToContents(3);
ui->flirtTreeView->resizeColumnToContents(4);
ui->flirtTreeView->resizeColumnToContents(5);
}
void FlirtWidget::setScrollMode()
{
qhelpers::setVerticalScrollMode(ui->flirtTreeView);
}
void FlirtWidget::onSelectedItemChanged(const QModelIndex &index)
{
if (index.isValid()) {
const FlirtDescription &entry = sigdb.at(index.row());
blockMenu->setTarget(entry);
} else {
blockMenu->clearTarget();
}
}
void FlirtWidget::showItemContextMenu(const QPoint &pt)
{
auto index = ui->flirtTreeView->currentIndex();
if (index.isValid()) {
const FlirtDescription &entry = sigdb.at(index.row());
blockMenu->setTarget(entry);
blockMenu->exec(this->mapToGlobal(pt));
}
}

88
src/widgets/FlirtWidget.h Normal file
View File

@ -0,0 +1,88 @@
#ifndef FLIRT_WIDGET_H
#define FLIRT_WIDGET_H
#include <memory>
#include "core/Cutter.h"
#include "CutterDockWidget.h"
#include "menus/FlirtContextMenu.h"
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
class MainWindow;
class QTreeWidget;
class QTreeWidgetItem;
class FlirtWidget;
namespace Ui {
class FlirtWidget;
}
class FlirtModel : public QAbstractListModel
{
Q_OBJECT
friend FlirtWidget;
public:
enum Column {
BinTypeColumn = 0,
ArchNameColumn,
ArchBitsColumn,
NumModulesColumn,
NameColumn,
DetailsColumn,
ColumnCount
};
enum Role { FlirtDescriptionRole = Qt::UserRole };
FlirtModel(QList<FlirtDescription> *sigdb, QObject *parent = 0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
QList<FlirtDescription> *sigdb;
};
class FlirtProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
FlirtProxyModel(FlirtModel *sourceModel, QObject *parent = nullptr);
protected:
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
class FlirtWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit FlirtWidget(MainWindow *main);
~FlirtWidget();
private slots:
void refreshFlirt();
void onSelectedItemChanged(const QModelIndex &index);
void showItemContextMenu(const QPoint &pt);
private:
std::unique_ptr<Ui::FlirtWidget> ui;
FlirtModel *model;
FlirtProxyModel *proxyModel;
QList<FlirtDescription> sigdb;
FlirtContextMenu *blockMenu;
void setScrollMode();
};
#endif // FLIRT_WIDGET_H

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ZignaturesWidget</class>
<widget class="QDockWidget" name="ZignaturesWidget">
<class>FlirtWidget</class>
<widget class="QDockWidget" name="FlirtWidget">
<property name="geometry">
<rect>
<x>0</x>
@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string notr="true">Zignatures</string>
<string notr="true">Signatures</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
@ -28,7 +28,7 @@
<number>0</number>
</property>
<item>
<widget class="CutterTreeView" name="zignaturesTreeView">
<widget class="CutterTreeView" name="flirtTreeView">
<property name="styleSheet">
<string notr="true">CutterTreeView::item
{

View File

@ -1,152 +0,0 @@
#include "ZignaturesWidget.h"
#include "ui_ZignaturesWidget.h"
#include "core/MainWindow.h"
#include "common/Helpers.h"
ZignaturesModel::ZignaturesModel(QList<ZignatureDescription> *zignatures, QObject *parent)
: QAbstractListModel(parent), zignatures(zignatures)
{
}
int ZignaturesModel::rowCount(const QModelIndex &) const
{
return zignatures->count();
}
int ZignaturesModel::columnCount(const QModelIndex &) const
{
return ZignaturesModel::ColumnCount;
}
QVariant ZignaturesModel::data(const QModelIndex &index, int role) const
{
if (index.row() >= zignatures->count())
return QVariant();
const ZignatureDescription &zignature = zignatures->at(index.row());
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case OffsetColumn:
return RzAddressString(zignature.offset);
case NameColumn:
return zignature.name;
case ValueColumn:
return zignature.bytes;
default:
return QVariant();
}
case ZignatureDescriptionRole:
return QVariant::fromValue(zignature);
case Qt::ToolTipRole: {
QString tmp = QString("Graph:\n\n Cyclomatic complexity: " + RzSizeString(zignature.cc)
+ "\n Nodes / basicblocks: " + RzSizeString(zignature.nbbs)
+ "\n Edges: " + RzSizeString(zignature.edges)
+ "\n Ebbs: " + RzSizeString(zignature.ebbs) + "\n\nRefs:\n");
for (const QString &ref : zignature.refs) {
tmp.append("\n " + ref);
}
return tmp;
}
default:
return QVariant();
}
}
QVariant ZignaturesModel::headerData(int section, Qt::Orientation, int role) const
{
switch (role) {
case Qt::DisplayRole:
switch (section) {
case OffsetColumn:
return tr("Offset");
case NameColumn:
return tr("Name");
case ValueColumn:
return tr("Bytes");
default:
return QVariant();
}
default:
return QVariant();
}
}
ZignaturesProxyModel::ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(sourceModel);
}
bool ZignaturesProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
{
QModelIndex index = sourceModel()->index(row, 0, parent);
ZignatureDescription item =
index.data(ZignaturesModel::ZignatureDescriptionRole).value<ZignatureDescription>();
return qhelpers::filterStringContains(item.name, this);
}
bool ZignaturesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
ZignatureDescription leftZignature =
left.data(ZignaturesModel::ZignatureDescriptionRole).value<ZignatureDescription>();
ZignatureDescription rightZignature =
right.data(ZignaturesModel::ZignatureDescriptionRole).value<ZignatureDescription>();
switch (left.column()) {
case ZignaturesModel::OffsetColumn:
return leftZignature.offset < rightZignature.offset;
case ZignaturesModel::NameColumn:
return leftZignature.name < rightZignature.name;
case ZignaturesModel::ValueColumn:
return leftZignature.bytes < rightZignature.bytes;
default:
break;
}
return leftZignature.offset < rightZignature.offset;
}
ZignaturesWidget::ZignaturesWidget(MainWindow *main)
: CutterDockWidget(main), ui(new Ui::ZignaturesWidget)
{
ui->setupUi(this);
zignaturesModel = new ZignaturesModel(&zignatures, this);
zignaturesProxyModel = new ZignaturesProxyModel(zignaturesModel, this);
ui->zignaturesTreeView->setModel(zignaturesProxyModel);
ui->zignaturesTreeView->sortByColumn(ZignaturesModel::OffsetColumn, Qt::AscendingOrder);
setScrollMode();
connect(Core(), &CutterCore::refreshAll, this, &ZignaturesWidget::refreshZignatures);
}
ZignaturesWidget::~ZignaturesWidget() {}
void ZignaturesWidget::refreshZignatures()
{
zignaturesModel->beginResetModel();
zignatures = Core()->getAllZignatures();
zignaturesModel->endResetModel();
ui->zignaturesTreeView->resizeColumnToContents(0);
ui->zignaturesTreeView->resizeColumnToContents(1);
ui->zignaturesTreeView->resizeColumnToContents(2);
}
void ZignaturesWidget::setScrollMode()
{
qhelpers::setVerticalScrollMode(ui->zignaturesTreeView);
}
void ZignaturesWidget::on_zignaturesTreeView_doubleClicked(const QModelIndex &index)
{
ZignatureDescription item =
index.data(ZignaturesModel::ZignatureDescriptionRole).value<ZignatureDescription>();
Core()->seekAndShow(item.offset);
}

View File

@ -1,78 +0,0 @@
#ifndef ZIGNATURESWIDGET_H
#define ZIGNATURESWIDGET_H
#include <memory>
#include "core/Cutter.h"
#include "CutterDockWidget.h"
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
class MainWindow;
class QTreeWidget;
class QTreeWidgetItem;
class ZignaturesWidget;
namespace Ui {
class ZignaturesWidget;
}
class ZignaturesModel : public QAbstractListModel
{
Q_OBJECT
friend ZignaturesWidget;
public:
enum Column { OffsetColumn = 0, NameColumn, ValueColumn, ColumnCount };
enum Role { ZignatureDescriptionRole = Qt::UserRole };
ZignaturesModel(QList<ZignatureDescription> *zignatures, QObject *parent = 0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
QList<ZignatureDescription> *zignatures;
};
class ZignaturesProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent = nullptr);
protected:
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
class ZignaturesWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit ZignaturesWidget(MainWindow *main);
~ZignaturesWidget();
private slots:
void on_zignaturesTreeView_doubleClicked(const QModelIndex &index);
void refreshZignatures();
private:
std::unique_ptr<Ui::ZignaturesWidget> ui;
ZignaturesModel *zignaturesModel;
ZignaturesProxyModel *zignaturesProxyModel;
QList<ZignatureDescription> zignatures;
void setScrollMode();
};
#endif // ZIGNATURESWIDGET_H