[C++] 纯文本查看 复制代码
#include "PatchDialog.h"#include "ui_PatchDialog.h"
#include <QMessageBox>
#include <QIcon>
#include <QFileDialog>
#include <QTextStream>
#include "MiscUtil.h"
#include "StringUtil.h"
#include "Configuration.h"
#include <QClipboard>
void PatchDialog::on_btnImport_clicked()
{
QStringList filenamelist = QFileDialog::getOpenFileNames(this, tr("Open patch"), "", tr("Patch files (*.1337)"));
int patched = 0;
bool bBadOriginal = false;
bool bAlreadyDone = false;
typedef struct _IMPORTSTATUS
{
bool badoriginal;
bool alreadypatched;
} IMPORTSTATUS;
QList<QPair<DBGPATCHINFO, IMPORTSTATUS>> patchList;
DBGPATCHINFO curPatch;
for(const auto & filename1 : filenamelist)
{
if(!filename1.length())
continue;
QString filename = QDir::toNativeSeparators(filename1); //convert to native path format (with backlashes)
QFile file(filename);
file.open(QFile::ReadOnly | QFile::Text);
QTextStream in(&file);
QString patch = in.readAll();
file.close();
patch = patch.replace("\r\n", "\n");
QStringList lines = patch.split("\n", QString::SkipEmptyParts);
if(!lines.size())
{
SimpleErrorBox(this, tr("Error!"), tr("The patch file is empty..."));
continue;
}
dsint modbase = 0;
for(int i = 0; i < lines.size(); i++)
{
ULONGLONG rva;
unsigned int oldbyte;
unsigned int newbyte;
QString curLine = lines.at(i);
if(curLine.startsWith(">")) //module
{
strcpy_s(curPatch.mod, curLine.toUtf8().constData() + 1);
modbase = DbgFunctions()->ModBaseFromName(curPatch.mod);
continue;
}
if(!modbase)
continue;
curLine = curLine.replace(" ", "");
if(sscanf_s(curLine.toUtf8().constData(), "%llX:%X->%X", &rva, &oldbyte, &newbyte) != 3)
{
//File format is error. Don't continue processing this file
SimpleErrorBox(this, tr("Error!"), tr("Patch file format is incorrect..."));
break;
}
oldbyte &= 0xFF;
newbyte &= 0xFF;
curPatch.addr = rva + modbase;
if(!DbgMemIsValidReadPtr(curPatch.addr))
continue;
unsigned char checkbyte = 0;
DbgMemRead(curPatch.addr, &checkbyte, sizeof(checkbyte));
IMPORTSTATUS status;
status.alreadypatched = (checkbyte == newbyte);
status.badoriginal = (checkbyte != oldbyte);
if(status.alreadypatched)
bAlreadyDone = true;
else if(status.badoriginal)
bBadOriginal = true;
curPatch.oldbyte = oldbyte;
curPatch.newbyte = newbyte;
patchList.push_back(QPair<DBGPATCHINFO, IMPORTSTATUS>(curPatch, status));
}
}
//Check if any patch exists
if(!patchList.size())
{
SimpleInfoBox(this, tr("Information"), tr("No patches to apply in the current process."));
return;
}
//Warn if some are already patched
bool bUndoPatched = false;
if(bAlreadyDone)
{
QMessageBox msg(QMessageBox::Question, tr("Question"), tr("Some patches are already applied.\n\nDo you want to remove these patches?"), QMessageBox::Yes | QMessageBox::No);
msg.setWindowIcon(DIcon("question.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
if(msg.exec() == QMessageBox::Yes)
bUndoPatched = true;
}
bool bPatchBadOriginals = false;
if(bBadOriginal)
{
QMessageBox msg(QMessageBox::Question, tr("Question"), tr("Some bytes do not match the original in the patch file.\n\nDo you want to apply these patches anyway?"), QMessageBox::Yes | QMessageBox::No);
msg.setWindowIcon(DIcon("question.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
if(msg.exec() == QMessageBox::Yes)
bPatchBadOriginals = true;
}
//Apply all of the patches
for(int i = 0; i < patchList.size(); i++)
{
if(!bPatchBadOriginals && patchList.at(i).second.badoriginal)
continue;
curPatch = patchList.at(i).first;
if(bUndoPatched && patchList.at(i).second.alreadypatched)
{
if(DbgFunctions()->MemPatch(curPatch.addr, &curPatch.oldbyte, 1))
patched++;
}
else
{
if(DbgFunctions()->MemPatch(curPatch.addr, &curPatch.newbyte, 1))
patched++;
}
}
updatePatches();
GuiUpdateAllViews();
SimpleInfoBox(this, tr("Information"), tr("%1/%2 patch(es) applied!").arg(patched).arg(patchList.size()));
}
void PatchDialog::on_btnExport_clicked()
{
if(!mPatches.size())
return;
if(containsRelocatedBytes() && !showRelocatedBytesWarning())
return;
QString filename = QFileDialog::getSaveFileName(this, tr("Save patch"), "", tr("Patch files (*.1337)"));
if(!filename.length())
return;
filename = QDir::toNativeSeparators(filename); //convert to native path format (with backlashes)
if(filename.endsWith(QString(".1337")))
saveAs1337(filename);
// TODO: C program source
}
void PatchDialog::saveAs1337(const QString & filename)
{
QStringList lines;
int patches = 0;
for(PatchMap::iterator i = mPatches.begin(); i != mPatches.end(); ++i)
{
const PatchInfoList & curPatchList = i.value();
bool bModPlaced = false;
dsint modbase = DbgFunctions()->ModBaseFromName(i.key().toUtf8().constData());
if(!modbase)
continue;
for(int j = 0; j < curPatchList.size(); j++)
{
if(!curPatchList.at(j).status.checked) //skip unchecked patches
continue;
if(!bModPlaced)
{
lines.push_back(">" + i.key());
bModPlaced = true;
}
QString addrText = ToPtrString(curPatchList.at(j).patch.addr - modbase);
lines.push_back(addrText + QString().sprintf(":%.2X->%.2X", curPatchList.at(j).patch.oldbyte, curPatchList.at(j).patch.newbyte));
patches++;
}
}
if(!lines.size())
{
SimpleInfoBox(this, tr("Information"), tr("No patches to export."));
return;
}
QFile file(filename);
file.open(QFile::WriteOnly | QFile::Text);
QString text = lines.join("\n");
QByteArray textUtf8 = text.toUtf8();
file.write(textUtf8.constData(), textUtf8.length());
file.close();
SimpleInfoBox(this, tr("Information"), tr("%1 patch(es) exported!").arg(patches));
}