From 78c6e651c825f6625037708299ec9a9aa48fbec4 Mon Sep 17 00:00:00 2001 From: Properrr Date: Wed, 18 Dec 2019 06:26:51 -0800 Subject: [PATCH] Define string of length N in address (#1915) * Implemented "setString" submenu for the Disasm widget --- src/Cutter.pro | 3 + src/core/Cutter.cpp | 51 +++++++++- src/core/Cutter.h | 23 ++++- src/dialogs/EditStringDialog.cpp | 68 +++++++++++++ src/dialogs/EditStringDialog.h | 58 +++++++++++ src/dialogs/EditStringDialog.ui | 143 +++++++++++++++++++++++++++ src/menus/DisassemblyContextMenu.cpp | 60 ++++++++++- src/menus/DisassemblyContextMenu.h | 8 +- 8 files changed, 407 insertions(+), 7 deletions(-) create mode 100644 src/dialogs/EditStringDialog.cpp create mode 100644 src/dialogs/EditStringDialog.h create mode 100644 src/dialogs/EditStringDialog.ui diff --git a/src/Cutter.pro b/src/Cutter.pro index 4e892f03..45c01153 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -258,6 +258,7 @@ QMAKE_SUBSTITUTES += CutterConfig.h.in SOURCES += \ Main.cpp \ core/Cutter.cpp \ + dialogs/EditStringDialog.cpp \ widgets/DisassemblerGraphView.cpp \ widgets/OverviewView.cpp \ common/RichTextPainter.cpp \ @@ -393,6 +394,7 @@ HEADERS += \ core/Cutter.h \ core/CutterCommon.h \ core/CutterDescriptions.h \ + dialogs/EditStringDialog.h \ widgets/DisassemblerGraphView.h \ widgets/OverviewView.h \ common/RichTextPainter.h \ @@ -532,6 +534,7 @@ GRAPHVIZ_HEADERS = widgets/GraphGridLayout.h FORMS += \ dialogs/AboutDialog.ui \ + dialogs/EditStringDialog.ui \ dialogs/preferences/AsmOptionsWidget.ui \ dialogs/CommentsDialog.ui \ dialogs/EditInstructionDialog.ui \ diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index a9945d88..f9e8079b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -643,12 +643,59 @@ void CutterCore::setToCode(RVA addr) emit instructionChanged(addr); } -void CutterCore::setAsString(RVA addr) +void CutterCore::setAsString(RVA addr, int size, StringTypeFormats type) { - cmd("Cs @ " + RAddressString(addr)); + if(RVA_INVALID == addr) + { + return; + } + + QString command; + + switch(type) + { + case StringTypeFormats::None: + { + command = "Cs "; + break; + } + case StringTypeFormats::ASCII_LATIN1: + { + command = "Csa "; + break; + } + case StringTypeFormats::UTF8: + { + command = "Cs8 "; + break; + } + default: + return; + } + + seekAndShow(addr); + QString arg; + if(size > 0) { + arg = QString::asprintf("%d @ %lld", size, addr); + } else { + arg = QString::asprintf("@ %lld", addr); + } + + cmd(command + arg); emit instructionChanged(addr); } +void CutterCore::removeString(RVA addr) +{ + cmd("Cs- @ " + RAddressString(addr)); + emit instructionChanged(addr); +} + +QString CutterCore::getString(RVA addr) +{ + return cmd("ps @ " + RAddressString(addr)); +} + void CutterCore::setToData(RVA addr, int size, int repeat) { if (size <= 0 || repeat <= 0) { diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 5e43ae14..38763cb3 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -145,7 +145,28 @@ public: /* Code/Data */ void setToCode(RVA addr); - void setAsString(RVA addr); + enum class StringTypeFormats { None, ASCII_LATIN1, UTF8 }; + /** + * @brief Adds string at address + * That function calls the 'Cs' command + * \param addr The address of the array where the string will be applied + * \param size The size of string + * \param type The type of string + */ + void setAsString(RVA addr, int size = 0, StringTypeFormats type = StringTypeFormats::None); + /** + * @brief Removes string at address + * That function calls the 'Cs-' command + * \param addr The address of the array where the string will be applied + */ + void removeString(RVA addr); + /** + * @brief Gets string at address + * That function calls the 'ps' command + * \param addr The address of the first byte of the array + * @return string at requested address + */ + QString getString(RVA addr); void setToData(RVA addr, int size, int repeat = 1); int sizeofDataMeta(RVA addr); diff --git a/src/dialogs/EditStringDialog.cpp b/src/dialogs/EditStringDialog.cpp new file mode 100644 index 00000000..5f6f2e74 --- /dev/null +++ b/src/dialogs/EditStringDialog.cpp @@ -0,0 +1,68 @@ +#include "EditStringDialog.h" +#include "ui_EditStringDialog.h" + +EditStringDialog::EditStringDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::EditStringDialog) +{ + ui->setupUi(this); + ui->spinBox_size->setMinimum(0); + ui->lineEdit_address->setMinimumWidth(150); + ui->pushButton_ok->setFocus(); + ui->comboBox_type->addItems({"Auto", "ASCII/Latin1", "UTF-8"}); + connect(ui->checkBox_autoSize, &QCheckBox::toggled, ui->spinBox_size, &QSpinBox::setDisabled); +} + +EditStringDialog::~EditStringDialog() +{ + delete ui; +} + +void EditStringDialog::setStringStartAddress(uint64_t address) +{ + ui->lineEdit_address->setText(QString::number(address, 16)); +} + +bool EditStringDialog::getStringStartAddress(uint64_t& returnValue) const +{ + bool status = false; + returnValue = ui->lineEdit_address->text().toLongLong(&status, 16); + return status; +} + +void EditStringDialog::setStringSizeValue(uint32_t size) +{ + ui->spinBox_size->setValue(size); +} + +int EditStringDialog::getStringSizeValue() const +{ + if( ui->checkBox_autoSize->isChecked() ) { + return -1; + } + + return ui->spinBox_size->value(); +} + +EditStringDialog::StringType EditStringDialog::getStringType() const +{ + const int indexVal = ui->comboBox_type->currentIndex(); + + switch(indexVal) + { + case 0: + { + return EditStringDialog::StringType::Auto; + } + case 1: + { + return EditStringDialog::StringType::ASCII_LATIN1; + } + case 2: + { + return EditStringDialog::StringType::UTF8; + } + default: + return EditStringDialog::StringType::Auto; + } +} diff --git a/src/dialogs/EditStringDialog.h b/src/dialogs/EditStringDialog.h new file mode 100644 index 00000000..78a48652 --- /dev/null +++ b/src/dialogs/EditStringDialog.h @@ -0,0 +1,58 @@ +#ifndef EDITSTRINGDIALOG_H +#define EDITSTRINGDIALOG_H + +#include + +namespace Ui { +class EditStringDialog; +} + +class EditStringDialog : public QDialog +{ + Q_OBJECT + +public: + enum class StringType {Auto, ASCII_LATIN1, UTF8}; + explicit EditStringDialog(QWidget *parent = nullptr); + ~EditStringDialog(); + + /** + * @brief Sets the address of the first byte of potential string in the dialog + * + * @param address The address of the bytearray where string is located + */ + void setStringStartAddress(uint64_t address); + /** + * @brief Returns the address of the first byte of potential string in the dialog + * + * @param[out] returnValue The address of the bytearray where string is located + * @return whether the call successful or not + */ + bool getStringStartAddress(uint64_t &returnValue) const; + + + /** + * @brief Sets the size of string in the dialog + * + * @param size The size of string in the dialog + */ + void setStringSizeValue(uint32_t size); + /** + * @brief Returns the size of string in the dialog + * + * @return -1 on error otherwise the size of string from the dialog + */ + int getStringSizeValue() const; + + /** + * @brief Returns the type of string from the dialog + * + * @return The type of string from the dialog + */ + StringType getStringType() const; + +private: + Ui::EditStringDialog *ui; +}; + +#endif // EDITSTRINGDIALOG_H diff --git a/src/dialogs/EditStringDialog.ui b/src/dialogs/EditStringDialog.ui new file mode 100644 index 00000000..c6fa8623 --- /dev/null +++ b/src/dialogs/EditStringDialog.ui @@ -0,0 +1,143 @@ + + + EditStringDialog + + + Qt::WindowModal + + + + 0 + 0 + 243 + 109 + + + + + 0 + 0 + + + + Edit string + + + + + + + + + + Address: + + + + + + + + 0 + 0 + + + + Size: + + + + + + + Type: + + + + + + + + + + + + + + + + + + + 150 + 0 + + + + + + + + + + + + + Auto + + + + + + + + + Cancel + + + + + + + OK + + + + + + + + + pushButton_cancel + clicked() + EditStringDialog + reject() + + + 51 + 94 + + + 174 + 67 + + + + + pushButton_ok + clicked() + EditStringDialog + accept() + + + 143 + 92 + + + 153 + 71 + + + + + diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 3b24f25b..f34a6dea 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -9,6 +9,7 @@ #include "dialogs/SetToDataDialog.h" #include "dialogs/EditFunctionDialog.h" #include "dialogs/LinkTypeDialog.h" +#include "dialogs/EditStringDialog.h" #include "MainWindow.h" #include @@ -57,7 +58,9 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main actionAddBreakpoint(this), actionSetPC(this), actionSetToCode(this), - actionSetAsString(this), + actionSetAsStringAuto(this), + actionSetAsStringRemove(this), + actionSetAsStringAdvanced(this), actionSetToDataEx(this), actionSetToDataByte(this), actionSetToDataWord(this), @@ -219,9 +222,19 @@ void DisassemblyContextMenu::addSetAsMenu() SLOT(on_actionSetToCode_triggered()), getSetToCodeSequence()); setAsMenu->addAction(&actionSetToCode); - initAction(&actionSetAsString, tr("String"), + setAsString = setAsMenu->addMenu(tr("String...")); + + initAction(&actionSetAsStringAuto, tr("Auto-detect"), SLOT(on_actionSetAsString_triggered()), getSetAsStringSequence()); - setAsMenu->addAction(&actionSetAsString); + initAction(&actionSetAsStringRemove, tr("Remove"), + SLOT(on_actionSetAsStringRemove_triggered())); + initAction(&actionSetAsStringAdvanced, tr("Adanced"), + SLOT(on_actionSetAsStringAdvanced_triggered())); + + + setAsString->addAction(&actionSetAsStringAuto); + setAsString->addAction(&actionSetAsStringRemove); + setAsString->addAction(&actionSetAsStringAdvanced); addSetToDataMenu(); } @@ -862,6 +875,47 @@ void DisassemblyContextMenu::on_actionSetAsString_triggered() Core()->setAsString(offset); } +void DisassemblyContextMenu::on_actionSetAsStringRemove_triggered() +{ + Core()->removeString(offset); +} + +void DisassemblyContextMenu::on_actionSetAsStringAdvanced_triggered() +{ + EditStringDialog dialog(parentWidget()); + const int predictedStrSize = Core()->getString(offset).size(); + dialog.setStringSizeValue(predictedStrSize); + dialog.setStringStartAddress(offset); + + if(!dialog.exec()) + { + return; + } + + uint64_t strAddr = 0U; + if( !dialog.getStringStartAddress(strAddr) ) { + QMessageBox::critical(this->window(), tr("Wrong address"), tr("Can't edit string at this address")); + return; + } + CutterCore::StringTypeFormats coreStringType = CutterCore::StringTypeFormats::None; + + const auto strSize = dialog.getStringSizeValue(); + const auto strType = dialog.getStringType(); + switch(strType) + { + case EditStringDialog::StringType::Auto: + coreStringType = CutterCore::StringTypeFormats::None; + break; + case EditStringDialog::StringType::ASCII_LATIN1: + coreStringType = CutterCore::StringTypeFormats::ASCII_LATIN1; + break; + case EditStringDialog::StringType::UTF8: + coreStringType = CutterCore::StringTypeFormats::UTF8; + break; + }; + + Core()->setAsString(strAddr, strSize, coreStringType); +} void DisassemblyContextMenu::on_actionSetToData_triggered() { diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 9c2da1fa..e03d96c8 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -58,6 +58,8 @@ private slots: void on_actionSetToCode_triggered(); void on_actionSetAsString_triggered(); + void on_actionSetAsStringRemove_triggered(); + void on_actionSetAsStringAdvanced_triggered(); void on_actionSetToData_triggered(); void on_actionSetToDataEx_triggered(); @@ -158,10 +160,14 @@ private: QAction actionSetPC; QAction actionSetToCode; - QAction actionSetAsString; + + QAction actionSetAsStringAuto; + QAction actionSetAsStringRemove; + QAction actionSetAsStringAdvanced; QMenu *setToDataMenu; QMenu *setAsMenu; + QMenu *setAsString; QAction actionSetToDataEx; QAction actionSetToDataByte; QAction actionSetToDataWord;