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 = {};
break;
case 1:
options.analCmd = { "aaa" };
options.analCmd = { {"aaa", "Auto analysis"} };
break;
case 2:
options.analCmd = { "aaaa" };
options.analCmd = { {"aaaa", "Auto analysis (experimental)"} };
break;
}
}

View File

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

View File

@ -4,6 +4,14 @@
#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
{
enum class Endianness { Auto, Little, Big };
@ -29,8 +37,8 @@ struct InitialOptions
QString pdbFile;
QString script;
QList<QString> analCmd = { "aaa" };
QList<CommandDescription> analCmd = { {"aaa", "Auto analysis"} };
QString shellcode;
};

View File

@ -50,8 +50,36 @@ InitialOptionsDialog::InitialOptionsDialog(MainWindow *main):
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->analoptionsFrame->setVisible(false);
ui->advancedAnlysisLine->setVisible(false);
updatePDBLayout();
@ -86,30 +114,30 @@ void InitialOptionsDialog::updateCPUComboBox()
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)
{
if (options.analCmd.isEmpty()) {
analLevel = 0;
} else if (options.analCmd == QList<QString>({ "aaa" })) {
} else if (options.analCmd.first().command == "aaa" ) {
analLevel = 1;
} else if (options.analCmd == QList<QString>({ "aaaa" })) {
} else if (options.analCmd.first().command == "aaaa" ) {
analLevel = 2;
} else {
analLevel = 3;
// TODO: These checks must always be in sync with getSelectedAdvancedAnalCmds(), which is dangerous
ui->aa_symbols->setChecked(options.analCmd.contains("aa"));
ui->aar_references->setChecked(options.analCmd.contains("aar"));
ui->aac_calls->setChecked(options.analCmd.contains("aac"));
ui->aab_basicblocks->setChecked(options.analCmd.contains("aab"));
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"));
AnalysisCommands item;
QList<QString> commands = getAnalysisCommands(options);
foreach (item, analysisCommands){
qInfo() << item.commandDesc.command;
item.checkbox->setChecked(commands.contains(item.commandDesc.command));
}
}
if (!options.script.isEmpty()) {
@ -171,55 +199,15 @@ QString InitialOptionsDialog::getSelectedOS() const
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) {
// Enable analysis configurations before executing analysis commands
if (ui->jmptbl->isChecked()) {
advanced << "e! anal.jmptbl";
}
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";
AnalysisCommands item;
foreach (item, analysisCommands){
if(item.checkbox->isChecked()) {
advanced << item.commandDesc;
}
}
}
return advanced;
@ -269,10 +257,10 @@ void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList<QString> adv
int level = ui->analSlider->value();
switch (level) {
case 1:
options.analCmd = { "aaa" };
options.analCmd = { {"aaa", "Auto analysis"} };
break;
case 2:
options.analCmd = { "aaaa" };
options.analCmd = { {"aaaa", "Auto analysis (experimental}"} };
break;
case 3:
options.analCmd = getSelectedAdvancedAnalCmds();
@ -346,8 +334,10 @@ void InitialOptionsDialog::on_analSlider_valueChanged(int value)
ui->analCheckBox->setText(tr("Analysis: Enabled"));
if (value == 3) {
ui->analoptionsFrame->setVisible(true);
ui->advancedAnlysisLine->setVisible(true);
} else {
ui->analoptionsFrame->setVisible(false);
ui->advancedAnlysisLine->setVisible(false);
}
}
}

View File

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

View File

@ -221,8 +221,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>564</width>
<height>867</height>
<width>567</width>
<height>418</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -269,9 +269,12 @@
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>5</number>
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QFrame" name="analoptionsFrame">
@ -300,156 +303,19 @@
<property name="bottomMargin">
<number>5</number>
</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>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="Line" name="advancedAnlysisLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="writeCheckBox">
<property name="text">