mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 10:56:11 +00:00
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:
parent
75c334596e
commit
46d29c1e85
@ -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
2
rizin
@ -1 +1 @@
|
||||
Subproject commit 0e87fbd8107dfe463924b498c84687cfc5fe2b7f
|
||||
Subproject commit 789a283dd565dadebd17ab33cbfb5ec06d87323b
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
zignatures << zignature;
|
||||
QList<FlirtDescription> sigdb;
|
||||
const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path");
|
||||
if (RZ_STR_ISEMPTY(sigdb_path)) {
|
||||
return sigdb;
|
||||
}
|
||||
|
||||
return zignatures;
|
||||
RzList *list = rz_sign_sigdb_load_database(sigdb_path, true);
|
||||
void *ptr = NULL;
|
||||
RzListIter *iter = NULL;
|
||||
|
||||
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 sigdb;
|
||||
}
|
||||
|
||||
QList<CommentDescription> CutterCore::getAllComments(const QString &filterType)
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
62
src/menus/FlirtContextMenu.cpp
Normal file
62
src/menus/FlirtContextMenu.cpp
Normal 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);
|
||||
}
|
||||
}
|
40
src/menus/FlirtContextMenu.h
Normal file
40
src/menus/FlirtContextMenu.h
Normal 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
188
src/widgets/FlirtWidget.cpp
Normal 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
88
src/widgets/FlirtWidget.h
Normal 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
|
@ -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
|
||||
{
|
@ -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);
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user