Add framework for in-game patches
This commit is contained in:
parent
e76aec4a67
commit
e86bb6cf15
13 changed files with 268 additions and 74 deletions
56
src/patcher/ingame.cpp
Normal file
56
src/patcher/ingame.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ingame.h"
|
||||
#include "rplinfo.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/asm.h"
|
||||
|
||||
#include <coreinit/title.h>
|
||||
|
||||
#include "patches/nn_olv.h"
|
||||
|
||||
void RunPatcher() {
|
||||
auto orplinfo = TryGetRPLInfo();
|
||||
if (!orplinfo) {
|
||||
DEBUG_FUNCTION_LINE("Couldn't get RPL info - trying patches");
|
||||
bool bret = PatchDynLoadFunctions();
|
||||
if (!bret) {
|
||||
DEBUG_FUNCTION_LINE("OSDynLoad patches failed! Quitting");
|
||||
return;
|
||||
}
|
||||
|
||||
//try again
|
||||
orplinfo = TryGetRPLInfo();
|
||||
if (!orplinfo) {
|
||||
DEBUG_FUNCTION_LINE("Still couldn't get RPL info - quitting");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto rpls = *orplinfo;
|
||||
|
||||
/*for (const auto& rpl : rpls) {
|
||||
DEBUG_FUNCTION_LINE("rpl[0]: [%s] %08x %08x %08x|%08x %08x %08x|%08x %08x %08x",
|
||||
rpl.name, rpl.textAddr, rpl.textOffset, rpl.textSize,
|
||||
rpl.dataAddr, rpl.dataOffset, rpl.dataSize,
|
||||
rpl.readAddr, rpl.readOffset, rpl.readSize
|
||||
);
|
||||
}*/
|
||||
|
||||
uint64_t titleId = OSGetTitleID();
|
||||
auto titleVer = __OSGetTitleVersion();
|
||||
|
||||
// "always" patches
|
||||
Patch_nn_olv(titleVer, titleId, rpls);
|
||||
}
|
||||
19
src/patcher/ingame.h
Normal file
19
src/patcher/ingame.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef INKAY_INGAME_H
|
||||
#define INKAY_INGAME_H
|
||||
|
||||
void RunPatcher();
|
||||
|
||||
#endif //INKAY_INGAME_H
|
||||
20
src/patcher/patcher.cpp
Normal file
20
src/patcher/patcher.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "patcher.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <kernel/kernel.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
|
||||
bool replace_string(uint32_t start, uint32_t size, const char* original_val, size_t original_val_sz, const char* new_val, size_t new_val_sz) {
|
||||
for (uint32_t addr = start; addr < start + size - original_val_sz; addr++) {
|
||||
int ret = memcmp(original_val, (void*)addr, original_val_sz);
|
||||
if (ret == 0) {
|
||||
DEBUG_FUNCTION_LINE("found str @%08x: %s", addr, (const char*)addr);
|
||||
KernelCopyData(OSEffectiveToPhysical(addr), OSEffectiveToPhysical((uint32_t)new_val), new_val_sz);
|
||||
DEBUG_FUNCTION_LINE("new str @%08x: %s", addr, (const char*)addr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
9
src/patcher/patcher.h
Normal file
9
src/patcher/patcher.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef INKAY_PATCHER_H
|
||||
#define INKAY_PATCHER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
bool replace_string(uint32_t start, uint32_t size, const char* original_val, size_t original_val_sz, const char* new_val, size_t new_val_sz);
|
||||
|
||||
#endif //INKAY_PATCHER_H
|
||||
30
src/patcher/patches/nn_olv.cpp
Normal file
30
src/patcher/patches/nn_olv.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "nn_olv.h"
|
||||
#include "utils/logger.h"
|
||||
#include "patcher/patcher.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
const char original_url[] = "discovery.olv.nintendo.net/v1/endpoint";
|
||||
const char new_url[] = "discovery.olv.pretendo.cc/v1/endpoint";
|
||||
_Static_assert(sizeof(original_url) > sizeof(new_url),
|
||||
"new_url too long! Must be less than 38chars.");
|
||||
|
||||
std::optional<OSDynLoad_NotifyData> checkForOlvLibs(const rplinfo& rpls) {
|
||||
auto res = FindRPL(rpls, "nn_olv.rpl");
|
||||
if (res) return res;
|
||||
|
||||
res = FindRPL(rpls, "nn_olv2.rpl");
|
||||
if (res) return res;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Patch_nn_olv(uint32_t titleVer, uint64_t titleId, const rplinfo& rpls) {
|
||||
auto olv_rpl = checkForOlvLibs(rpls);
|
||||
if (!olv_rpl) {
|
||||
DEBUG_FUNCTION_LINE("olv not loaded?");
|
||||
return;
|
||||
}
|
||||
|
||||
replace_string(olv_rpl->dataAddr, olv_rpl->dataSize, original_url, sizeof(original_url), new_url, sizeof(new_url));
|
||||
}
|
||||
8
src/patcher/patches/nn_olv.h
Normal file
8
src/patcher/patches/nn_olv.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _TPATCH_NN_OLV_H
|
||||
#define _TPATCH_NN_OLV_H
|
||||
|
||||
#include "patcher/rplinfo.h"
|
||||
|
||||
void Patch_nn_olv(uint32_t titleVer, uint64_t titleId, const rplinfo& rpls);
|
||||
|
||||
#endif //_TPATCH_NN_OLV_H
|
||||
70
src/patcher/rplinfo.cpp
Normal file
70
src/patcher/rplinfo.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "rplinfo.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <kernel/kernel.h>
|
||||
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
|
||||
std::optional<std::vector<OSDynLoad_NotifyData>> TryGetRPLInfo() {
|
||||
int num_rpls = OSDynLoad_GetNumberOfRPLs();
|
||||
if (num_rpls == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("num_rpls: %d", num_rpls);
|
||||
|
||||
std::vector<OSDynLoad_NotifyData> rpls;
|
||||
rpls.resize(num_rpls);
|
||||
|
||||
bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data());
|
||||
if (!ret) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return rpls;
|
||||
}
|
||||
|
||||
bool PatchInstruction(void* instr, uint32_t original, uint32_t replacement) {
|
||||
uint32_t current = *(uint32_t*)instr;
|
||||
DEBUG_FUNCTION_LINE("current instr %08x", current);
|
||||
if (current != original) return current == replacement;
|
||||
|
||||
KernelCopyData(OSEffectiveToPhysical((uint32_t)instr), OSEffectiveToPhysical((uint32_t)&replacement), sizeof(replacement));
|
||||
//Only works on AROMA! WUPS 0.1's KernelCopyData is uncached, needs DCInvalidate here instead
|
||||
DCFlushRange(instr, 4);
|
||||
ICInvalidateRange(instr, 4);
|
||||
|
||||
current = *(uint32_t*)instr;
|
||||
DEBUG_FUNCTION_LINE("patched instr %08x", current);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchDynLoadFunctions() {
|
||||
uint32_t *patch1 = ((uint32_t *) &OSDynLoad_GetNumberOfRPLs) + 6;
|
||||
uint32_t *patch2 = ((uint32_t *) &OSDynLoad_GetRPLInfo) + 22;
|
||||
|
||||
if (!PatchInstruction(patch1, 0x41820038 /* beq +38 */, 0x60000000 /*nop*/)) {
|
||||
return false;
|
||||
}
|
||||
if (!PatchInstruction(patch2, 0x41820100 /* beq +100 */, 0x60000000 /*nop*/)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
35
src/patcher/rplinfo.h
Normal file
35
src/patcher/rplinfo.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef INKAY_RPLINFO_H
|
||||
#define INKAY_RPLINFO_H
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
using rplinfo = std::vector<OSDynLoad_NotifyData>;
|
||||
|
||||
std::optional<rplinfo> TryGetRPLInfo();
|
||||
bool PatchDynLoadFunctions();
|
||||
|
||||
constexpr inline std::optional<OSDynLoad_NotifyData> FindRPL(const rplinfo& rpls, const std::string& name) {
|
||||
auto res = std::find_if(rpls.cbegin(), rpls.cend(), [&](const OSDynLoad_NotifyData& data){ return std::string(data.name).ends_with(name); });
|
||||
if (res == rpls.cend()) return std::nullopt;
|
||||
return *res;
|
||||
}
|
||||
|
||||
#endif //INKAY_RPLINFO_H
|
||||
Loading…
Reference in a new issue