Merge pull request #4 from CrazyBloo/Cheats_Patches

Initial Patch Implementation
This commit is contained in:
DanielSvoboda 2024-08-23 08:53:53 -03:00 committed by GitHub
commit 6be2251724
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 128 additions and 33 deletions

View file

@ -292,6 +292,8 @@ set(COMMON src/common/logging/backend.cpp
src/common/enum.h
src/common/io_file.cpp
src/common/io_file.h
src/common/memory_patcher.cpp
src/common/memory_patcher.h
src/common/error.cpp
src/common/error.h
src/common/scope_exit.h

View file

@ -0,0 +1,51 @@
#include "common/logging/log.h"
#include "memory_patcher.h"
namespace MemoryPatcher {
uintptr_t g_eboot_address;
std::vector<patchInfo> pending_patches;
void AddPatchToQueue(patchInfo patchToAdd) {
pending_patches.push_back(patchToAdd);
}
void ApplyPendingPatches() {
for (size_t i = 0; i < pending_patches.size(); ++i) {
patchInfo currentPatch = pending_patches[i];
PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr,
currentPatch.isOffset);
}
pending_patches.clear();
}
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr,
bool isOffset) {
// 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));
}
std::vector<unsigned char> bytePatch;
for (size_t i = 0; i < valueStr.length(); i += 2) {
unsigned char byte =
static_cast<unsigned char>(std::strtol(valueStr.substr(i, 2).c_str(), nullptr, 16));
bytePatch.push_back(byte);
}
std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size());
LOG_INFO(Loader, "Applied patch:{}, Offset:{}, Value:{}", modNameStr, (uintptr_t)cheatAddress,
valueStr);
}
} // namespace MemoryPatcher

View file

@ -0,0 +1,25 @@
#pragma once
#include <cstring>
#include <string>
#include <vector>
namespace MemoryPatcher {
extern uintptr_t g_eboot_address;
struct patchInfo {
std::string modNameStr;
std::string offsetStr;
std::string valueStr;
bool isOffset;
};
extern std::vector<patchInfo> pending_patches;
void AddPatchToQueue(patchInfo patchToAdd);
void ApplyPendingPatches();
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr,
bool isOffset);
} // namespace MemoryPatcher

View file

@ -5,6 +5,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/memory_patcher.h"
#include "common/string_util.h"
#include "core/aerolib/aerolib.h"
#include "core/cpu_patches.h"
@ -19,8 +20,6 @@ using EntryFunc = PS4_SYSV_ABI int (*)(size_t args, const void* argp, void* para
static u64 LoadOffset = CODE_BASE_OFFSET;
static constexpr u64 CODE_BASE_INCR = 0x010000000u;
uintptr_t g_eboot_address;
static u64 GetAlignedSize(const elf_program_header& phdr) {
return (phdr.p_align != 0 ? (phdr.p_memsz + (phdr.p_align - 1)) & ~(phdr.p_align - 1)
: phdr.p_memsz);
@ -92,12 +91,6 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
LoadOffset += CODE_BASE_INCR * (1 + aligned_base_size / CODE_BASE_INCR);
LOG_INFO(Core_Linker, "Loading module {} to {}", name, fmt::ptr(*out_addr));
if (g_eboot_address == 0) {
if (name == "eboot") {
g_eboot_address = base_virtual_addr;
}
}
// Initialize trampoline generator.
void* trampoline_addr = std::bit_cast<void*>(base_virtual_addr + aligned_base_size);
Xbyak::CodeGenerator c(TrampolineSize, trampoline_addr);
@ -200,6 +193,13 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
const VAddr entry_addr = base_virtual_addr + elf.GetElfEntry();
LOG_INFO(Core_Linker, "program entry addr ..........: {:#018x}", entry_addr);
if (MemoryPatcher::g_eboot_address == 0) {
if (name == "eboot") {
MemoryPatcher::g_eboot_address = base_virtual_addr;
MemoryPatcher::ApplyPendingPatches();
}
}
}
void Module::LoadDynamicInfo() {

View file

@ -243,6 +243,4 @@ public:
std::vector<u8> rela_bits;
};
extern uintptr_t g_eboot_address;
} // namespace Core

View file

@ -26,8 +26,10 @@
#include <QXmlStreamReader>
#include <common/logging/log.h>
#include "cheats_patches.h"
#include "common/memory_patcher.h"
#include "common/path_util.h"
#include "core/module.h"
using namespace Common::FS;
CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial,
@ -578,6 +580,8 @@ void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
// Hook checkbox hover events
patchCheckBox->installEventFilter(this);
connect(patchCheckBox, &QCheckBox::toggled, [=](bool checked) { applyPatch(name, checked); });
}
void CheatsPatches::updateNoteTextEdit(const QString& patchName) {
@ -625,16 +629,6 @@ void CheatsPatches::applyCheat(const QString& modName, bool enabled) {
if (!m_cheats.contains(modName))
return;
if (Core::g_eboot_address == 0) {
if (showErrorMessage) {
QMessageBox::warning(this, "Game Not Started",
"Cheat cannot be applied until the game has started.");
showErrorMessage = false;
}
uncheckAllCheatCheckBoxes();
return;
}
Cheat cheat = m_cheats[modName];
for (const MemoryMod& memoryMod : cheat.memoryMods) {
@ -644,21 +638,45 @@ void CheatsPatches::applyCheat(const QString& modName, bool enabled) {
std::string offsetStr = memoryMod.offset.toStdString();
std::string valueStr = value.toStdString();
LOG_INFO(Loader, "Cheat applied:{}, Offset:{}, Value:{}", modNameStr, offsetStr, valueStr);
if (MemoryPatcher::g_eboot_address == 0) {
MemoryPatcher::patchInfo addingPatch;
addingPatch.modNameStr = modNameStr;
addingPatch.offsetStr = offsetStr;
addingPatch.valueStr = valueStr;
addingPatch.isOffset = true;
// Send a request to modify the process memory.
void* cheatAddress =
reinterpret_cast<void*>(Core::g_eboot_address + std::stoi(offsetStr, 0, 16));
std::vector<unsigned char> bytePatch;
for (size_t i = 0; i < valueStr.length(); i += 2) {
unsigned char byte =
static_cast<unsigned char>(std::strtol(valueStr.substr(i, 2).c_str(), nullptr, 16));
bytePatch.push_back(byte);
MemoryPatcher::AddPatchToQueue(addingPatch);
continue;
}
MemoryPatcher::PatchMemory(modNameStr, offsetStr, valueStr, true);
}
}
void CheatsPatches::applyPatch(const QString& patchName, bool enabled) {
if (m_patchInfos.contains(patchName)) {
const PatchInfo& patchInfo = m_patchInfos[patchName];
foreach (const QJsonValue& value, patchInfo.linesArray) {
QJsonObject lineObject = value.toObject();
QString type = lineObject["Type"].toString();
QString address = lineObject["Address"].toString();
QString patchValue = lineObject["Value"].toString();
if (MemoryPatcher::g_eboot_address == 0) {
MemoryPatcher::patchInfo addingPatch;
addingPatch.modNameStr = patchName.toStdString();
addingPatch.offsetStr = address.toStdString();
addingPatch.valueStr = patchValue.toStdString();
addingPatch.isOffset = false;
MemoryPatcher::AddPatchToQueue(addingPatch);
continue;
}
MemoryPatcher::PatchMemory(patchName.toStdString(), address.toStdString(),
patchValue.toStdString(), false);
}
std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size());
}
}

View file

@ -50,6 +50,7 @@ private:
void createFilesJson();
void uncheckAllCheatCheckBoxes();
void applyCheat(const QString& modName, bool enabled);
void applyPatch(const QString& patchName, bool enabled);
// Event Filtering
bool eventFilter(QObject* obj, QEvent* event);