Revert "Memory Patch Fixes (#4619)" (#4620)

This reverts commit a52b4c0dae.
This commit is contained in:
kalaposfos13 2026-06-25 15:52:51 +02:00 committed by GitHub
parent a52b4c0dae
commit 221efa40c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 81 deletions

View File

@ -30,34 +30,20 @@ std::string toHex(u64 value, size_t byteSize) {
return ss.str(); return ss.str();
} }
static bool isHexSym(const std::string& s) {
return (s.size() >= 2 && (s[0] == '$' || s[0] == '#'));
}
static bool isHex0x(const std::string& s) {
return (s.size() >= 3 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
}
// possible prefixes == (s == `0x` || s == `#` || s == `$`) will be interpet as hex value, else is
// decimal
static int convertNumBase(const std::string& s) {
return (isHex0x(s) || isHexSym(s)) ? 16 : 10;
}
std::string convertValueToHex(const std::string type, const std::string valueStr) { std::string convertValueToHex(const std::string type, const std::string valueStr) {
std::string result; std::string result;
if (type == "byte") { if (type == "byte") {
const u32 value = std::stoul(valueStr, nullptr, convertNumBase(valueStr)); const u32 value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 1); result = toHex(value, 1);
} else if (type == "bytes16") { } else if (type == "bytes16") {
const u32 value = std::stoul(valueStr, nullptr, convertNumBase(valueStr)); const u32 value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 2); result = toHex(value, 2);
} else if (type == "bytes32") { } else if (type == "bytes32") {
const u32 value = std::stoul(valueStr, nullptr, convertNumBase(valueStr)); const u32 value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 4); result = toHex(value, 4);
} else if (type == "bytes64") { } else if (type == "bytes64") {
const u64 value = std::stoull(valueStr, nullptr, convertNumBase(valueStr)); const u64 value = std::stoull(valueStr, nullptr, 16);
result = toHex(value, 8); result = toHex(value, 8);
} else if (type == "float32") { } else if (type == "float32") {
union { union {
@ -184,18 +170,9 @@ void ApplyPatchesFromXML(std::filesystem::path path) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10); maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
} }
const patchInfo patch = { MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, targetStr,
.gameSerial = "*", sizeStr, false, littleEndian, patchMask,
.modNameStr = currentPatchName, maskOffsetValue);
.offsetStr = address,
.valueStr = patchValue,
.targetStr = targetStr,
.sizeStr = sizeStr,
.littleEndian = littleEndian,
.patchMask = patchMask,
.maskOffset = maskOffsetValue,
};
MemoryPatcher::PatchMemory(patch);
} }
} }
} }
@ -237,9 +214,11 @@ void OnGameLoaded() {
ApplyPendingPatches(); ApplyPendingPatches();
} }
void AddPatchToQueue(const patchInfo& patchToAdd) { void AddPatchToQueue(patchInfo patchToAdd) {
if (patches_applied) { if (patches_applied) {
PatchMemory(patchToAdd); PatchMemory(patchToAdd.modNameStr, patchToAdd.offsetStr, patchToAdd.valueStr,
patchToAdd.targetStr, patchToAdd.sizeStr, patchToAdd.isOffset,
patchToAdd.littleEndian, patchToAdd.patchMask, patchToAdd.maskOffset);
return; return;
} }
pending_patches.push_back(patchToAdd); pending_patches.push_back(patchToAdd);
@ -253,32 +232,35 @@ void ApplyPendingPatches() {
if (currentPatch.gameSerial != "*" && currentPatch.gameSerial != g_game_serial) if (currentPatch.gameSerial != "*" && currentPatch.gameSerial != g_game_serial)
continue; continue;
PatchMemory(currentPatch); PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr,
currentPatch.targetStr, currentPatch.sizeStr, currentPatch.isOffset,
currentPatch.littleEndian, currentPatch.patchMask, currentPatch.maskOffset);
} }
pending_patches.clear(); pending_patches.clear();
} }
void PatchMemory(const patchInfo& patch) { void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr,
std::string targetStr, std::string sizeStr, bool isOffset, bool littleEndian,
PatchMask patchMask, int maskOffset) {
// Send a request to modify the process memory. // Send a request to modify the process memory.
void* cheatAddress = nullptr; void* cheatAddress = nullptr;
if (patch.patchMask == PatchMask::None) { if (patchMask == PatchMask::None) {
if (patch.isOffset) { if (isOffset) {
cheatAddress = cheatAddress = reinterpret_cast<void*>(g_eboot_address + std::stoi(offsetStr, 0, 16));
reinterpret_cast<void*>(g_eboot_address + std::stoi(patch.offsetStr, 0, 16));
} else { } else {
cheatAddress = reinterpret_cast<void*>(g_eboot_address + cheatAddress =
(std::stoi(patch.offsetStr, 0, 16) - 0x400000)); reinterpret_cast<void*>(g_eboot_address + (std::stoi(offsetStr, 0, 16) - 0x400000));
} }
} }
if (patch.patchMask == PatchMask::Mask) { if (patchMask == PatchMask::Mask) {
cheatAddress = reinterpret_cast<void*>(PatternScan(patch.offsetStr) + patch.maskOffset); cheatAddress = reinterpret_cast<void*>(PatternScan(offsetStr) + maskOffset);
} }
if (patch.patchMask == PatchMask::Mask_Jump32) { if (patchMask == PatchMask::Mask_Jump32) {
int jumpSize = std::stoi(patch.sizeStr); int jumpSize = std::stoi(sizeStr);
constexpr int MAX_PATTERN_LENGTH = 256; constexpr int MAX_PATTERN_LENGTH = 256;
if (jumpSize < 5) { if (jumpSize < 5) {
@ -291,35 +273,35 @@ void PatchMemory(const patchInfo& patch) {
} }
// Find the base address using "Address" // Find the base address using "Address"
uintptr_t baseAddress = PatternScan(patch.offsetStr); uintptr_t baseAddress = PatternScan(offsetStr);
if (baseAddress == 0) { if (baseAddress == 0) {
LOG_ERROR(Loader, "PatternScan failed for mask_jump32 with pattern: {}", LOG_ERROR(Loader, "PatternScan failed for mask_jump32 with pattern: {}", offsetStr);
patch.offsetStr);
return; return;
} }
uintptr_t patchAddress = baseAddress + patch.maskOffset; uintptr_t patchAddress = baseAddress + maskOffset;
// Fills the original region (jumpSize bytes) with NOPs // Fills the original region (jumpSize bytes) with NOPs
std::vector<u8> nopBytes(jumpSize, 0x90); std::vector<u8> nopBytes(jumpSize, 0x90);
std::memcpy(reinterpret_cast<void*>(patchAddress), nopBytes.data(), nopBytes.size()); std::memcpy(reinterpret_cast<void*>(patchAddress), nopBytes.data(), nopBytes.size());
// Use "Target" to locate the start of the code cave // Use "Target" to locate the start of the code cave
uintptr_t jump_target = PatternScan(patch.targetStr); uintptr_t jump_target = PatternScan(targetStr);
if (jump_target == 0) { if (jump_target == 0) {
LOG_ERROR(Loader, "PatternScan failed to Target with pattern: {}", patch.targetStr); LOG_ERROR(Loader, "PatternScan failed to Target with pattern: {}", targetStr);
return; return;
} }
// Converts the Value attribute to a byte array (payload) // Converts the Value attribute to a byte array (payload)
std::vector<u8> payload; std::vector<u8> payload;
for (size_t i = 0; i < patch.valueStr.length(); i += 2) { for (size_t i = 0; i < valueStr.length(); i += 2) {
std::string tempStr = patch.valueStr.substr(i, 2);
std::string tempStr = valueStr.substr(i, 2);
const char* byteStr = tempStr.c_str(); const char* byteStr = tempStr.c_str();
char* endPtr; char* endPtr;
unsigned int byteVal = std::strtoul(byteStr, &endPtr, 16); unsigned int byteVal = std::strtoul(byteStr, &endPtr, 16);
if (endPtr != byteStr + 2) { if (endPtr != byteStr + 2) {
LOG_ERROR(Loader, "Invalid byte in Value: {}", patch.valueStr.substr(i, 2)); LOG_ERROR(Loader, "Invalid byte in Value: {}", valueStr.substr(i, 2));
return; return;
} }
payload.push_back(static_cast<u8>(byteVal)); payload.push_back(static_cast<u8>(byteVal));
@ -351,32 +333,32 @@ void PatchMemory(const patchInfo& patch) {
LOG_INFO(Loader, LOG_INFO(Loader,
"Applied Patch mask_jump32: {}, PatchAddress: {:#x}, JumpTarget: {:#x}, " "Applied Patch mask_jump32: {}, PatchAddress: {:#x}, JumpTarget: {:#x}, "
"CodeCaveEnd: {:#x}, JumpSize: {}", "CodeCaveEnd: {:#x}, JumpSize: {}",
patch.modNameStr, patchAddress, jump_target, code_cave_end, jumpSize); modNameStr, patchAddress, jump_target, code_cave_end, jumpSize);
return; return;
} }
if (cheatAddress == nullptr) { if (cheatAddress == nullptr) {
LOG_ERROR(Loader, "Failed to get address for patch {}", patch.modNameStr); LOG_ERROR(Loader, "Failed to get address for patch {}", modNameStr);
return; return;
} }
std::vector<unsigned char> bytePatch; std::vector<unsigned char> bytePatch;
for (size_t i = 0; i < patch.valueStr.length(); i += 2) { for (size_t i = 0; i < valueStr.length(); i += 2) {
unsigned char byte = static_cast<unsigned char>( unsigned char byte =
std::strtol(patch.valueStr.substr(i, 2).c_str(), nullptr, 16)); static_cast<unsigned char>(std::strtol(valueStr.substr(i, 2).c_str(), nullptr, 16));
bytePatch.push_back(byte); bytePatch.push_back(byte);
} }
if (patch.littleEndian) { if (littleEndian) {
std::reverse(bytePatch.begin(), bytePatch.end()); std::reverse(bytePatch.begin(), bytePatch.end());
} }
std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size()); std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size());
LOG_INFO(Loader, "Applied patch: {}, Offset: {:#x}, Value: {}", patch.modNameStr, LOG_INFO(Loader, "Applied patch: {}, Offset: {}, Value: {}", modNameStr,
(uintptr_t)cheatAddress, patch.valueStr); (uintptr_t)cheatAddress, valueStr);
} }
static std::vector<int32_t> PatternToByte(const std::string& pattern) { static std::vector<int32_t> PatternToByte(const std::string& pattern) {

View File

@ -26,12 +26,12 @@ enum PatchMask : uint8_t {
}; };
struct patchInfo { struct patchInfo {
const std::string& gameSerial; std::string gameSerial;
const std::string& modNameStr; std::string modNameStr;
const std::string& offsetStr; std::string offsetStr;
const std::string& valueStr; std::string valueStr;
const std::string& targetStr; std::string targetStr;
const std::string& sizeStr; std::string sizeStr;
bool isOffset; bool isOffset;
bool littleEndian; bool littleEndian;
PatchMask patchMask; PatchMask patchMask;
@ -41,9 +41,11 @@ struct patchInfo {
std::string convertValueToHex(const std::string type, const std::string valueStr); std::string convertValueToHex(const std::string type, const std::string valueStr);
void OnGameLoaded(); void OnGameLoaded();
void AddPatchToQueue(const patchInfo& patchToAdd); void AddPatchToQueue(patchInfo patchToAdd);
void PatchMemory(const patchInfo& patch); void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr,
std::string targetStr, std::string sizeStr, bool isOffset, bool littleEndian,
PatchMask patchMask = PatchMask::None, int maskOffset = 0);
static std::vector<int32_t> PatternToByte(const std::string& pattern); static std::vector<int32_t> PatternToByte(const std::string& pattern);
uintptr_t PatternScan(const std::string& signature); uintptr_t PatternScan(const std::string& signature);

View File

@ -124,18 +124,17 @@ void IPC::InputLoop() {
} else if (cmd == "START") { } else if (cmd == "START") {
start_semaphore.release(); start_semaphore.release();
} else if (cmd == "PATCH_MEMORY") { } else if (cmd == "PATCH_MEMORY") {
const MemoryPatcher::patchInfo entry = { MemoryPatcher::patchInfo entry;
.gameSerial = "*", entry.gameSerial = "*";
.modNameStr = next_str(), entry.modNameStr = next_str();
.offsetStr = next_str(), entry.offsetStr = next_str();
.valueStr = next_str(), entry.valueStr = next_str();
.targetStr = next_str(), entry.targetStr = next_str();
.sizeStr = next_str(), entry.sizeStr = next_str();
.isOffset = next_u64() != 0, entry.isOffset = next_u64() != 0;
.littleEndian = next_u64() != 0, entry.littleEndian = next_u64() != 0;
.patchMask = static_cast<MemoryPatcher::PatchMask>(next_u64()), entry.patchMask = static_cast<MemoryPatcher::PatchMask>(next_u64());
.maskOffset = static_cast<int>(next_u64()), entry.maskOffset = static_cast<int>(next_u64());
};
MemoryPatcher::AddPatchToQueue(entry); MemoryPatcher::AddPatchToQueue(entry);
} else if (cmd == "PAUSE") { } else if (cmd == "PAUSE") {
DebugState.PauseGuestThreads(); DebugState.PauseGuestThreads();