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 @@
+
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