Improve InitialOptionsDialog and modify UI terminology for analysis (#1669)

* Define CommandDescription struct

* Refactor InitialOptionsDialog to to work with CommandDescription

* Clean InitialOptionsDialog UI
This commit is contained in:
Itay Cohen 2019-08-04 00:58:41 +03:00 committed by GitHub
parent 2f0c0ddc23
commit 330795a650
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 225 deletions

View File

@ -173,10 +173,10 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
options.analCmd = {}; options.analCmd = {};
break; break;
case 1: case 1:
options.analCmd = { "aaa" }; options.analCmd = { {"aaa", "Auto analysis"} };
break; break;
case 2: case 2:
options.analCmd = { "aaaa" }; options.analCmd = { {"aaaa", "Auto analysis (experimental)"} };
break; break;
} }
} }

View File

@ -96,13 +96,13 @@ void AnalTask::runTask()
Core()->setConfig("prj.simple", true); Core()->setConfig("prj.simple", true);
if (!options.analCmd.empty()) { if (!options.analCmd.empty()) {
log(tr("Analyzing...")); log(tr("Executing analysis..."));
for (const QString &cmd : options.analCmd) { for (const CommandDescription &cmd : options.analCmd) {
if (isInterrupted()) { if (isInterrupted()) {
return; return;
} }
log(" " + tr("Running") + " " + cmd); log(cmd.description);
Core()->cmd(cmd); Core()->cmd(cmd.command);
} }
log(tr("Analysis complete!")); log(tr("Analysis complete!"));
} else { } else {

View File

@ -4,6 +4,14 @@
#include "core/Cutter.h" #include "core/Cutter.h"
/**
* @brief The CommandDescription struct is a pair of a radare2 command and its description
*/
struct CommandDescription {
QString command;
QString description;
};
struct InitialOptions struct InitialOptions
{ {
enum class Endianness { Auto, Little, Big }; enum class Endianness { Auto, Little, Big };
@ -30,7 +38,7 @@ struct InitialOptions
QString pdbFile; QString pdbFile;
QString script; QString script;
QList<QString> analCmd = { "aaa" }; QList<CommandDescription> analCmd = { {"aaa", "Auto analysis"} };
QString shellcode; QString shellcode;
}; };

View File

@ -50,8 +50,36 @@ InitialOptionsDialog::InitialOptionsDialog(MainWindow *main):
ui->formatComboBox->addItem(plugin.name, QVariant::fromValue(plugin)); ui->formatComboBox->addItem(plugin.name, QVariant::fromValue(plugin));
} }
analysisCommands = {
{ { "aa", tr("Analyze all symbols") }, new QCheckBox(), true },
{ { "aar", tr("Analyze instructions for references") }, new QCheckBox(), true },
{ { "aac", tr("Analyze function calls") }, new QCheckBox(), true },
{ { "aab", tr("Analyze all basic blocks") }, new QCheckBox(), false },
{ { "aao", tr("Analyze all objc references") }, new QCheckBox(), false },
{ { "avrr", tr("Recover class information from RTTI") }, new QCheckBox(), false },
{ { "aan", tr("Autoname functions based on context") }, new QCheckBox(), false },
{ { "aae", tr("Emulate code to find computed references") }, new QCheckBox(), false },
{ { "aat", tr("Analyze all consecutive functions") }, new QCheckBox(), false },
{ { "aaft", tr("Type and Argument matching analysis") }, new QCheckBox(), false },
{ { "aaT", tr("Analyze code after trap-sleds") }, new QCheckBox(), false },
{ { "aap", tr("Analyze function preludes") }, new QCheckBox(), false },
{ { "e! anal.jmp.tbl", tr("Analyze jump tables in switch statements") }, new QCheckBox(), false },
{ { "e! anal.pushret", tr("Analyze PUSH+RET as JMP") }, new QCheckBox(), false },
{ { "e! anal.hasnext", tr("Continue analysis after each function") }, new QCheckBox(), false }};
// Per each checkbox, set a tooltip desccribing it
AnalysisCommands item;
foreach (item, analysisCommands){
item.checkbox->setText(item.commandDesc.description);
item.checkbox->setToolTip(item.commandDesc.command);
item.checkbox->setChecked(item.checked);
ui->verticalLayout_7->addWidget(item.checkbox);
}
ui->hideFrame->setVisible(false); ui->hideFrame->setVisible(false);
ui->analoptionsFrame->setVisible(false); ui->analoptionsFrame->setVisible(false);
ui->advancedAnlysisLine->setVisible(false);
updatePDBLayout(); updatePDBLayout();
@ -86,30 +114,30 @@ void InitialOptionsDialog::updateCPUComboBox()
ui->cpuComboBox->lineEdit()->setText(currentText); ui->cpuComboBox->lineEdit()->setText(currentText);
} }
QList<QString> InitialOptionsDialog::getAnalysisCommands(const InitialOptions &options) {
QList<QString> commands;
for (auto& commandDesc: options.analCmd) {
commands << commandDesc.command;
}
return commands;
}
void InitialOptionsDialog::loadOptions(const InitialOptions &options) void InitialOptionsDialog::loadOptions(const InitialOptions &options)
{ {
if (options.analCmd.isEmpty()) { if (options.analCmd.isEmpty()) {
analLevel = 0; analLevel = 0;
} else if (options.analCmd == QList<QString>({ "aaa" })) { } else if (options.analCmd.first().command == "aaa" ) {
analLevel = 1; analLevel = 1;
} else if (options.analCmd == QList<QString>({ "aaaa" })) { } else if (options.analCmd.first().command == "aaaa" ) {
analLevel = 2; analLevel = 2;
} else { } else {
analLevel = 3; analLevel = 3;
// TODO: These checks must always be in sync with getSelectedAdvancedAnalCmds(), which is dangerous AnalysisCommands item;
ui->aa_symbols->setChecked(options.analCmd.contains("aa")); QList<QString> commands = getAnalysisCommands(options);
ui->aar_references->setChecked(options.analCmd.contains("aar")); foreach (item, analysisCommands){
ui->aac_calls->setChecked(options.analCmd.contains("aac")); qInfo() << item.commandDesc.command;
ui->aab_basicblocks->setChecked(options.analCmd.contains("aab")); item.checkbox->setChecked(commands.contains(item.commandDesc.command));
ui->aan_rename->setChecked(options.analCmd.contains("aan")); }
ui->aae_emulate->setChecked(options.analCmd.contains("aae"));
ui->aat_consecutive->setChecked(options.analCmd.contains("aat"));
ui->afta_typeargument->setChecked(options.analCmd.contains("afta"));
ui->aaT_aftertrap->setChecked(options.analCmd.contains("aaT"));
ui->aap_preludes->setChecked(options.analCmd.contains("aap"));
ui->jmptbl->setChecked(options.analCmd.contains("e! anal.jmptbl"));
ui->pushret->setChecked(options.analCmd.contains("e! anal.pushret"));
ui->hasnext->setChecked(options.analCmd.contains("e! anal.hasnext"));
} }
if (!options.script.isEmpty()) { if (!options.script.isEmpty()) {
@ -171,55 +199,15 @@ QString InitialOptionsDialog::getSelectedOS() const
return os.isValid() ? os.toString() : nullptr; return os.isValid() ? os.toString() : nullptr;
} }
QList<QString> InitialOptionsDialog::getSelectedAdvancedAnalCmds() const QList<CommandDescription> InitialOptionsDialog::getSelectedAdvancedAnalCmds() const
{ {
QList<QString> advanced = QList<QString>(); QList<CommandDescription> advanced = QList<CommandDescription>();
if (ui->analSlider->value() == 3) { if (ui->analSlider->value() == 3) {
// Enable analysis configurations before executing analysis commands AnalysisCommands item;
if (ui->jmptbl->isChecked()) { foreach (item, analysisCommands){
advanced << "e! anal.jmptbl"; if(item.checkbox->isChecked()) {
} advanced << item.commandDesc;
if (ui->pushret->isChecked()) { }
advanced << "e! anal.pushret";
}
if (ui->hasnext->isChecked()) {
advanced << "e! anal.hasnext";
}
if (ui->aa_symbols->isChecked()) {
advanced << "aa";
}
if (ui->aar_references->isChecked()) {
advanced << "aar";
}
if (ui->aac_calls->isChecked()) {
advanced << "aac";
}
if (ui->aab_basicblocks->isChecked()) {
advanced << "aab";
}
if (ui->aao_objc->isChecked()) {
advanced << "aao";
}
if (ui->avrr_vtables->isChecked()) {
advanced << "avrr";
}
if (ui->aan_rename->isChecked()) {
advanced << "aan";
}
if (ui->aae_emulate->isChecked()) {
advanced << "aae";
}
if (ui->aat_consecutive->isChecked()) {
advanced << "aat";
}
if (ui->afta_typeargument->isChecked()) {
advanced << "afta";
}
if (ui->aaT_aftertrap->isChecked()) {
advanced << "aaT";
}
if (ui->aap_preludes->isChecked()) {
advanced << "aap";
} }
} }
return advanced; return advanced;
@ -269,10 +257,10 @@ void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList<QString> adv
int level = ui->analSlider->value(); int level = ui->analSlider->value();
switch (level) { switch (level) {
case 1: case 1:
options.analCmd = { "aaa" }; options.analCmd = { {"aaa", "Auto analysis"} };
break; break;
case 2: case 2:
options.analCmd = { "aaaa" }; options.analCmd = { {"aaaa", "Auto analysis (experimental}"} };
break; break;
case 3: case 3:
options.analCmd = getSelectedAdvancedAnalCmds(); options.analCmd = getSelectedAdvancedAnalCmds();
@ -346,8 +334,10 @@ void InitialOptionsDialog::on_analSlider_valueChanged(int value)
ui->analCheckBox->setText(tr("Analysis: Enabled")); ui->analCheckBox->setText(tr("Analysis: Enabled"));
if (value == 3) { if (value == 3) {
ui->analoptionsFrame->setVisible(true); ui->analoptionsFrame->setVisible(true);
ui->advancedAnlysisLine->setVisible(true);
} else { } else {
ui->analoptionsFrame->setVisible(false); ui->analoptionsFrame->setVisible(false);
ui->advancedAnlysisLine->setVisible(false);
} }
} }
} }

View File

@ -2,6 +2,7 @@
#define OPTIONSDIALOG_H #define OPTIONSDIALOG_H
#include <QDialog> #include <QDialog>
#include <QCheckBox>
#include <memory> #include <memory>
#include "common/InitialOptions.h" #include "common/InitialOptions.h"
@ -49,13 +50,20 @@ private:
void updateCPUComboBox(); void updateCPUComboBox();
struct AnalysisCommands {
CommandDescription commandDesc;
QCheckBox *checkbox;
bool checked;
};
QList<AnalysisCommands> analysisCommands;
QList<QString> getAnalysisCommands(const InitialOptions &options);
QString getSelectedArch() const; QString getSelectedArch() const;
QString getSelectedCPU() const; QString getSelectedCPU() const;
int getSelectedBits() const; int getSelectedBits() const;
InitialOptions::Endianness getSelectedEndianness() const; InitialOptions::Endianness getSelectedEndianness() const;
QString getSelectedOS() const; QString getSelectedOS() const;
QList<QString> getSelectedAdvancedAnalCmds() const; QList<CommandDescription> getSelectedAdvancedAnalCmds() const;
public: public:
void loadOptions(const InitialOptions &options); void loadOptions(const InitialOptions &options);

View File

@ -221,8 +221,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>564</width> <width>567</width>
<height>867</height> <height>418</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_5">
@ -269,9 +269,12 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing"> <property name="spacing">
<number>5</number> <number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property> </property>
<item> <item>
<widget class="QFrame" name="analoptionsFrame"> <widget class="QFrame" name="analoptionsFrame">
@ -300,156 +303,19 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>5</number> <number>5</number>
</property> </property>
<item>
<widget class="QCheckBox" name="aa_symbols">
<property name="text">
<string>Analyze all symbols (aa)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aar_references">
<property name="text">
<string>Analyze for references (aar)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aac_calls">
<property name="text">
<string>Analyze function calls (aac)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aab_basicblocks">
<property name="text">
<string>Analyze all basic blocks (aab)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aan_rename">
<property name="text">
<string>Autorename functions based on context (aan)</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aao_objc">
<property name="text">
<string> Analyze all objc references (aao)</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="avrr_vtables">
<property name="text">
<string> Recover class information (avrr)</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Experimental:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aae_emulate">
<property name="text">
<string>Emulate code to find computed references (aae)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aat_consecutive">
<property name="text">
<string>Analyze for consecutive function (aat)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="afta_typeargument">
<property name="text">
<string>Type and Argument matching analysis (afta)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aaT_aftertrap">
<property name="text">
<string>Analyze code after trap-sleds (aaT)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="aap_preludes">
<property name="text">
<string>Analyze function preludes (aap)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="jmptbl">
<property name="text">
<string>Analyze jump tables in switch statements (e! anal.jmptbl)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="pushret">
<property name="text">
<string>Analyze push+ret as jmp (e! anal.pushret)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="hasnext">
<property name="text">
<string>Continue analysis after each function (e! anal.hasnext)</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
</layout> <item>
</item> <widget class="Line" name="advancedAnlysisLine">
<item> <property name="orientation">
<layout class="QVBoxLayout" name="verticalLayout_2"> <enum>Qt::Horizontal</enum>
<property name="spacing"> </property>
<number>0</number> <property name="visible">
</property> <bool>false</bool>
<property name="sizeConstraint"> </property>
<enum>QLayout::SetMinimumSize</enum> </widget>
</property> </item>
<item> <item>
<widget class="QCheckBox" name="writeCheckBox"> <widget class="QCheckBox" name="writeCheckBox">
<property name="text"> <property name="text">