From 06f6082bc18340b01e8592eed3e0e3c87db70726 Mon Sep 17 00:00:00 2001 From: CrazyBloo Date: Thu, 22 Aug 2024 19:54:34 -0400 Subject: [PATCH 1/5] MemoryPatcher namespace, activate cheats on start --- CMakeLists.txt | 2 ++ src/common/memory_patcher.cpp | 44 +++++++++++++++++++++++++++++++++++ src/common/memory_patcher.h | 24 +++++++++++++++++++ src/core/module.cpp | 18 +++++++------- src/core/module.h | 2 -- src/qt_gui/cheats_patches.cpp | 34 +++++++++------------------ 6 files changed, 91 insertions(+), 33 deletions(-) create mode 100644 src/common/memory_patcher.cpp create mode 100644 src/common/memory_patcher.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b2b2ceaad..6495cb665 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -299,6 +299,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 diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp new file mode 100644 index 000000000..fb6ef7542 --- /dev/null +++ b/src/common/memory_patcher.cpp @@ -0,0 +1,44 @@ +#include "memory_patcher.h" +#include "common/logging/log.h" + +namespace MemoryPatcher +{ + +uintptr_t g_eboot_address; + +std::vector 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]; + LOG_INFO(Loader, "loading patch {}", i); + PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr); + } + + pending_patches.clear(); +} + +void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr) { + // Send a request to modify the process memory. + void* cheatAddress = + reinterpret_cast(g_eboot_address + std::stoi(offsetStr, 0, 16)); + + std::vector bytePatch; + + for (size_t i = 0; i < valueStr.length(); i += 2) { + unsigned char byte = + static_cast(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); +} + +} \ No newline at end of file diff --git a/src/common/memory_patcher.h b/src/common/memory_patcher.h new file mode 100644 index 000000000..f06e547ec --- /dev/null +++ b/src/common/memory_patcher.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include + +namespace MemoryPatcher +{ + extern uintptr_t g_eboot_address; + + struct patchInfo { + std::string modNameStr; + std::string offsetStr; + std::string valueStr; + }; + + extern std::vector pending_patches; + + void AddPatchToQueue(patchInfo patchToAdd); + void ApplyPendingPatches(); + + void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr); + + +} \ No newline at end of file diff --git a/src/core/module.cpp b/src/core/module.cpp index 369931ff5..338025475 100644 --- a/src/core/module.cpp +++ b/src/core/module.cpp @@ -11,6 +11,7 @@ #include "core/loader/dwarf.h" #include "core/memory.h" #include "core/module.h" +#include "common/memory_patcher.h" namespace Core { @@ -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(base_virtual_addr + aligned_base_size); Xbyak::CodeGenerator c(TrampolineSize, trampoline_addr); @@ -200,6 +193,15 @@ 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() { diff --git a/src/core/module.h b/src/core/module.h index c00488550..007501f08 100644 --- a/src/core/module.h +++ b/src/core/module.h @@ -243,6 +243,4 @@ public: std::vector rela_bits; }; -extern uintptr_t g_eboot_address; - } // namespace Core diff --git a/src/qt_gui/cheats_patches.cpp b/src/qt_gui/cheats_patches.cpp index bc1b0c840..a58a07e72 100644 --- a/src/qt_gui/cheats_patches.cpp +++ b/src/qt_gui/cheats_patches.cpp @@ -28,6 +28,8 @@ #include "cheats_patches.h" #include "common/path_util.h" #include "core/module.h" +#include "common/memory_patcher.h" + using namespace Common::FS; CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial, @@ -625,16 +627,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 +636,17 @@ 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; - // Send a request to modify the process memory. - void* cheatAddress = - reinterpret_cast(Core::g_eboot_address + std::stoi(offsetStr, 0, 16)); - - std::vector bytePatch; - - for (size_t i = 0; i < valueStr.length(); i += 2) { - unsigned char byte = - static_cast(std::strtol(valueStr.substr(i, 2).c_str(), nullptr, 16)); - - bytePatch.push_back(byte); + MemoryPatcher::AddPatchToQueue(addingPatch); + continue; } - std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size()); + + MemoryPatcher::PatchMemory(modNameStr, offsetStr, valueStr); } } From fbe7f6d3882ca30212fdd013ef958391b3504afc Mon Sep 17 00:00:00 2001 From: CrazyBloo Date: Thu, 22 Aug 2024 20:11:53 -0400 Subject: [PATCH 2/5] format --- src/common/memory_patcher.cpp | 13 ++++++------- src/common/memory_patcher.h | 27 +++++++++++++-------------- src/core/module.cpp | 4 +--- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp index fb6ef7542..336bf3ad5 100644 --- a/src/common/memory_patcher.cpp +++ b/src/common/memory_patcher.cpp @@ -1,8 +1,7 @@ -#include "memory_patcher.h" #include "common/logging/log.h" +#include "memory_patcher.h" -namespace MemoryPatcher -{ +namespace MemoryPatcher { uintptr_t g_eboot_address; @@ -25,8 +24,7 @@ void ApplyPendingPatches() { void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr) { // Send a request to modify the process memory. - void* cheatAddress = - reinterpret_cast(g_eboot_address + std::stoi(offsetStr, 0, 16)); + void* cheatAddress = reinterpret_cast(g_eboot_address + std::stoi(offsetStr, 0, 16)); std::vector bytePatch; @@ -38,7 +36,8 @@ void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valu } std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size()); - LOG_INFO(Loader, "Applied patch:{}, Offset:{}, Value:{}", modNameStr, (uintptr_t)cheatAddress, valueStr); + LOG_INFO(Loader, "Applied patch:{}, Offset:{}, Value:{}", modNameStr, (uintptr_t)cheatAddress, + valueStr); } -} \ No newline at end of file +} // namespace MemoryPatcher \ No newline at end of file diff --git a/src/common/memory_patcher.h b/src/common/memory_patcher.h index f06e547ec..43039fdb2 100644 --- a/src/common/memory_patcher.h +++ b/src/common/memory_patcher.h @@ -1,24 +1,23 @@ #pragma once #include -#include #include +#include -namespace MemoryPatcher -{ - extern uintptr_t g_eboot_address; +namespace MemoryPatcher { - struct patchInfo { - std::string modNameStr; - std::string offsetStr; - std::string valueStr; - }; +extern uintptr_t g_eboot_address; - extern std::vector pending_patches; +struct patchInfo { + std::string modNameStr; + std::string offsetStr; + std::string valueStr; +}; - void AddPatchToQueue(patchInfo patchToAdd); - void ApplyPendingPatches(); +extern std::vector pending_patches; - void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr); +void AddPatchToQueue(patchInfo patchToAdd); +void ApplyPendingPatches(); +void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr); -} \ No newline at end of file +} // namespace MemoryPatcher \ No newline at end of file diff --git a/src/core/module.cpp b/src/core/module.cpp index 338025475..2f1212448 100644 --- a/src/core/module.cpp +++ b/src/core/module.cpp @@ -5,13 +5,13 @@ #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" #include "core/loader/dwarf.h" #include "core/memory.h" #include "core/module.h" -#include "common/memory_patcher.h" namespace Core { @@ -197,11 +197,9 @@ void Module::LoadModuleToMemory(u32& max_tls_index) { if (MemoryPatcher::g_eboot_address == 0) { if (name == "eboot") { MemoryPatcher::g_eboot_address = base_virtual_addr; - MemoryPatcher::ApplyPendingPatches(); } } - } void Module::LoadDynamicInfo() { From 90f1d2c08f7e8bf06214d76a042c223d319463bf Mon Sep 17 00:00:00 2001 From: CrazyBloo Date: Fri, 23 Aug 2024 02:37:39 -0400 Subject: [PATCH 3/5] initial patch implementation --- src/common/memory_patcher.cpp | 15 +++++++++++---- src/common/memory_patcher.h | 3 ++- src/qt_gui/cheats_patches.cpp | 32 +++++++++++++++++++++++++++++++- src/qt_gui/cheats_patches.h | 1 + 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp index 336bf3ad5..ca9d5bf6e 100644 --- a/src/common/memory_patcher.cpp +++ b/src/common/memory_patcher.cpp @@ -15,16 +15,23 @@ void ApplyPendingPatches() { for (size_t i = 0; i < pending_patches.size(); ++i) { patchInfo currentPatch = pending_patches[i]; - LOG_INFO(Loader, "loading patch {}", i); - PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr); + PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr, + currentPatch.isOffset); } pending_patches.clear(); } -void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr) { +void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset) { // Send a request to modify the process memory. - void* cheatAddress = reinterpret_cast(g_eboot_address + std::stoi(offsetStr, 0, 16)); + void* cheatAddress = nullptr; + + if (isOffset) { + cheatAddress = reinterpret_cast(g_eboot_address + std::stoi(offsetStr, 0, 16)); + } else { + cheatAddress = + reinterpret_cast(g_eboot_address + (std::stoi(offsetStr, 0, 16) - 0x400000)); + } std::vector bytePatch; diff --git a/src/common/memory_patcher.h b/src/common/memory_patcher.h index 43039fdb2..80f8e44af 100644 --- a/src/common/memory_patcher.h +++ b/src/common/memory_patcher.h @@ -11,6 +11,7 @@ struct patchInfo { std::string modNameStr; std::string offsetStr; std::string valueStr; + bool isOffset; }; extern std::vector pending_patches; @@ -18,6 +19,6 @@ extern std::vector pending_patches; void AddPatchToQueue(patchInfo patchToAdd); void ApplyPendingPatches(); -void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr); +void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset); } // namespace MemoryPatcher \ No newline at end of file diff --git a/src/qt_gui/cheats_patches.cpp b/src/qt_gui/cheats_patches.cpp index a58a07e72..5205a68cd 100644 --- a/src/qt_gui/cheats_patches.cpp +++ b/src/qt_gui/cheats_patches.cpp @@ -580,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) { @@ -641,12 +643,40 @@ void CheatsPatches::applyCheat(const QString& modName, bool enabled) { addingPatch.modNameStr = modNameStr; addingPatch.offsetStr = offsetStr; addingPatch.valueStr = valueStr; + addingPatch.isOffset = true; MemoryPatcher::AddPatchToQueue(addingPatch); continue; } - MemoryPatcher::PatchMemory(modNameStr, offsetStr, valueStr); + 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); + } } } diff --git a/src/qt_gui/cheats_patches.h b/src/qt_gui/cheats_patches.h index d9cb72278..ad0c0e914 100644 --- a/src/qt_gui/cheats_patches.h +++ b/src/qt_gui/cheats_patches.h @@ -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); From 0c1c3d7a83d62580e5302c7f7bc940e30f502594 Mon Sep 17 00:00:00 2001 From: CrazyBloo Date: Fri, 23 Aug 2024 02:45:52 -0400 Subject: [PATCH 4/5] format --- src/common/memory_patcher.cpp | 9 +++++---- src/common/memory_patcher.h | 3 ++- src/qt_gui/cheats_patches.cpp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp index ca9d5bf6e..2c62a7e6f 100644 --- a/src/common/memory_patcher.cpp +++ b/src/common/memory_patcher.cpp @@ -13,16 +13,17 @@ void AddPatchToQueue(patchInfo patchToAdd) { void ApplyPendingPatches() { - for (size_t i = 0; i < pending_patches.size(); ++i) { +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.isOffset); } pending_patches.clear(); } -void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset) { +void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, + bool isOffset) { // Send a request to modify the process memory. void* cheatAddress = nullptr; @@ -44,7 +45,7 @@ void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valu std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size()); LOG_INFO(Loader, "Applied patch:{}, Offset:{}, Value:{}", modNameStr, (uintptr_t)cheatAddress, - valueStr); + valueStr); } } // namespace MemoryPatcher \ No newline at end of file diff --git a/src/common/memory_patcher.h b/src/common/memory_patcher.h index 80f8e44af..f9f76a324 100644 --- a/src/common/memory_patcher.h +++ b/src/common/memory_patcher.h @@ -19,6 +19,7 @@ extern std::vector pending_patches; void AddPatchToQueue(patchInfo patchToAdd); void ApplyPendingPatches(); -void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset); +void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, + bool isOffset); } // namespace MemoryPatcher \ No newline at end of file diff --git a/src/qt_gui/cheats_patches.cpp b/src/qt_gui/cheats_patches.cpp index 5205a68cd..a826db40a 100644 --- a/src/qt_gui/cheats_patches.cpp +++ b/src/qt_gui/cheats_patches.cpp @@ -26,9 +26,9 @@ #include #include #include "cheats_patches.h" +#include "common/memory_patcher.h" #include "common/path_util.h" #include "core/module.h" -#include "common/memory_patcher.h" using namespace Common::FS; From 055de99d5abf03c1380b747d5b754638e3dfcfac Mon Sep 17 00:00:00 2001 From: CrazyBloo Date: Fri, 23 Aug 2024 02:49:05 -0400 Subject: [PATCH 5/5] format again... --- src/common/memory_patcher.cpp | 2 +- src/qt_gui/cheats_patches.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp index 2c62a7e6f..af8b425c6 100644 --- a/src/common/memory_patcher.cpp +++ b/src/common/memory_patcher.cpp @@ -13,7 +13,7 @@ void AddPatchToQueue(patchInfo patchToAdd) { void ApplyPendingPatches() { -for (size_t i = 0; i < pending_patches.size(); ++i) { + for (size_t i = 0; i < pending_patches.size(); ++i) { patchInfo currentPatch = pending_patches[i]; PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr, currentPatch.isOffset); diff --git a/src/qt_gui/cheats_patches.cpp b/src/qt_gui/cheats_patches.cpp index a826db40a..32eea09fe 100644 --- a/src/qt_gui/cheats_patches.cpp +++ b/src/qt_gui/cheats_patches.cpp @@ -663,7 +663,7 @@ void CheatsPatches::applyPatch(const QString& patchName, bool enabled) { QString address = lineObject["Address"].toString(); QString patchValue = lineObject["Value"].toString(); - if (MemoryPatcher::g_eboot_address == 0) { + if (MemoryPatcher::g_eboot_address == 0) { MemoryPatcher::patchInfo addingPatch; addingPatch.modNameStr = patchName.toStdString(); addingPatch.offsetStr = address.toStdString();