Fix Projects, Some restructuring of OptionsDialog (#165)

* Add Settings, Project Management

* Re-enable -A argument

* Fix loading notes from project
This commit is contained in:
Florian Märkl 2017-05-13 20:09:36 +02:00 committed by C. Balles
parent 23c92ac77c
commit d2df03ee62
13 changed files with 303 additions and 193 deletions

View File

@ -100,7 +100,8 @@ HEADERS += \
widgets/sectionsdock.h \
widgets/dockwidget.h \
widgets/consolewidget.h \
radarewebserver.h
radarewebserver.h \
settings.h
FORMS += \
mainwindow.ui \

View File

@ -23,20 +23,20 @@ int main(int argc, char *argv[])
#endif
QCommandLineParser cmdParser;
cmdParser.setApplicationDescription("A Qt and C++ GUI for radare2 reverse engineering framework");
cmdParser.addHelpOption();
cmdParser.addVersionOption();
cmdParser.addPositionalArgument("filename", QObject::tr("Filename to open."));
QCommandLineParser cmd_parser;
cmd_parser.setApplicationDescription("A Qt and C++ GUI for radare2 reverse engineering framework");
cmd_parser.addHelpOption();
cmd_parser.addVersionOption();
cmd_parser.addPositionalArgument("filename", QObject::tr("Filename to open."));
QCommandLineOption analOption({"A", "anal"},
QCommandLineOption anal_option({"A", "anal"},
QObject::tr("Automatically start analysis. Needs filename to be specified. May be a value between 0 and 4."),
QObject::tr("level"));
cmdParser.addOption(analOption);
cmd_parser.addOption(anal_option);
cmdParser.process(a);
cmd_parser.process(a);
QStringList args = cmdParser.positionalArguments();
QStringList args = cmd_parser.positionalArguments();
// Check r2 version
QString r2version = r_core_version();
@ -55,14 +55,14 @@ int main(int argc, char *argv[])
bool analLevelSpecified = false;
int analLevel = 0;
bool anal_level_specified = false;
int anal_level = 0;
if (cmdParser.isSet(analOption))
if (cmd_parser.isSet(anal_option))
{
analLevel = cmdParser.value(analOption).toInt(&analLevelSpecified);
anal_level = cmd_parser.value(anal_option).toInt(&anal_level_specified);
if (!analLevelSpecified || analLevel < 0 || analLevel > 4)
if (!anal_level_specified || anal_level < 0 || anal_level > 4)
{
printf("%s\n", QObject::tr("Invalid Analysis Level. May be a value between 0 and 4.").toLocal8Bit().constData());
return 1;
@ -72,7 +72,7 @@ int main(int argc, char *argv[])
if (args.empty())
{
if (analLevelSpecified)
if (anal_level_specified)
{
printf("%s\n", QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData());
return 1;
@ -84,12 +84,8 @@ int main(int argc, char *argv[])
}
else // filename specified as positional argument
{
OptionsDialog *o = new OptionsDialog(args[0]);
o->setAttribute(Qt::WA_DeleteOnClose);
o->show();
if (analLevelSpecified)
o->setupAndStartAnalysis(analLevel);
MainWindow *main = new MainWindow();
main->openFile(args[0], anal_level_specified ? anal_level : -1);
}
return a.exec();

View File

@ -61,6 +61,8 @@
#include "widgets/sdbdock.h"
#include "widgets/omnibar.h"
#include "widgets/consolewidget.h"
#include "settings.h"
#include "optionsdialog.h"
// graphics
#include <QGraphicsEllipseItem>
@ -81,9 +83,9 @@ static void registerCustomFonts()
Q_UNUSED(ret)
}
MainWindow::MainWindow(QWidget *parent, QRCore *kore) :
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
core(kore),
core(new QRCore()),
memoryDock(nullptr),
notepadDock(nullptr),
asmDock(nullptr),
@ -109,15 +111,23 @@ MainWindow::MainWindow(QWidget *parent, QRCore *kore) :
consoleWidget(nullptr),
webserver(core)
{
this->start_web_server();
ui->setupUi(this);
doLock = false;
this->cursor_address = core->getOffset();
}
MainWindow::~MainWindow()
{
delete ui;
delete core;
}
void MainWindow::initUI()
{
ui->setupUi(this);
registerCustomFonts();
/*
* Toolbar
*/
@ -268,10 +278,159 @@ MainWindow::MainWindow(QWidget *parent, QRCore *kore) :
connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshVisibleDockWidgets()));
}
MainWindow::~MainWindow()
void MainWindow::openFile(const QString &fn, int anal_level)
{
delete ui;
delete core;
QString project_name = qhelpers::uniqueProjectName(fn);
if(core->getProjectNames().contains(project_name))
openProject(project_name);
else
openNewFile(fn, anal_level);
}
void MainWindow::openNewFile(const QString &fn, int anal_level)
{
setFilename(fn);
OptionsDialog *o = new OptionsDialog(this);
o->setAttribute(Qt::WA_DeleteOnClose);
o->show();
if(anal_level >= 0)
o->setupAndStartAnalysis(anal_level);
}
void MainWindow::openProject(const QString &project_name)
{
QString filename = core->cmd("Pi " + project_name);
setFilename(filename.trimmed());
core->cmd("Po " + project_name);
initUI();
finalizeOpen();
}
void MainWindow::finalizeOpen()
{
core->getOpcodes();
// Set settings to override any incorrect saved in the project
core->setSettings();
addOutput(" > Populating UI");
// FIXME: initialization order frakup. the next line is needed so that the
// comments widget displays the function names.
core->cmd("fs sections");
updateFrames();
get_refs(core->cmd("?v entry0"));
memoryDock->selectHexPreview();
// Restore project notes
QString notes = this->core->cmd("Pnj");
//qDebug() << "Notes:" << notes;
if (notes != "")
{
QByteArray ba;
ba.append(notes);
notepadDock->setText(QByteArray::fromBase64(ba));
}
else
{
addOutput(" > Adding binary information to notepad");
notepadDock->setText("# Binary information\n\n" + core->cmd("i") +
"\n" + core->cmd("ie") + "\n" + core->cmd("iM") + "\n");
}
//Get binary beginning/end addresses
this->core->binStart = this->core->cmd("?v $M");
this->core->binEnd = this->core->cmd("?v $M+$s");
addOutput(" > Finished, happy reversing :)");
// Add fortune message
addOutput("\n" + core->cmd("fo"));
memoryDock->setWindowTitle("entry0");
start_web_server();
showMaximized();
// Initialize syntax highlighters
memoryDock->highlightDisasms();
notepadDock->highlightPreview();
}
void MainWindow::applySettings()
{
Settings settings;
// Show asm bytes
if (settings.getAsmBytes())
{
core->config("asm.bytes", "true");
core->config("asm.cmtcol", "100");
}
else
{
core->config("asm.bytes", "false");
core->config("asm.cmtcol", "70");
}
// Show AT&T syntax
if (settings.getATnTSyntax())
core->config("asm.syntax", "att");
else
core->config("asm.syntax", "intel");
// Show opcode description
if (settings.getOpcodeDescription())
{
core->config("asm.describe", "true");
}
else
{
core->config("asm.describe", "false");
}
// Show stack pointer
if (settings.getStackPointer())
{
core->config("asm.stackptr", "true");
}
else
{
core->config("asm.stackptr", "false");
}
// Show uppercase dasm
if (settings.getUppercaseDisas())
{
core->config("asm.ucase", "true");
}
else
{
core->config("asm.ucase", "false");
}
// Show spaces in dasm
if (settings.getSpacy())
{
core->config("asm.spacy", "true");
}
else
{
core->config("asm.spacy", "false");
}
}
void MainWindow::saveProject()
{
QString project_name = qhelpers::uniqueProjectName(filename);
core->cmd("Ps " + project_name);
QString notes = this->notepadDock->textToBase64();
//this->add_debug_output(notes);
this->core->cmd("Pnj " + notes);
this->addOutput("Project saved: " + project_name);
}
void MainWindow::start_web_server()
@ -333,10 +492,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.setValue("state", saveState());
core->cmd("Ps " + qhelpers::uniqueProjectName(filename));
QString notes = this->notepadDock->textToBase64();
//this->add_debug_output(notes);
this->core->cmd("Pnj " + notes);
saveProject();
QMainWindow::closeEvent(event);
}
else if (ret == QMessageBox::Discard)
@ -842,11 +998,7 @@ void MainWindow::on_actionNew_triggered()
void MainWindow::on_actionSave_triggered()
{
core->cmd("Ps " + qhelpers::uniqueProjectName(filename));
QString notes = this->notepadDock->textToBase64();
//this->add_debug_output(notes);
this->core->cmd("Pnj " + notes);
this->addOutput("Project saved");
saveProject();
}
void MainWindow::on_actionRun_Script_triggered()

View File

@ -49,9 +49,17 @@ public:
bool responsive;
explicit MainWindow(QWidget *parent = 0, QRCore *kore = nullptr);
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void openFile(const QString &fn, int anal_level = -1);
void initUI();
void finalizeOpen();
void applySettings();
void saveProject();
void start_web_server();
void closeEvent(QCloseEvent *event);
void readSettings();
@ -202,9 +210,14 @@ private:
RVA cursor_address;
void openProject(const QString &project_name);
void openNewFile(const QString &fn, int anal_level);
public:
RVA getCursorAddress() const { return cursor_address; }
void setCursorAddress(RVA addr);
QString getFilename() const { return filename; }
};
#endif // MAINWINDOW_H

View File

@ -114,10 +114,13 @@ void NewFileDialog::on_loadFileButton_clicked()
settings.setValue("recentFileList", files);
// Close dialog and open OptionsDialog
close();
OptionsDialog *o = new OptionsDialog(fname);
o->exec();
// Close dialog and open MainWindow/OptionsDialog
MainWindow *main = new MainWindow();
main->openFile(fname);
//OptionsDialog *o = new OptionsDialog(fname);
//o->exec();
}
}
@ -152,8 +155,11 @@ void NewFileDialog::on_recentsList_itemDoubleClicked(QListWidgetItem *item)
QString sitem = data.toString();
// Close dialog and open OptionsDialog
close();
OptionsDialog *o = new OptionsDialog(sitem);
o->exec();
MainWindow *main = new MainWindow();
main->openFile(sitem);
//OptionsDialog *o = new OptionsDialog(sitem);
//o->exec();
}
void NewFileDialog::on_cancelButton_clicked()

View File

@ -7,17 +7,16 @@
// TODO: remove us
#include "widgets/memorywidget.h"
#include "widgets/notepad.h"
#include "settings.h"
#include <QSettings>
OptionsDialog::OptionsDialog(const QString &filename, QWidget *parent):
QDialog(parent),
OptionsDialog::OptionsDialog(MainWindow *main):
QDialog(0), // parent may not be main
ui(new Ui::OptionsDialog),
core(new QRCore()),
analThread(this),
w(nullptr),
filename(filename),
main(main),
defaultAnalLevel(3)
{
ui->setupUi(this);
@ -28,7 +27,7 @@ OptionsDialog::OptionsDialog(const QString &filename, QWidget *parent):
ui->analSlider->setValue(defaultAnalLevel);
// Fill the plugins combo
asm_plugins = core->getAsmPluginNames();
asm_plugins = main->core->getAsmPluginNames();
for (auto plugin : asm_plugins)
ui->processorComboBox->addItem(plugin, plugin);
@ -48,8 +47,8 @@ OptionsDialog::OptionsDialog(const QString &filename, QWidget *parent):
connect(&analThread, SIGNAL(finished()), this, SLOT(anal_finished()));
ui->programLineEdit->setText(filename);
this->core->tryFile(filename, true);
ui->programLineEdit->setText(main->getFilename());
this->main->core->tryFile(main->getFilename(), true);
}
OptionsDialog::~OptionsDialog()
@ -73,87 +72,24 @@ void OptionsDialog::setupAndStartAnalysis(int level)
ui->statusLabel->setText("Starting analysis");
//ui->progressBar->setValue(5);
// Close dialog and open OptionsDialog
this->w = new MainWindow(0, this->core);
// Fill asm plugins in hexdump combo
this->w->memoryDock->fillPlugins(this->asm_plugins);
int va = ui->vaCheckBox->isChecked();
ut64 loadaddr = 0LL;
ut64 mapaddr = 0LL;
// Save options in settings
QSettings settings;
Settings settings;
settings.setAsmBytes(ui->bytesCheckBox->isChecked());
settings.setATnTSyntax(ui->attCheckBox->isChecked());
settings.setOpcodeDescription(ui->descriptionCheckBox->isChecked());
settings.setStackPointer(ui->stackCheckBox->isChecked());
settings.setUppercaseDisas(ui->ucaseCheckBox->isChecked());
settings.setSpacy(ui->spacyCheckBox->isChecked());
// Show asm bytes
if (ui->bytesCheckBox->isChecked())
{
this->w->core->config("asm.bytes", "true");
this->w->core->config("asm.cmtcol", "100");
}
else
{
this->w->core->config("asm.bytes", "false");
this->w->core->config("asm.cmtcol", "70");
}
settings.setValue("bytes", ui->bytesCheckBox->isChecked());
// Show AT&T syntax
if (ui->attCheckBox->isChecked())
{
this->w->core->config("asm.syntax", "att");
}
else
{
this->w->core->config("asm.syntax", "intel");
}
settings.setValue("syntax", ui->attCheckBox->isChecked());
// Show opcode description
if (ui->descriptionCheckBox->isChecked())
{
this->w->core->config("asm.describe", "true");
}
else
{
this->w->core->config("asm.describe", "false");
}
settings.setValue("describe", ui->descriptionCheckBox->isChecked());
// Show stack pointer
if (ui->stackCheckBox->isChecked())
{
this->w->core->config("asm.stackptr", "true");
}
else
{
this->w->core->config("asm.stackptr", "false");
}
settings.setValue("stackptr", ui->stackCheckBox->isChecked());
// Show uppercase dasm
if (ui->ucaseCheckBox->isChecked())
{
this->w->core->config("asm.ucase", "true");
}
else
{
this->w->core->config("asm.ucase", "false");
}
settings.setValue("ucase", ui->ucaseCheckBox->isChecked());
// Show spaces in dasm
if (ui->spacyCheckBox->isChecked())
{
this->w->core->config("asm.spacy", "true");
}
else
{
this->w->core->config("asm.spacy", "false");
}
settings.setValue("spacy", ui->spacyCheckBox->isChecked());
main->initUI();
// Apply options set above in MainWindow
main->applySettings();
//
@ -168,9 +104,9 @@ void OptionsDialog::setupAndStartAnalysis(int level)
bits = sel_bits.toInt();
}
w->core->setCPU(archValue.isValid() ? archValue.toString() : NULL,
QString(),
bits);
main->core->setCPU(archValue.isValid() ? archValue.toString() : NULL,
QString(),
bits);
@ -183,7 +119,7 @@ void OptionsDialog::setupAndStartAnalysis(int level)
{
va = 2;
loadaddr = UT64_MAX;
r_config_set_i(this->core->core()->config, "bin.laddr", loadaddr);
r_config_set_i(main->core->core()->config, "bin.laddr", loadaddr);
mapaddr = 0;
}
}
@ -198,15 +134,15 @@ void OptionsDialog::setupAndStartAnalysis(int level)
// options dialog should show the list of archs inside the given fatbin
int binidx = 0; // index of subbin
this->w->addOutput(" > Loading file: " + this->filename);
this->w->core->loadFile(this->filename, loadaddr, mapaddr, rw, va, binidx, load_bininfo);
main->addOutput(" > Loading file: " + main->getFilename());
main->core->loadFile(main->getFilename(), loadaddr, mapaddr, rw, va, binidx, load_bininfo);
//ui->progressBar->setValue(40);
ui->statusLabel->setText("Analysis in progress");
// Threads stuff
// connect signal/slot
analThread.start(core, level);
analThread.start(main->core, level);
}
void OptionsDialog::on_closeButton_clicked()
@ -221,68 +157,29 @@ void OptionsDialog::on_okButton_clicked()
void OptionsDialog::anal_finished()
{
// Get opcodes
this->w->core->getOpcodes();
//fprintf(stderr, "anal done");
//ui->progressBar->setValue(70);
const QString uniqueName(qhelpers::uniqueProjectName(filename));
this->w->core->cmd("Po " + uniqueName);
// Set settings to override any incorrect saved in the project
this->core->setSettings();
ui->statusLabel->setText("Loading interface");
this->w->addOutput(" > Analysis finished");
main->addOutput(" > Analysis finished");
QString initial_seek = ui->entry_initialSeek->text();
if (initial_seek.length() > 0)
{
this->w->core->seek(initial_seek);
main->core->seek(initial_seek);
}
else
{
this->w->core->seek("entry0");
}
this->w->addOutput(" > Populating UI");
// FIXME: initialization order frakup. the next line is needed so that the
// comments widget displays the function names.
core->cmd("fs sections");
this->w->updateFrames();
this->w->setFilename(this->filename);
this->w->get_refs(this->w->core->cmd("?v entry0"));
this->w->memoryDock->selectHexPreview();
// Restore project notes
QString notes = this->core->cmd("Pn");
//qDebug() << "Notes:" << notes;
if (notes != "")
{
QByteArray ba;
ba.append(notes);
this->w->notepadDock->setText(QByteArray::fromBase64(ba));
main->core->seek("entry0");
}
//Get binary beginning/end addresses
this->core->binStart = this->core->cmd("?v $M");
this->core->binEnd = this->core->cmd("?v $M+$s");
this->w->addOutput(" > Finished, happy reversing :)");
// Add fortune message
this->w->addOutput("\n" + this->w->core->cmd("fo"));
this->w->memoryDock->setWindowTitle("entry0");
this->w->start_web_server();
main->finalizeOpen();
close();
this->w->showMaximized();
// Initialize syntax highlighters
this->w->memoryDock->highlightDisasms();
this->w->notepadDock->highlightPreview();
}
void OptionsDialog::on_cancelButton_clicked()
{
delete this->core;
this->core = NULL;
//delete this->core;
//this->core = NULL;
// Close dialog and open OptionsDialog
delete main;
close();
NewFileDialog *n = new NewFileDialog(nullptr);
n->show();

View File

@ -19,7 +19,7 @@ class OptionsDialog : public QDialog
Q_OBJECT
public:
explicit OptionsDialog(const QString &filename, QWidget *parent = 0);
explicit OptionsDialog(MainWindow *main);
~OptionsDialog();
RAnalFunction functionAt(ut64 addr);
QStringList asm_plugins;
@ -43,10 +43,8 @@ private slots:
private:
Ui::OptionsDialog *ui;
QRCore *core;
AnalThread analThread;
MainWindow *w;
QString filename;
MainWindow *main;
int defaultAnalLevel;
QString analysisDescription(int level);

View File

@ -211,6 +211,7 @@ QRCore::~QRCore()
QString QRCore::cmd(const QString &str)
{
CORE_LOCK();
QByteArray cmd = str.toUtf8();
//r_cons_flush();
char *res = r_core_cmd_str(this->core_, cmd.constData());
@ -848,6 +849,20 @@ QStringList QRCore::getAnalPluginNames()
}
QStringList QRCore::getProjectNames()
{
CORE_LOCK();
QStringList ret;
QJsonArray jsonArray = cmdj("Plj").array();
for(QJsonValue value : jsonArray)
ret.append(value.toString());
return ret;
}
QList<FunctionDescription> QRCore::getAllFunctions()
{
CORE_LOCK();
@ -1081,4 +1096,4 @@ QList<SectionDescription> QRCore::getAllSections()
ret << section;
}
return ret;
}
}

View File

@ -203,6 +203,8 @@ public:
QStringList getAsmPluginNames();
QStringList getAnalPluginNames();
QStringList getProjectNames();
QList<FunctionDescription> getAllFunctions();
QList<ImportDescription> getAllImports();
QList<SymbolDescription> getAllSymbols();

32
src/settings.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QtCore/QSettings>
class Settings
{
private:
QSettings settings;
public:
bool getAsmBytes() const { return settings.value("bytes", false).toBool(); }
void setAsmBytes(bool v) { settings.setValue("bytes", v); }
bool getATnTSyntax() const { return settings.value("syntax", false).toBool(); }
void setATnTSyntax(bool v) { settings.setValue("syntax", v); }
bool getOpcodeDescription() const { return settings.value("describe", false).toBool(); }
void setOpcodeDescription(bool v) { settings.setValue("describe", v); }
bool getStackPointer() const { return settings.value("stackptr", false).toBool(); }
void setStackPointer(bool v) { settings.setValue("stackptr", v); }
bool getUppercaseDisas() const { return settings.value("ucase", false).toBool(); }
void setUppercaseDisas(bool v) { settings.setValue("ucase", v); }
bool getSpacy() const { return settings.value("spacy", false).toBool(); }
void setSpacy(bool v) { settings.setValue("spacy", v); }
};
#endif // SETTINGS_H

View File

@ -193,6 +193,8 @@ MemoryWidget::MemoryWidget(MainWindow *main) :
connect(ui->graphWebView->page(), SIGNAL(loadFinished(bool)), this, SLOT(frameLoadFinished(bool)));
connect(main, SIGNAL(cursorAddressChanged(RVA)), this, SLOT(on_cursorAddressChanged(RVA)));
fillPlugins();
}
@ -418,10 +420,10 @@ void MemoryWidget::refresh()
* Content management functions
*/
void MemoryWidget::fillPlugins(QStringList plugins)
void MemoryWidget::fillPlugins()
{
// Fill the plugins combo for the hexdump sidebar
ui->hexArchComboBox_2->insertItems(0, plugins);
ui->hexArchComboBox_2->insertItems(0, main->core->getAsmPluginNames());
}
void MemoryWidget::addTextDisasm(QString txt)

View File

@ -60,7 +60,7 @@ signals:
void fontChanged(QFont font);
public slots:
void fillPlugins(QStringList plugins);
void fillPlugins();
void addTextDisasm(QString txt);

View File

@ -49,10 +49,6 @@ Notepad::~Notepad()
void Notepad::setup()
{
main->addOutput(" > Adding binary information to notepad");
setText("# Binary information\n\n" + main->core->cmd("i") +
"\n" + main->core->cmd("ie") + "\n" + main->core->cmd("iM") + "\n");
}
void Notepad::refresh()