mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-19 02:48:49 +00:00
Initial work on bin diffing
This commit is contained in:
parent
f97ab44072
commit
39532d312c
@ -58,6 +58,7 @@ set(SOURCES
|
|||||||
widgets/DecompilerWidget.cpp
|
widgets/DecompilerWidget.cpp
|
||||||
widgets/VisualNavbar.cpp
|
widgets/VisualNavbar.cpp
|
||||||
widgets/GraphView.cpp
|
widgets/GraphView.cpp
|
||||||
|
dialogs/bindiff/BinDiffDialog.cpp
|
||||||
dialogs/preferences/PreferencesDialog.cpp
|
dialogs/preferences/PreferencesDialog.cpp
|
||||||
dialogs/preferences/AppearanceOptionsWidget.cpp
|
dialogs/preferences/AppearanceOptionsWidget.cpp
|
||||||
dialogs/preferences/GraphOptionsWidget.cpp
|
dialogs/preferences/GraphOptionsWidget.cpp
|
||||||
@ -213,6 +214,7 @@ set(HEADER_FILES
|
|||||||
widgets/DecompilerWidget.h
|
widgets/DecompilerWidget.h
|
||||||
widgets/VisualNavbar.h
|
widgets/VisualNavbar.h
|
||||||
widgets/GraphView.h
|
widgets/GraphView.h
|
||||||
|
dialogs/bindiff/BinDiffDialog.h
|
||||||
dialogs/preferences/PreferencesDialog.h
|
dialogs/preferences/PreferencesDialog.h
|
||||||
dialogs/preferences/AppearanceOptionsWidget.h
|
dialogs/preferences/AppearanceOptionsWidget.h
|
||||||
dialogs/preferences/PreferenceCategory.h
|
dialogs/preferences/PreferenceCategory.h
|
||||||
@ -345,6 +347,7 @@ set(UI_FILES
|
|||||||
widgets/GlobalsWidget.ui
|
widgets/GlobalsWidget.ui
|
||||||
widgets/StringsWidget.ui
|
widgets/StringsWidget.ui
|
||||||
widgets/HexdumpWidget.ui
|
widgets/HexdumpWidget.ui
|
||||||
|
dialogs/bindiff/BinDiffDialog.ui
|
||||||
dialogs/preferences/PreferencesDialog.ui
|
dialogs/preferences/PreferencesDialog.ui
|
||||||
dialogs/preferences/AppearanceOptionsWidget.ui
|
dialogs/preferences/AppearanceOptionsWidget.ui
|
||||||
dialogs/preferences/GraphOptionsWidget.ui
|
dialogs/preferences/GraphOptionsWidget.ui
|
||||||
|
@ -78,6 +78,14 @@ const QHash<QString, QHash<ColorFlags, QColor>> Configuration::cutterOptionColor
|
|||||||
{ { DarkFlag, QColor(0x1c, 0x1f, 0x24) }, { LightFlag, QColor(0xf5, 0xfa, 0xff) } } },
|
{ { DarkFlag, QColor(0x1c, 0x1f, 0x24) }, { LightFlag, QColor(0xf5, 0xfa, 0xff) } } },
|
||||||
{ "gui.disass_selected",
|
{ "gui.disass_selected",
|
||||||
{ { DarkFlag, QColor(0x1f, 0x22, 0x28) }, { LightFlag, QColor(0xff, 0xff, 0xff) } } },
|
{ { DarkFlag, QColor(0x1f, 0x22, 0x28) }, { LightFlag, QColor(0xff, 0xff, 0xff) } } },
|
||||||
|
{ "gui.match.perfect",
|
||||||
|
{ { DarkFlag, QColor(0x4c, 0xaf, 0x50) }, { LightFlag, QColor(0x00, 0xc8, 0x53) } } },
|
||||||
|
{ "gui.match.partial",
|
||||||
|
{ { DarkFlag, QColor(0xff, 0xc1, 0x07) }, { LightFlag, QColor(0xff, 0xa0, 0x00) } } },
|
||||||
|
{ "gui.match.none",
|
||||||
|
{ { DarkFlag, QColor(0xf4, 0x43, 0x36) }, { LightFlag, QColor(0xd3, 0x2f, 0x2f) } } },
|
||||||
|
{ "gui.match.new",
|
||||||
|
{ { DarkFlag, QColor(0x21, 0x96, 0xf3) }, { LightFlag, QColor(0x19, 0x76, 0xd2) } } },
|
||||||
{ "lineHighlight",
|
{ "lineHighlight",
|
||||||
{ { DarkFlag, QColor(0x15, 0x1d, 0x1d, 0x96) },
|
{ { DarkFlag, QColor(0x15, 0x1d, 0x1d, 0x96) },
|
||||||
{ LightFlag, QColor(0xd2, 0xd2, 0xff, 0x96) } } },
|
{ LightFlag, QColor(0xd2, 0xd2, 0xff, 0x96) } } },
|
||||||
|
@ -11,17 +11,17 @@ RizinTask::~RizinTask()
|
|||||||
|
|
||||||
void RizinTask::startTask()
|
void RizinTask::startTask()
|
||||||
{
|
{
|
||||||
rz_core_task_enqueue(&Core()->core_->tasks, task);
|
rz_core_task_enqueue(&Core()->core_a->tasks, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RizinTask::breakTask()
|
void RizinTask::breakTask()
|
||||||
{
|
{
|
||||||
rz_core_task_break(&Core()->core_->tasks, task->id);
|
rz_core_task_break(&Core()->core_a->tasks, task->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RizinTask::joinTask()
|
void RizinTask::joinTask()
|
||||||
{
|
{
|
||||||
rz_core_task_join(&Core()->core_->tasks, nullptr, task->id);
|
rz_core_task_join(&Core()->core_a->tasks, nullptr, task->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RizinTask::taskFinished()
|
void RizinTask::taskFinished()
|
||||||
|
@ -67,7 +67,7 @@ void Basefind::run()
|
|||||||
core->coreMutex.lock();
|
core->coreMutex.lock();
|
||||||
options.callback = threadCallback;
|
options.callback = threadCallback;
|
||||||
options.user = this;
|
options.user = this;
|
||||||
scores = rz_basefind(core->core_, &options);
|
scores = rz_basefind(core->core_a, &options);
|
||||||
core->coreMutex.unlock();
|
core->coreMutex.unlock();
|
||||||
|
|
||||||
emit complete();
|
emit complete();
|
||||||
|
@ -152,12 +152,12 @@ RzCoreLocked::~RzCoreLocked()
|
|||||||
|
|
||||||
RzCoreLocked::operator RzCore *() const
|
RzCoreLocked::operator RzCore *() const
|
||||||
{
|
{
|
||||||
return core->core_;
|
return core->core_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
RzCore *RzCoreLocked::operator->() const
|
RzCore *RzCoreLocked::operator->() const
|
||||||
{
|
{
|
||||||
return core->core_;
|
return core->core_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CORE_LOCK() RzCoreLocked core(this)
|
#define CORE_LOCK() RzCoreLocked core(this)
|
||||||
@ -198,20 +198,21 @@ void CutterCore::initialize(bool loadPlugins)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
rz_cons_new(); // initialize console
|
rz_cons_new(); // initialize console
|
||||||
core_ = rz_core_new();
|
core_a = rz_core_new();
|
||||||
rz_core_task_sync_begin(&core_->tasks);
|
core_b = nullptr;
|
||||||
|
rz_core_task_sync_begin(&core_a->tasks);
|
||||||
coreBed = rz_cons_sleep_begin();
|
coreBed = rz_cons_sleep_begin();
|
||||||
CORE_LOCK();
|
CORE_LOCK();
|
||||||
|
|
||||||
rz_event_hook(core_->analysis->ev, RZ_EVENT_ALL, cutterREventCallback, this);
|
rz_event_hook(core_a->analysis->ev, RZ_EVENT_ALL, cutterREventCallback, this);
|
||||||
|
|
||||||
if (loadPlugins) {
|
if (loadPlugins) {
|
||||||
setConfig("cfg.plugins", true);
|
setConfig("cfg.plugins", true);
|
||||||
rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL);
|
rz_core_loadlibs(this->core_a, RZ_CORE_LOADLIBS_ALL);
|
||||||
} else {
|
} else {
|
||||||
setConfig("cfg.plugins", false);
|
setConfig("cfg.plugins", false);
|
||||||
}
|
}
|
||||||
// IMPLICIT rz_bin_iobind (core_->bin, core_->io);
|
// IMPLICIT rz_bin_iobind (core_a->bin, core_a->io);
|
||||||
|
|
||||||
// Otherwise Rizin may ask the user for input and Cutter would freeze
|
// Otherwise Rizin may ask the user for input and Cutter would freeze
|
||||||
setConfig("scr.interactive", false);
|
setConfig("scr.interactive", false);
|
||||||
@ -232,8 +233,11 @@ CutterCore::~CutterCore()
|
|||||||
{
|
{
|
||||||
delete bbHighlighter;
|
delete bbHighlighter;
|
||||||
rz_cons_sleep_end(coreBed);
|
rz_cons_sleep_end(coreBed);
|
||||||
rz_core_task_sync_end(&core_->tasks);
|
rz_core_free(this->core_b);
|
||||||
rz_core_free(this->core_);
|
this->core_b = nullptr;
|
||||||
|
rz_core_task_sync_end(&core_a->tasks);
|
||||||
|
rz_core_free(this->core_a);
|
||||||
|
this->core_a = nullptr;
|
||||||
rz_cons_free();
|
rz_cons_free();
|
||||||
assert(uniqueInstance == this);
|
assert(uniqueInstance == this);
|
||||||
uniqueInstance = nullptr;
|
uniqueInstance = nullptr;
|
||||||
@ -1044,7 +1048,7 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count)
|
|||||||
|
|
||||||
RVA CutterCore::getOffset()
|
RVA CutterCore::getOffset()
|
||||||
{
|
{
|
||||||
return core_->offset;
|
return core_a->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::applySignature(const QString &filepath)
|
void CutterCore::applySignature(const QString &filepath)
|
||||||
@ -4560,6 +4564,93 @@ bool CutterCore::isWriteModeEnabled()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RzAnalysisMatchResult *CutterCore::matchFunctionsFromNewFile(const QString &filePath) {
|
||||||
|
RzList *fcns_a = NULL, *fcns_b = NULL;
|
||||||
|
RzAnalysisMatchResult *result = NULL;
|
||||||
|
RzListIter *iter;
|
||||||
|
RzConfigNode *node;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if (core_b) {
|
||||||
|
rz_core_free(core_b);
|
||||||
|
core_b = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_b = rz_core_new();
|
||||||
|
if (!core_b) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rz_config_set_b(core_b->config, "io.va", rz_config_get_b(core_a->config, "io.va"));
|
||||||
|
|
||||||
|
rz_core_loadlibs(core_b, RZ_CORE_LOADLIBS_ALL);
|
||||||
|
core_b->print->scr_prompt = false;
|
||||||
|
if (!rz_core_file_open(core_b, filePath.toUtf8().constData(), RZ_PERM_RX, 0)) {
|
||||||
|
qWarning() << "cannot open file " << filePath;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rz_core_bin_load(core_b, NULL, UT64_MAX)) {
|
||||||
|
qWarning() << "cannot load bin " << filePath;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rz_core_bin_update_arch_bits(core_b)) {
|
||||||
|
qWarning() << "cannot set architecture with bits";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rz_list_foreach (core_a->config->nodes, iter, ptr) {
|
||||||
|
node = reinterpret_cast<RzConfigNode *>(ptr);
|
||||||
|
if (!strcmp(node->name, "scr.color") ||
|
||||||
|
!strcmp(node->name, "scr.interactive") ||
|
||||||
|
!strcmp(node->name, "cfg.debug")) {
|
||||||
|
rz_config_set(core_b->config, node->name, "0");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rz_config_set(core_b->config, node->name, node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rz_core_analysis_everything(core_b, false, NULL)) {
|
||||||
|
qWarning() << "cannot analyze binary " << filePath;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcns_a = rz_list_clone(rz_analysis_get_fcns(core_a->analysis));
|
||||||
|
if (rz_list_empty(fcns_a)) {
|
||||||
|
qWarning() << "no functions found in the current opened file";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcns_b = rz_list_clone(rz_analysis_get_fcns(core_b->analysis));
|
||||||
|
if (rz_list_empty(fcns_b)) {
|
||||||
|
qWarning() << "no functions found in " << filePath;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rz_list_sort(fcns_a, core_a->analysis->columnSort);
|
||||||
|
rz_list_sort(fcns_b, core_b->analysis->columnSort);
|
||||||
|
|
||||||
|
// calculate all the matches between the functions of the 2 different core files.
|
||||||
|
result = rz_analysis_match_functions_2(core_a->analysis, fcns_a, core_b->analysis, fcns_b);
|
||||||
|
if (!result) {
|
||||||
|
qWarning() << "failed to perform the function matching operation";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rz_list_free(fcns_a);
|
||||||
|
rz_list_free(fcns_b);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
rz_list_free(fcns_a);
|
||||||
|
rz_list_free(fcns_b);
|
||||||
|
rz_core_free(this->core_b);
|
||||||
|
this->core_b = nullptr;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get a compact disassembly preview for tooltips
|
* @brief get a compact disassembly preview for tooltips
|
||||||
* @param address - the address from which to print the disassembly
|
* @param address - the address from which to print the disassembly
|
||||||
|
@ -84,7 +84,7 @@ public:
|
|||||||
|
|
||||||
AsyncTaskManager *getAsyncTaskManager() { return asyncTaskManager; }
|
AsyncTaskManager *getAsyncTaskManager() { return asyncTaskManager; }
|
||||||
|
|
||||||
RVA getOffset() const { return core_->offset; }
|
RVA getOffset() const { return core_a->offset; }
|
||||||
|
|
||||||
/* Core functions (commands) */
|
/* Core functions (commands) */
|
||||||
/* Almost the same as core_cmd_raw,
|
/* Almost the same as core_cmd_raw,
|
||||||
@ -754,6 +754,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type, RVA address);
|
void writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type, RVA address);
|
||||||
|
|
||||||
|
/* Diffing/Matching */
|
||||||
|
RzAnalysisMatchResult *matchFunctionsFromNewFile(const QString &filePath);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void refreshAll();
|
void refreshAll();
|
||||||
|
|
||||||
@ -826,7 +829,8 @@ private:
|
|||||||
* Internal reference to the RzCore.
|
* Internal reference to the RzCore.
|
||||||
* NEVER use this directly! Always use the CORE_LOCK(); macro and access it like core->...
|
* NEVER use this directly! Always use the CORE_LOCK(); macro and access it like core->...
|
||||||
*/
|
*/
|
||||||
RzCore *core_ = nullptr;
|
RzCore *core_a = nullptr;
|
||||||
|
RzCore *core_b = nullptr;
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
QMutex coreMutex;
|
QMutex coreMutex;
|
||||||
#else
|
#else
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "CutterApplication.h"
|
#include "CutterApplication.h"
|
||||||
|
|
||||||
// Dialogs
|
// Dialogs
|
||||||
|
#include "dialogs/RizinTaskDialog.h"
|
||||||
#include "dialogs/WelcomeDialog.h"
|
#include "dialogs/WelcomeDialog.h"
|
||||||
#include "dialogs/NewFileDialog.h"
|
#include "dialogs/NewFileDialog.h"
|
||||||
#include "dialogs/InitialOptionsDialog.h"
|
#include "dialogs/InitialOptionsDialog.h"
|
||||||
@ -1613,11 +1614,62 @@ void MainWindow::on_actionBackward_triggered()
|
|||||||
core->seekPrev();
|
core->seekPrev();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionDiff_triggered()
|
||||||
|
{
|
||||||
|
QFileDialog dialog(this);
|
||||||
|
dialog.setWindowTitle(tr("Select a file to use for diffing"));
|
||||||
|
dialog.setNameFilters({ tr("All files (*)") });
|
||||||
|
|
||||||
|
if (!dialog.exec()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &fileName = QDir::toNativeSeparators(dialog.selectedFiles().first());
|
||||||
|
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compareTask = new RizinFunctionTask([=](RzCore *) {
|
||||||
|
return Core()->matchFunctionsFromNewFile(fileName);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
task = QSharedPointer<RizinTask>(compareTask);
|
||||||
|
taskDialog = new RizinTaskDialog(task);
|
||||||
|
taskDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
taskDialog->setDesc(tr("Performing function comparison..."));
|
||||||
|
taskDialog->show();
|
||||||
|
|
||||||
|
connect(task.data(), &RizinTask::finished, this, [this, compareTask]() {
|
||||||
|
RzAnalysisMatchResult *result = static_cast<RzAnalysisMatchResult *>(compareTask->getResult());
|
||||||
|
openBinDiffDialog(result);
|
||||||
|
delete taskDialog;
|
||||||
|
taskDialog = nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
compareTask->startTask();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionForward_triggered()
|
void MainWindow::on_actionForward_triggered()
|
||||||
{
|
{
|
||||||
core->seekNext();
|
core->seekNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::openBinDiffDialog(RzAnalysisMatchResult *result)
|
||||||
|
{
|
||||||
|
if (!result) {
|
||||||
|
messageBoxWarning(tr("Error"), tr("Failed to perform the function matching."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binDiffDialog) {
|
||||||
|
delete binDiffDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
binDiffDialog = new BinDiffDialog(result, this);
|
||||||
|
binDiffDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionDisasAdd_comment_triggered()
|
void MainWindow::on_actionDisasAdd_comment_triggered()
|
||||||
{
|
{
|
||||||
CommentsDialog c(this);
|
CommentsDialog c(this);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "core/Cutter.h" // only needed for ut64
|
#include "core/Cutter.h" // only needed for ut64
|
||||||
#include "dialogs/NewFileDialog.h"
|
#include "dialogs/NewFileDialog.h"
|
||||||
#include "dialogs/WelcomeDialog.h"
|
#include "dialogs/WelcomeDialog.h"
|
||||||
|
#include "dialogs/bindiff/BinDiffDialog.h"
|
||||||
#include "common/Configuration.h"
|
#include "common/Configuration.h"
|
||||||
#include "common/InitialOptions.h"
|
#include "common/InitialOptions.h"
|
||||||
#include "common/IOModesController.h"
|
#include "common/IOModesController.h"
|
||||||
@ -151,6 +152,8 @@ public slots:
|
|||||||
|
|
||||||
void openNewFileFailed();
|
void openNewFileFailed();
|
||||||
|
|
||||||
|
void openBinDiffDialog(RzAnalysisMatchResult *result);
|
||||||
|
|
||||||
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
||||||
private slots:
|
private slots:
|
||||||
void on_actionBaseFind_triggered();
|
void on_actionBaseFind_triggered();
|
||||||
@ -176,6 +179,8 @@ private slots:
|
|||||||
void on_actionBackward_triggered();
|
void on_actionBackward_triggered();
|
||||||
void on_actionForward_triggered();
|
void on_actionForward_triggered();
|
||||||
|
|
||||||
|
void on_actionDiff_triggered();
|
||||||
|
|
||||||
void on_actionMap_triggered();
|
void on_actionMap_triggered();
|
||||||
|
|
||||||
void on_actionTabs_on_Top_triggered();
|
void on_actionTabs_on_Top_triggered();
|
||||||
@ -329,6 +334,10 @@ private:
|
|||||||
MemoryDockWidget *lastSyncMemoryWidget = nullptr;
|
MemoryDockWidget *lastSyncMemoryWidget = nullptr;
|
||||||
MemoryDockWidget *lastMemoryWidget = nullptr;
|
MemoryDockWidget *lastMemoryWidget = nullptr;
|
||||||
int functionDockWidthToRestore = 0;
|
int functionDockWidthToRestore = 0;
|
||||||
|
|
||||||
|
QSharedPointer<RizinTask> task;
|
||||||
|
RizinTaskDialog *taskDialog = nullptr;
|
||||||
|
BinDiffDialog *binDiffDialog = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
@ -133,6 +133,7 @@
|
|||||||
<string>Tools</string>
|
<string>Tools</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionBaseFind"/>
|
<addaction name="actionBaseFind"/>
|
||||||
|
<addaction name="actionDiff"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuHelp">
|
<widget class="QMenu" name="menuHelp">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -877,6 +878,11 @@
|
|||||||
<string>Manage layouts</string>
|
<string>Manage layouts</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionDiff">
|
||||||
|
<property name="text">
|
||||||
|
<string>Diff With File..</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources>
|
<resources>
|
||||||
|
137
src/dialogs/bindiff/BinDiffDialog.cpp
Normal file
137
src/dialogs/bindiff/BinDiffDialog.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "core/Cutter.h"
|
||||||
|
#include "BinDiffDialog.h"
|
||||||
|
|
||||||
|
#include "ui_BinDiffDialog.h"
|
||||||
|
#include "common/Configuration.h"
|
||||||
|
#include "common/BugReporting.h"
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <UpdateWorker.h>
|
||||||
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
#include <QtNetwork/QNetworkAccessManager>
|
||||||
|
|
||||||
|
#include "CutterConfig.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
QColor perfect;
|
||||||
|
QColor partial;
|
||||||
|
QColor none;
|
||||||
|
} DiffColors;
|
||||||
|
|
||||||
|
inline QString doubleToString(double number)
|
||||||
|
{
|
||||||
|
return QString::asprintf("%.6f", number);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QTableWidgetItem *newColoredCell(QString text, double similarity, const DiffColors *colors) {
|
||||||
|
auto item = new QTableWidgetItem(text);
|
||||||
|
if (similarity >= 1.0) {
|
||||||
|
item->setBackground(colors->perfect);
|
||||||
|
} else if (similarity >= RZ_ANALYSIS_SIMILARITY_THRESHOLD) {
|
||||||
|
item->setBackground(colors->partial);
|
||||||
|
} else {
|
||||||
|
item->setBackground(colors->none);
|
||||||
|
}
|
||||||
|
item->setForeground(Qt::black);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinDiffDialog::BinDiffDialog(RzAnalysisMatchResult *result, QWidget *parent) : QDialog(parent), ui(new Ui::BinDiffDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||||
|
|
||||||
|
void *ptr;
|
||||||
|
RzListIter *iter = nullptr;
|
||||||
|
RzAnalysisMatchPair *pair = nullptr;
|
||||||
|
const RzAnalysisFunction *fcn_a = nullptr, *fcn_b = nullptr;
|
||||||
|
|
||||||
|
const DiffColors colors = {
|
||||||
|
.perfect = Config()->getColor("gui.match.perfect"),
|
||||||
|
.partial = Config()->getColor("gui.match.partial"),
|
||||||
|
.none = Config()->getColor("gui.match.none"),
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t n_raws = rz_list_length(result->matches);
|
||||||
|
n_raws += rz_list_length(result->unmatch_a);
|
||||||
|
n_raws += rz_list_length(result->unmatch_b);
|
||||||
|
|
||||||
|
QStringList tableHeader = {
|
||||||
|
tr("name"), tr("size"), tr("addr"),
|
||||||
|
tr("type"), tr("similarity"),
|
||||||
|
tr("addr"), tr("size"), tr("name")
|
||||||
|
};
|
||||||
|
|
||||||
|
ui->resultTable->setRowCount(n_raws);
|
||||||
|
ui->resultTable->setColumnCount(8);
|
||||||
|
ui->resultTable->setHorizontalHeaderLabels(tableHeader);
|
||||||
|
ui->resultTable->verticalHeader()->setVisible(false);
|
||||||
|
ui->resultTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
|
|
||||||
|
n_raws = 0;
|
||||||
|
rz_list_foreach(result->matches, iter, ptr) {
|
||||||
|
pair = static_cast<RzAnalysisMatchPair *>(ptr);
|
||||||
|
fcn_a = static_cast<const RzAnalysisFunction *>(pair->pair_a);
|
||||||
|
fcn_b = static_cast<const RzAnalysisFunction *>(pair->pair_b);
|
||||||
|
|
||||||
|
QString size_a = RzSizeString(rz_analysis_function_realsize(fcn_a));
|
||||||
|
QString size_b = RzSizeString(rz_analysis_function_realsize(fcn_b));
|
||||||
|
QString addr_a = RzAddressString(fcn_a->addr);
|
||||||
|
QString addr_b = RzAddressString(fcn_b->addr);
|
||||||
|
QString simtype = RZ_ANALYSIS_SIMILARITY_TYPE_STR(pair->similarity);
|
||||||
|
QString similarity = doubleToString(pair->similarity);
|
||||||
|
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceName, newColoredCell(fcn_a->name, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceSize, newColoredCell(size_a, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceAddr, newColoredCell(addr_a, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSimilarityType, newColoredCell(simtype, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSimilarityNum, newColoredCell(similarity, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchAddr, newColoredCell(addr_b, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchSize, newColoredCell(size_b, pair->similarity, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchName, newColoredCell(fcn_b->name, pair->similarity, &colors));
|
||||||
|
n_raws++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rz_list_foreach(result->unmatch_a, iter, ptr) {
|
||||||
|
fcn_a = static_cast<RzAnalysisFunction *>(ptr);
|
||||||
|
QString size_a = RzSizeString(rz_analysis_function_realsize(fcn_a));
|
||||||
|
QString addr_a = RzAddressString(fcn_a->addr);
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceName, newColoredCell(fcn_a->name, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceSize, newColoredCell(size_a, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceAddr, newColoredCell(addr_a, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSimilarityType, newColoredCell(RZ_ANALYSIS_SIMILARITY_UNLIKE_STR, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSimilarityNum, newColoredCell("0.000000", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchAddr, newColoredCell("------", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchSize, newColoredCell("------", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchName, newColoredCell("------", 0.0, &colors));
|
||||||
|
n_raws++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rz_list_foreach(result->unmatch_b, iter, ptr) {
|
||||||
|
fcn_b = static_cast<RzAnalysisFunction *>(ptr);
|
||||||
|
QString size_b = RzSizeString(rz_analysis_function_realsize(fcn_b));
|
||||||
|
QString addr_b = RzAddressString(fcn_b->addr);
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceName, newColoredCell("------", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceSize, newColoredCell("------", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSourceAddr, newColoredCell("------", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSimilarityType, newColoredCell(RZ_ANALYSIS_SIMILARITY_UNLIKE_STR, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnSimilarityNum, newColoredCell("0.000000", 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchAddr, newColoredCell(fcn_b->name, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchSize, newColoredCell(size_b, 0.0, &colors));
|
||||||
|
ui->resultTable->setItem(n_raws, ColumnMatchName, newColoredCell(addr_b, 0.0, &colors));
|
||||||
|
n_raws++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BinDiffDialog::~BinDiffDialog() {}
|
||||||
|
|
||||||
|
void BinDiffDialog::on_buttonBox_rejected()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
37
src/dialogs/bindiff/BinDiffDialog.h
Normal file
37
src/dialogs/bindiff/BinDiffDialog.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef BINDIFFDIALOG_H
|
||||||
|
#define BINDIFFDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <memory>
|
||||||
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class BinDiffDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BinDiffDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BinDiffDialog(RzAnalysisMatchResult *result, QWidget *parent = nullptr);
|
||||||
|
~BinDiffDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_buttonBox_rejected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
ColumnSourceName = 0,
|
||||||
|
ColumnSourceSize,
|
||||||
|
ColumnSourceAddr,
|
||||||
|
ColumnSimilarityType,
|
||||||
|
ColumnSimilarityNum,
|
||||||
|
ColumnMatchAddr,
|
||||||
|
ColumnMatchSize,
|
||||||
|
ColumnMatchName
|
||||||
|
} BinDiffTableColumn;
|
||||||
|
std::unique_ptr<Ui::BinDiffDialog> ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BINDIFFDIALOG_H
|
55
src/dialogs/bindiff/BinDiffDialog.ui
Normal file
55
src/dialogs/bindiff/BinDiffDialog.ui
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BinDiffDialog</class>
|
||||||
|
<widget class="QDialog" name="BinDiffDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>935</width>
|
||||||
|
<height>554</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Cutter Binary Diffing Tool</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1013</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="defaultUp">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="nativeMenuBar">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuExport">
|
||||||
|
<property name="title">
|
||||||
|
<string>Export</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuExport"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="resultTable"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
Loading…
Reference in New Issue
Block a user