mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 12:04:45 +00:00
Implement pattern scanning for mask type patches
This commit is contained in:
parent
7564f195c3
commit
5377ae9c37
4 changed files with 113 additions and 15 deletions
|
@ -9,6 +9,7 @@
|
|||
namespace MemoryPatcher {
|
||||
|
||||
uintptr_t g_eboot_address;
|
||||
u64 g_eboot_image_size;
|
||||
|
||||
std::vector<patchInfo> pending_patches;
|
||||
|
||||
|
@ -18,25 +19,42 @@ void AddPatchToQueue(patchInfo patchToAdd) {
|
|||
|
||||
void ApplyPendingPatches() {
|
||||
|
||||
//TODO: need to verify that the patch is actually for the game we open,
|
||||
//if we enable patches but open a different game they will still attempt to load
|
||||
|
||||
for (size_t i = 0; i < pending_patches.size(); ++i) {
|
||||
patchInfo currentPatch = pending_patches[i];
|
||||
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 +76,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,6 +9,13 @@
|
|||
namespace MemoryPatcher {
|
||||
|
||||
extern uintptr_t g_eboot_address;
|
||||
extern u64 g_eboot_image_size;
|
||||
|
||||
enum PatchMask : uint8_t {
|
||||
None,
|
||||
Mask,
|
||||
Mask_Jump32,
|
||||
};
|
||||
|
||||
struct patchInfo {
|
||||
std::string modNameStr;
|
||||
|
@ -16,6 +23,8 @@ struct patchInfo {
|
|||
std::string valueStr;
|
||||
bool isOffset;
|
||||
bool littleEndian;
|
||||
PatchMask patchMask;
|
||||
int maskOffset;
|
||||
};
|
||||
|
||||
extern std::vector<patchInfo> pending_patches;
|
||||
|
@ -24,6 +33,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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -748,9 +748,14 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
QXmlStreamAttributes attributes = xmlReader.attributes();
|
||||
QString appVer = attributes.value("AppVer").toString();
|
||||
if (appVer == m_gameVersion) {
|
||||
patchName = attributes.value("Name").toString();
|
||||
patchAuthor = attributes.value("Author").toString();
|
||||
patchNote = attributes.value("Note").toString();
|
||||
patchName = attributes.value("Name").toString();
|
||||
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;
|
||||
|
@ -873,19 +878,34 @@ 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.modNameStr = patchName.toStdString();
|
||||
|
@ -893,13 +913,15 @@ void CheatsPatches::applyPatch(const QString& patchName, bool enabled) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue