mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 12:04:45 +00:00
Merge pull request #4 from CrazyBloo/Cheats_Patches
Initial Patch Implementation
This commit is contained in:
commit
6be2251724
7 changed files with 128 additions and 33 deletions
|
@ -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
|
||||
|
|
51
src/common/memory_patcher.cpp
Normal file
51
src/common/memory_patcher.cpp
Normal 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
|
25
src/common/memory_patcher.h
Normal file
25
src/common/memory_patcher.h
Normal 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
|
|
@ -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() {
|
||||
|
|
|
@ -243,6 +243,4 @@ public:
|
|||
std::vector<u8> rela_bits;
|
||||
};
|
||||
|
||||
extern uintptr_t g_eboot_address;
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue