diff --git a/x64_dbg_gui/Project/DebuggerX64.pro b/x64_dbg_gui/Project/DebuggerX64.pro index 1115e764..5d46ea70 100644 --- a/x64_dbg_gui/Project/DebuggerX64.pro +++ b/x64_dbg_gui/Project/DebuggerX64.pro @@ -75,7 +75,8 @@ SOURCES += \ Src/QHexEdit/ArrayCommand.cpp \ Src/QHexEdit/QHexEdit.cpp \ Src/QHexEdit/QHexEditPrivate.cpp \ - Src/QHexEdit/XByteArray.cpp + Src/QHexEdit/XByteArray.cpp \ + Src/Gui/PatchDialog.cpp HEADERS += \ @@ -129,7 +130,8 @@ HEADERS += \ Src/QHexEdit/ArrayCommand.h \ Src/QHexEdit/QHexEdit.h \ Src/QHexEdit/QHexEditPrivate.h \ - Src/QHexEdit/XByteArray.h + Src/QHexEdit/XByteArray.h \ + Src/Gui/PatchDialog.h INCLUDEPATH += \ @@ -158,7 +160,8 @@ FORMS += \ Src/Gui/CommandHelpView.ui \ Src/Gui/AppearanceDialog.ui \ Src/Gui/CloseDialog.ui \ - Src/Gui/HexEditDialog.ui + Src/Gui/HexEditDialog.ui \ + Src/Gui/PatchDialog.ui INCLUDEPATH += $$PWD/Src/Bridge diff --git a/x64_dbg_gui/Project/Src/Gui/HexEditDialog.cpp b/x64_dbg_gui/Project/Src/Gui/HexEditDialog.cpp index 5e0f0f22..621bdfe3 100644 --- a/x64_dbg_gui/Project/Src/Gui/HexEditDialog.cpp +++ b/x64_dbg_gui/Project/Src/Gui/HexEditDialog.cpp @@ -8,7 +8,7 @@ HexEditDialog::HexEditDialog(QWidget *parent) : ui(new Ui::HexEditDialog) { ui->setupUi(this); - setModal(true); + setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint); setFixedSize(this->size()); //fixed size setModal(true); //modal window diff --git a/x64_dbg_gui/Project/Src/Gui/MainWindow.cpp b/x64_dbg_gui/Project/Src/Gui/MainWindow.cpp index 7d7d81bd..76e7ad43 100644 --- a/x64_dbg_gui/Project/Src/Gui/MainWindow.cpp +++ b/x64_dbg_gui/Project/Src/Gui/MainWindow.cpp @@ -102,7 +102,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi mLastLogLabel=new StatusLabel(); ui->statusBar->addPermanentWidget(mLastLogLabel, 1); - + mPatchDialog = new PatchDialog(this); // Setup Signals/Slots connect(mCmdLineEdit, SIGNAL(returnPressed()), this, SLOT(executeCommand())); @@ -136,6 +136,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi connect(ui->actionStrings,SIGNAL(triggered()),this,SLOT(findStrings())); connect(ui->actionCalls,SIGNAL(triggered()),this,SLOT(findModularCalls())); connect(ui->actionAppearance,SIGNAL(triggered()),this,SLOT(openAppearance())); + connect(ui->actionPatches,SIGNAL(triggered()),this,SLOT(patchWindow())); connect(Bridge::getBridge(), SIGNAL(updateWindowTitle(QString)), this, SLOT(updateWindowTitleSlot(QString))); connect(Bridge::getBridge(), SIGNAL(addRecentFile(QString)), this, SLOT(addRecentFile(QString))); @@ -742,3 +743,9 @@ void MainWindow::getStrWindow(const QString title, QString *text) *text=mLineEdit.editText; Bridge::getBridge()->BridgeSetResult(bResult); } + +void MainWindow::patchWindow() +{ + mPatchDialog->show(); + mPatchDialog->setFocus(); +} diff --git a/x64_dbg_gui/Project/Src/Gui/MainWindow.h b/x64_dbg_gui/Project/Src/Gui/MainWindow.h index 04d0cf97..bb9852c8 100644 --- a/x64_dbg_gui/Project/Src/Gui/MainWindow.h +++ b/x64_dbg_gui/Project/Src/Gui/MainWindow.h @@ -21,6 +21,7 @@ #include "Configuration.h" #include "AppearanceDialog.h" #include "CloseDialog.h" +#include "PatchDialog.h" namespace Ui { @@ -78,6 +79,7 @@ public slots: void menuEntrySlot(); void runSelection(); void getStrWindow(const QString title, QString* text); + void patchWindow(); private: Ui::MainWindow *ui; @@ -93,6 +95,7 @@ private: ScriptView* mScriptView; ReferenceView* mReferenceView; ThreadView* mThreadView; + PatchDialog* mPatchDialog; StatusLabel* mStatusLabel; StatusLabel* mLastLogLabel; diff --git a/x64_dbg_gui/Project/Src/Gui/MainWindow.ui b/x64_dbg_gui/Project/Src/Gui/MainWindow.ui index 29210334..4c992988 100644 --- a/x64_dbg_gui/Project/Src/Gui/MainWindow.ui +++ b/x64_dbg_gui/Project/Src/Gui/MainWindow.ui @@ -53,6 +53,7 @@ + @@ -520,6 +521,21 @@ Find Intermodular Calls + + + + :/icons/images/patch.png:/icons/images/patch.png + + + Patches + + + Patches + + + Ctrl+P + + diff --git a/x64_dbg_gui/Project/Src/Gui/PatchDialog.cpp b/x64_dbg_gui/Project/Src/Gui/PatchDialog.cpp new file mode 100644 index 00000000..de18e8de --- /dev/null +++ b/x64_dbg_gui/Project/Src/Gui/PatchDialog.cpp @@ -0,0 +1,211 @@ +#include "PatchDialog.h" +#include "ui_PatchDialog.h" + +PatchDialog::PatchDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::PatchDialog) +{ + ui->setupUi(this); + + setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint); + setFixedSize(this->size()); //fixed size + setModal(false); //non-modal window + + connect(Bridge::getBridge(), SIGNAL(updatePatches()), this, SLOT(updatePatches())); + + mPatches = new PatchMap(); +} + +PatchDialog::~PatchDialog() +{ + delete ui; +} + +bool PatchDialog::isPartOfPreviousGroup(PatchInfoList & patchList, int index) +{ + if(!index) + return true; + uint addr=patchList.at(index).first.addr; + uint prevAddr=patchList.at(index-1).first.addr; + for(int i=1; i<10; i++) //10 bytes in between groups + if(addr-i==prevAddr) + return true; + return false; +} + +void PatchDialog::updatePatches() +{ + mIsAdding=true; + //clear GUI + ui->listModules->clear(); + ui->listPatches->clear(); + delete mPatches; + mPatches = new PatchMap(); + + //get patches from DBG + size_t cbsize; + if(!DbgFunctions()->PatchEnum(0, &cbsize)) + return; + int numPatches = cbsize/sizeof(DBGPATCHINFO); + if(!numPatches) + return; + DBGPATCHINFO* patches = new DBGPATCHINFO[numPatches]; + memset(patches, 0, numPatches*sizeof(DBGPATCHINFO)); + if(!DbgFunctions()->PatchEnum(patches, 0)) + { + delete [] patches; + mIsAdding=false; + return; + } + + //fill the patch list + STATUSINFO defaultStatus; + defaultStatus.group=0; + defaultStatus.checked=false; + for(int i=0; ifind(mod); + if(found != mPatches->end()) //found + (*mPatches)[mod].append(PatchPair(patches[i], defaultStatus)); + else //not found + { + PatchInfoList patchList; + patchList.append(PatchPair(patches[i], defaultStatus)); + mPatches->insert(mod, patchList); + } + } + delete [] patches; + + //sort the patches by address + for(PatchMap::iterator i=mPatches->begin(); i!=mPatches->end(); ++i) + { + qSort(i.value().begin(), i.value().end(), PatchInfoLess); + PatchInfoList & curPatchList = i.value(); + //group the patched bytes + for(int j=0,group=0; jlistModules->addItem(i.key()); + } + mIsAdding=false; +} + +void PatchDialog::on_listModules_itemSelectionChanged() +{ + if(!ui->listModules->selectedItems().size()) + return; + QString mod(ui->listModules->selectedItems().at(0)->text()); + PatchMap::iterator found = mPatches->find(mod); + if(found == mPatches->end()) //not found + return; + mIsAdding=true; + PatchInfoList patchList = found.value(); + ui->listPatches->clear(); + for(int i=0; i%.2X", curPatch.oldbyte, curPatch.newbyte), ui->listPatches); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Unchecked); + } + mIsAdding=false; +} + +void PatchDialog::on_listPatches_itemChanged(QListWidgetItem *item) //checkbox changed +{ + if(mIsAdding || !ui->listModules->selectedItems().size()) + return; + QString mod = ui->listModules->selectedItems().at(0)->text(); + PatchMap::iterator found = mPatches->find(mod); + if(found == mPatches->end()) //not found + return; + bool checked=item->checkState()==Qt::Checked; + PatchInfoList & curPatchList = found.value(); + PatchPair & patch = curPatchList[ui->listPatches->row(item)]; + if(patch.second.checked == checked) //check state did not change + return; + patch.second.checked = checked; + //check state changed + if((QApplication::keyboardModifiers() & Qt::ControlModifier) == Qt::ControlModifier) + return; //control held down -> do not check/uncheck group + mIsAdding=true; + //check/uncheck the complete group + for(int i=0; ilistPatches->item(i)->setCheckState(item->checkState()); + } + mIsAdding=false; +} + +void PatchDialog::on_btnSelectAll_clicked() +{ + if(!ui->listModules->selectedItems().size()) + return; + QString mod = ui->listModules->selectedItems().at(0)->text(); + PatchMap::iterator found = mPatches->find(mod); + if(found == mPatches->end()) //not found + return; + mIsAdding=true; + PatchInfoList & curPatchList = found.value(); + for(int i=0; ilistPatches->item(i)->setCheckState(Qt::Checked); + curPatchList[i].second.checked=true; + } + mIsAdding=false; +} + +void PatchDialog::on_btnDeselectAll_clicked() +{ + if(!ui->listModules->selectedItems().size()) + return; + QString mod = ui->listModules->selectedItems().at(0)->text(); + PatchMap::iterator found = mPatches->find(mod); + if(found == mPatches->end()) //not found + return; + mIsAdding=true; + PatchInfoList & curPatchList = found.value(); + for(int i=0; ilistPatches->item(i)->setCheckState(Qt::Unchecked); + curPatchList[i].second.checked=false; + } + mIsAdding=false; +} + +void PatchDialog::on_btnRestoreSelected_clicked() +{ + if(!ui->listModules->selectedItems().size()) + return; + int selModIdx = ui->listModules->row(ui->listModules->selectedItems().at(0)); + QString mod = ui->listModules->selectedItems().at(0)->text(); + PatchMap::iterator found = mPatches->find(mod); + if(found == mPatches->end()) //not found + return; + mIsAdding=true; + PatchInfoList & curPatchList = found.value(); + int removed=0; + int total=curPatchList.size(); + for(int i=0; iPatchRestore(curPatchList.at(i).first.addr); + removed++; + } + } + mIsAdding=false; + updatePatches(); + if(removed!=total) + ui->listModules->setCurrentRow(selModIdx); + GuiUpdateAllViews(); +} diff --git a/x64_dbg_gui/Project/Src/Gui/PatchDialog.h b/x64_dbg_gui/Project/Src/Gui/PatchDialog.h new file mode 100644 index 00000000..9ea17afd --- /dev/null +++ b/x64_dbg_gui/Project/Src/Gui/PatchDialog.h @@ -0,0 +1,50 @@ +#ifndef PATCHDIALOG_H +#define PATCHDIALOG_H + +#include +#include "Bridge.h" + +namespace Ui { + class PatchDialog; +} + +class PatchDialog : public QDialog +{ + Q_OBJECT + + struct STATUSINFO + { + bool checked; + int group; + }; + + typedef QPair PatchPair; + typedef QList PatchInfoList; + typedef QMap PatchMap; + + static bool PatchInfoLess(const PatchPair & a, const PatchPair & b) + { + return a.first.addr < b.first.addr; + } + +public: + explicit PatchDialog(QWidget *parent = 0); + ~PatchDialog(); + +private: + Ui::PatchDialog *ui; + PatchMap* mPatches; + bool mIsAdding; + + bool isPartOfPreviousGroup(PatchInfoList & patchList, int index); + +private slots: + void updatePatches(); + void on_listModules_itemSelectionChanged(); + void on_listPatches_itemChanged(QListWidgetItem *item); + void on_btnSelectAll_clicked(); + void on_btnDeselectAll_clicked(); + void on_btnRestoreSelected_clicked(); +}; + +#endif // PATCHDIALOG_H diff --git a/x64_dbg_gui/Project/Src/Gui/PatchDialog.ui b/x64_dbg_gui/Project/Src/Gui/PatchDialog.ui new file mode 100644 index 00000000..245ab023 --- /dev/null +++ b/x64_dbg_gui/Project/Src/Gui/PatchDialog.ui @@ -0,0 +1,147 @@ + + + PatchDialog + + + + 0 + 0 + 511 + 452 + + + + Patches + + + + :/icons/images/patch.png:/icons/images/patch.png + + + + + 230 + 10 + 271 + 361 + + + + &Patches + + + + + 10 + 20 + 251 + 331 + + + + + Courier New + + + + + + + + 10 + 10 + 211 + 431 + + + + &Modules + + + + + 10 + 20 + 191 + 401 + + + + + Courier New + + + + + + + + 230 + 380 + 271 + 58 + + + + + + + + + Select All + + + + + + + Deselect All + + + + + + + Restore Selected + + + + + + + + + + + false + + + Pick Groups + + + + + + + false + + + Patch File + + + + + + + + + + listModules + listPatches + btnPatchFile + + + + + + diff --git a/x64_dbg_gui/Project/images/patch.png b/x64_dbg_gui/Project/images/patch.png new file mode 100644 index 00000000..fe8c7976 Binary files /dev/null and b/x64_dbg_gui/Project/images/patch.png differ diff --git a/x64_dbg_gui/Project/resource.qrc b/x64_dbg_gui/Project/resource.qrc index 506516af..a4da1f2f 100644 --- a/x64_dbg_gui/Project/resource.qrc +++ b/x64_dbg_gui/Project/resource.qrc @@ -33,5 +33,6 @@ images/color-swatches.png images/call.png images/document-binary.png + images/patch.png