mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 12:04:45 +00:00
Merge pull request #6 from CrazyBloo/Cheats_Patches
pattern scanning for 'mask' type patches + prevent patches from applying to the wrong game
This commit is contained in:
commit
c78752ef88
6 changed files with 123 additions and 15 deletions
|
@ -9,6 +9,8 @@
|
|||
namespace MemoryPatcher {
|
||||
|
||||
uintptr_t g_eboot_address;
|
||||
u64 g_eboot_image_size;
|
||||
std::string g_game_serial;
|
||||
|
||||
std::vector<patchInfo> pending_patches;
|
||||
|
||||
|
@ -20,23 +22,41 @@ void ApplyPendingPatches() {
|
|||
|
||||
for (size_t i = 0; i < pending_patches.size(); ++i) {
|
||||
patchInfo currentPatch = pending_patches[i];
|
||||
|
||||
if (currentPatch.gameSerial != g_game_serial)
|
||||
continue;
|
||||
|
||||
PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr,
|
||||
currentPatch.isOffset, currentPatch.littleEndian);
|
||||
currentPatch.isOffset, currentPatch.littleEndian, currentPatch.patchMask,
|
||||
currentPatch.maskOffset);
|
||||
}
|
||||
|
||||
pending_patches.clear();
|
||||
}
|
||||
|
||||
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset,
|
||||
bool littleEndian) {
|
||||
bool littleEndian, PatchMask patchMask, int maskOffset) {
|
||||
// Send a request to modify the process memory.
|
||||
void* cheatAddress = nullptr;
|
||||
|
||||
if (isOffset) {
|
||||
cheatAddress = reinterpret_cast<void*>(g_eboot_address + std::stoi(offsetStr, 0, 16));
|
||||
} else {
|
||||
cheatAddress =
|
||||
reinterpret_cast<void*>(g_eboot_address + (std::stoi(offsetStr, 0, 16) - 0x400000));
|
||||
if (patchMask == PatchMask::None) {
|
||||
if (isOffset) {
|
||||
cheatAddress = reinterpret_cast<void*>(g_eboot_address + std::stoi(offsetStr, 0, 16));
|
||||
} else {
|
||||
cheatAddress =
|
||||
reinterpret_cast<void*>(g_eboot_address + (std::stoi(offsetStr, 0, 16) - 0x400000));
|
||||
}
|
||||
}
|
||||
|
||||
if (patchMask == PatchMask::Mask) {
|
||||
cheatAddress = reinterpret_cast<void*>(PatternScan(offsetStr) + maskOffset);
|
||||
}
|
||||
|
||||
// TODO: implement mask_jump32
|
||||
|
||||
if (cheatAddress == nullptr) {
|
||||
LOG_ERROR(Loader, "Failed to get address for patch {}", modNameStr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> bytePatch;
|
||||
|
@ -58,4 +78,49 @@ void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valu
|
|||
valueStr);
|
||||
}
|
||||
|
||||
static std::vector<int32_t> PatternToByte(const std::string& pattern) {
|
||||
std::vector<int32_t> bytes;
|
||||
const char* start = pattern.data();
|
||||
const char* end = start + pattern.size();
|
||||
|
||||
for (const char* current = start; current < end; ++current) {
|
||||
if (*current == '?') {
|
||||
++current;
|
||||
if (*current == '?')
|
||||
++current;
|
||||
bytes.push_back(-1);
|
||||
} else {
|
||||
bytes.push_back(strtoul(current, const_cast<char**>(¤t), 16));
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uintptr_t PatternScan(const std::string& signature) {
|
||||
std::vector<int32_t> patternBytes = PatternToByte(signature);
|
||||
const auto scanBytes = static_cast<uint8_t*>((void*)g_eboot_address);
|
||||
|
||||
const int32_t* sigPtr = patternBytes.data();
|
||||
const size_t sigSize = patternBytes.size();
|
||||
|
||||
uint32_t foundResults = 0;
|
||||
for (uint32_t i = 0; i < g_eboot_image_size - sigSize; ++i) {
|
||||
bool found = true;
|
||||
for (uint32_t j = 0; j < sigSize; ++j) {
|
||||
if (scanBytes[i + j] != sigPtr[j] && sigPtr[j] != -1) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
foundResults++;
|
||||
return reinterpret_cast<uintptr_t>(&scanBytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace MemoryPatcher
|
|
@ -9,13 +9,24 @@
|
|||
namespace MemoryPatcher {
|
||||
|
||||
extern uintptr_t g_eboot_address;
|
||||
extern u64 g_eboot_image_size;
|
||||
extern std::string g_game_serial;
|
||||
|
||||
enum PatchMask : uint8_t {
|
||||
None,
|
||||
Mask,
|
||||
Mask_Jump32,
|
||||
};
|
||||
|
||||
struct patchInfo {
|
||||
std::string gameSerial;
|
||||
std::string modNameStr;
|
||||
std::string offsetStr;
|
||||
std::string valueStr;
|
||||
bool isOffset;
|
||||
bool littleEndian;
|
||||
PatchMask patchMask;
|
||||
int maskOffset;
|
||||
};
|
||||
|
||||
extern std::vector<patchInfo> pending_patches;
|
||||
|
@ -24,6 +35,9 @@ void AddPatchToQueue(patchInfo patchToAdd);
|
|||
void ApplyPendingPatches();
|
||||
|
||||
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset,
|
||||
bool littleEndian);
|
||||
bool littleEndian, PatchMask patchMask = PatchMask::None, int maskOffset = 0);
|
||||
|
||||
static std::vector<int32_t> PatternToByte(const std::string& pattern);
|
||||
uintptr_t PatternScan(const std::string& signature);
|
||||
|
||||
} // namespace MemoryPatcher
|
|
@ -197,6 +197,7 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
|
|||
if (MemoryPatcher::g_eboot_address == 0) {
|
||||
if (name == "eboot") {
|
||||
MemoryPatcher::g_eboot_address = base_virtual_addr;
|
||||
MemoryPatcher::g_eboot_image_size = base_size;
|
||||
MemoryPatcher::ApplyPendingPatches();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "common/debug.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/memory_patcher.h"
|
||||
#include "common/ntapi.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
|
@ -93,6 +94,7 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||
param_sfo->open(sce_sys_folder.string() + "/param.sfo", {});
|
||||
id = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9);
|
||||
MemoryPatcher::g_game_serial = id;
|
||||
title = param_sfo->GetString("TITLE");
|
||||
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
||||
u32 fw_version = param_sfo->GetInteger("SYSTEM_VER");
|
||||
|
|
|
@ -752,6 +752,11 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
patchAuthor = attributes.value("Author").toString();
|
||||
patchNote = attributes.value("Note").toString();
|
||||
}
|
||||
if (appVer == "mask") {
|
||||
patchName = attributes.value("Name").toString();
|
||||
patchAuthor = attributes.value("Author").toString();
|
||||
patchNote = attributes.value("Note").toString();
|
||||
}
|
||||
} else if (xmlReader.name() == QStringLiteral("PatchList")) {
|
||||
QJsonArray linesArray;
|
||||
while (!xmlReader.atEnd() &&
|
||||
|
@ -773,7 +778,7 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
}
|
||||
|
||||
if (!patchName.isEmpty() && !patchLines.isEmpty()) {
|
||||
addPatchToLayout(patchName, patchAuthor, patchNote, patchLines);
|
||||
addPatchToLayout(patchName, patchAuthor, patchNote, patchLines, serial);
|
||||
patchName.clear();
|
||||
patchAuthor.clear();
|
||||
patchNote.clear();
|
||||
|
@ -786,7 +791,8 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
}
|
||||
|
||||
void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
|
||||
const QString& note, const QJsonArray& linesArray) {
|
||||
const QString& note, const QJsonArray& linesArray,
|
||||
const QString& serial) {
|
||||
|
||||
QCheckBox* patchCheckBox = new QCheckBox(name);
|
||||
patchesGroupBoxLayout->addWidget(patchCheckBox);
|
||||
|
@ -795,6 +801,7 @@ void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
|
|||
patchInfo.author = author;
|
||||
patchInfo.note = note;
|
||||
patchInfo.linesArray = linesArray;
|
||||
patchInfo.serial = serial;
|
||||
m_patchInfos[name] = patchInfo;
|
||||
|
||||
// Hook checkbox hover events
|
||||
|
@ -873,33 +880,51 @@ void CheatsPatches::applyPatch(const QString& patchName, bool enabled) {
|
|||
QString type = lineObject["Type"].toString();
|
||||
QString address = lineObject["Address"].toString();
|
||||
QString patchValue = lineObject["Value"].toString();
|
||||
QString maskOffsetStr = lineObject["Offset"].toString();
|
||||
|
||||
patchValue = convertValueToHex(type, patchValue);
|
||||
|
||||
bool littleEndian = false;
|
||||
|
||||
if (type.toStdString() == "bytes16") {
|
||||
if (type == "bytes16") {
|
||||
littleEndian = true;
|
||||
} else if (type.toStdString() == "bytes32") {
|
||||
} else if (type == "bytes32") {
|
||||
littleEndian = true;
|
||||
} else if (type.toStdString() == "bytes64") {
|
||||
} else if (type == "bytes64") {
|
||||
littleEndian = true;
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
|
||||
int maskOffsetValue = 0;
|
||||
|
||||
if (type == "mask") {
|
||||
patchMask = MemoryPatcher::PatchMask::Mask;
|
||||
|
||||
// im not sure if this works, there is no games to test the mask offset on yet
|
||||
if (!maskOffsetStr.toStdString().empty())
|
||||
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
|
||||
}
|
||||
|
||||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
if (MemoryPatcher::g_eboot_address == 0) {
|
||||
MemoryPatcher::patchInfo addingPatch;
|
||||
addingPatch.gameSerial = patchInfo.serial.toStdString();
|
||||
addingPatch.modNameStr = patchName.toStdString();
|
||||
addingPatch.offsetStr = address.toStdString();
|
||||
addingPatch.valueStr = patchValue.toStdString();
|
||||
addingPatch.isOffset = false;
|
||||
addingPatch.littleEndian = littleEndian;
|
||||
addingPatch.patchMask = patchMask;
|
||||
addingPatch.maskOffset = maskOffsetValue;
|
||||
|
||||
MemoryPatcher::AddPatchToQueue(addingPatch);
|
||||
continue;
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMemory(patchName.toStdString(), address.toStdString(),
|
||||
patchValue.toStdString(), false, littleEndian);
|
||||
patchValue.toStdString(), false, littleEndian, patchMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ private:
|
|||
|
||||
void addCheatsToLayout(const QJsonArray& modsArray);
|
||||
void addPatchToLayout(const QString& name, const QString& author, const QString& note,
|
||||
const QJsonArray& linesArray);
|
||||
const QJsonArray& linesArray, const QString& serial);
|
||||
|
||||
void createFilesJson();
|
||||
void uncheckAllCheatCheckBoxes();
|
||||
|
@ -85,6 +85,7 @@ private:
|
|||
QString author;
|
||||
QString note;
|
||||
QJsonArray linesArray;
|
||||
QString serial;
|
||||
};
|
||||
|
||||
// Members
|
||||
|
|
Loading…
Add table
Reference in a new issue