-
-
Save TheRouletteBoi/712f060505e7ecab51a61a48667532ac to your computer and use it in GitHub Desktop.
PlayStation 3 hooking class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uint32_t GetCurrentToc() | |
{ | |
uint32_t* entry_point = *reinterpret_cast<uint32_t**>(0x1001C); // ElfHeader->e_entry | |
return entry_point[1]; | |
} | |
template <typename R, typename... TArgs> | |
inline R GameCall(std::uint32_t addr, TArgs... args) | |
{ | |
volatile opd_s opd = { addr, GetCurrentToc() }; | |
R(*func)(TArgs...) = (R(*)(TArgs...)) & opd; | |
return func(args...); | |
} | |
void GetLabelTextByGtxHook(HookRegisters* registers) | |
{ | |
// Original instruction at 0xD914D8 is 'std r0, 0x90+arg_10(r1)' | |
*(uint64_t*)(uint32_t)(registers->r1 + 0xA0) = registers->r0; | |
const char* labelName = (const char*)(uint32_t)(registers->r4); | |
printf("GetLabelTextByGtxHook\n"); | |
printf("labelHashMap: 0x%X\n", registers->r3); | |
printf("labelName: %s\n", labelName); | |
if (strcmp(labelName, "LEGAL_ROCKSTAR") == 0) | |
{ | |
// ??? | |
} | |
} | |
void GetLabelTextByHashHook(HookRegisters* registers) | |
{ | |
// Original instruction at 0xD91558 is 'bl sub_D91174' | |
const char* labelText = GameCall<const char*>(0xD91174, registers->r3, registers->r4); | |
const char* labelName = (const char*)(uint32_t)(registers->r30); | |
printf("GetLabelTextByHashHook\n"); | |
printf("labelHashMap: 0x%X\n", registers->r3); | |
printf("labelHash: 0x%X\n", registers->r4); | |
if (strcmp(labelName, "LEGAL_ROCKSTAR") == 0) | |
{ | |
registers->r3 = (uint32_t)"hello from hash hook"; | |
return; | |
} | |
else if (strcmp(labelName, "LEGAL_SPLASH") == 0) | |
{ | |
registers->r3 = (uint32_t)"hello from hash hook"; | |
return; | |
} | |
registers->r3 = (uint32_t)labelText; | |
} | |
void VmOpCode44_NativeCallHook(HookRegisters* registers) | |
{ | |
// Original instruction at 0x9B5A08 is 'bcctrl 20 4*cr7+eq' | |
uint32_t funcAddr = (uint32_t)(registers->r4); | |
GameCall<void>(funcAddr, registers->r3); | |
} | |
int main() | |
{ | |
g_Hooks = Hooking(); | |
g_Hooks.AddToHandler(0xD914D8, GetLabelTextByGtxHook); // https://imgur.com/a/83DPu0z | |
g_Hooks.AddToHandler(0xD91558, GetLabelTextByHashHook); // https://imgur.com/a/d1CdYMt | |
g_Hooks.AddToHandler(0x9B5A08, VmOpCode44_NativeCallHook); // https://imgur.com/a/voTdVIp | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "HookHandler.hpp" | |
Hooking::Hooking(uint32_t mainHookAddress) | |
: m_MainHookAddress(mainHookAddress) | |
{ | |
Install(); | |
} | |
void Hooking::Install() | |
{ | |
// Install our main hook | |
uint32_t hookRedirect = *(uint32_t*)RedirectToHandler; // Get func address from opd | |
// Copy Hooking::RedirectToHandler to m_MainHookAddress because we can't branch to it directly. | |
// 12 is the number of instructions in our function | |
for (int i = 0; i < 12; i++) | |
*(uint32_t*)(m_MainHookAddress + 4 * i) = *(uint32_t*)(hookRedirect + 4 * i); | |
} | |
void __attribute__((noinline)) Hooking::Handler(HookRegisters* registers) | |
{ | |
// This shouldn't happen, but just in case... | |
if (!registers) | |
return; | |
// Look through all our hooks to find the corresponding callback | |
for (auto& hook : m_HookData) | |
{ | |
if ((uint32_t(registers->lr) - 4) != hook.address) | |
continue; | |
hook.callback(registers); | |
return; | |
} | |
// Just in case our hook callback isn't executed | |
__builtin_trap(); | |
} | |
void Hooking::AddToHandler(uint32_t address, void(*callback)(HookRegisters*)) | |
{ | |
// If the address isn't valid don't go further | |
if (address < 0x10000) | |
return; | |
HookData hook; | |
hook.callback = callback; | |
hook.address = address; | |
hook.instruction = *(uint32_t*)address; | |
// Branch link address to Hooking::RedirectToHandler(). | |
#define MAKE_CALL(address, to) *(uint32_t*)address = (0x48000001 + ((to - address) & 0x3FFFFFF)); | |
MAKE_CALL(address, m_MainHookAddress); | |
#undef MAKE_CALL | |
m_HookData.push_back(hook); | |
} | |
void Hooking::ClearAll() | |
{ | |
// Restore original instructions | |
for (auto& hook : m_HookData) | |
*(uint32_t*)hook.address = hook.instruction; | |
m_HookData.clear(); | |
} | |
//=============================================== | |
// This is the asm part. | |
void __attribute__((naked)) Hooking::RedirectToHandler() | |
{ | |
asm( | |
// Allocate enough space to save the registers | |
"stdu %r1, -0x300(%r1);" | |
// Save r2, r3 and the link register now because we will need them | |
"std %r2, 0x80(%r1);" | |
"std %r3, 0x88(%r1);" | |
"mflr %r2;" | |
"std %r2, 0x170(%r1);" | |
// Get the opd pointer from Hooking::HandleRegisters() and call it | |
"li %r3, 0;" | |
"oris %r3, %r3, _ZN7Hooking15HandleRegistersEv@h;" | |
"ori %r3, %r3, _ZN7Hooking15HandleRegistersEv@l;" | |
"lwz %r2, 4(%r3);" | |
"lwz %r3, 0(%r3);" | |
"mtlr %r3;" | |
"blr;" | |
); | |
} | |
void __attribute__((naked)) Hooking::HandleRegisters() | |
{ | |
asm( | |
// Save r0 | |
"std %r0, 0x70(%r1);" | |
// Save r1 as r1 + 0x300 to get the hooked function stack address | |
"addi %r0, %r1, 0x300;" | |
"std %r0, 0x78(%r1);" | |
// Save all gprs | |
"std %r4, 0x90(%r1);" | |
"std %r5, 0x98(%r1);" | |
"std %r6, 0xA0(%r1);" | |
"std %r7, 0xA8(%r1);" | |
"std %r8, 0xB0(%r1);" | |
"std %r9, 0xB8(%r1);" | |
"std %r10, 0xC0(%r1);" | |
"std %r11, 0xC8(%r1);" | |
"std %r12, 0xD0(%r1);" | |
"std %r13, 0xD8(%r1);" | |
"std %r14, 0xE0(%r1);" | |
"std %r15, 0xE8(%r1);" | |
"std %r16, 0xF0(%r1);" | |
"std %r17, 0xF8(%r1);" | |
"std %r18, 0x100(%r1);" | |
"std %r19, 0x108(%r1);" | |
"std %r20, 0x110(%r1);" | |
"std %r21, 0x118(%r1);" | |
"std %r22, 0x120(%r1);" | |
"std %r23, 0x128(%r1);" | |
"std %r24, 0x130(%r1);" | |
"std %r25, 0x138(%r1);" | |
"std %r26, 0x140(%r1);" | |
"std %r27, 0x148(%r1);" | |
"std %r28, 0x150(%r1);" | |
"std %r29, 0x158(%r1);" | |
"std %r30, 0x160(%r1);" | |
"std %r31, 0x168(%r1);" | |
// Save all sprs | |
"mfctr %r0;" | |
"std %r0, 0x178(%r1);" | |
"mfcr %r0;" | |
"std %r0, 0x180(%r1);" | |
"mfxer %r0;" | |
"std %r0, 0x188(%r1);" | |
// Save all fprs | |
"stfd %f0, 0x190(%r1);" | |
"stfd %f1, 0x198(%r1);" | |
"stfd %f2, 0x1A0(%r1);" | |
"stfd %f3, 0x1A8(%r1);" | |
"stfd %f4, 0x1B0(%r1);" | |
"stfd %f5, 0x1B8(%r1);" | |
"stfd %f6, 0x1C0(%r1);" | |
"stfd %f7, 0x1C8(%r1);" | |
"stfd %f8, 0x1D0(%r1);" | |
"stfd %f9, 0x1D8(%r1);" | |
"stfd %f10, 0x1E0(%r1);" | |
"stfd %f11, 0x1E8(%r1);" | |
"stfd %f12, 0x1F0(%r1);" | |
"stfd %f13, 0x1F8(%r1);" | |
"stfd %f14, 0x200(%r1);" | |
"stfd %f15, 0x208(%r1);" | |
"stfd %f16, 0x210(%r1);" | |
"stfd %f17, 0x218(%r1);" | |
"stfd %f18, 0x220(%r1);" | |
"stfd %f19, 0x228(%r1);" | |
"stfd %f20, 0x230(%r1);" | |
"stfd %f21, 0x238(%r1);" | |
"stfd %f22, 0x240(%r1);" | |
"stfd %f23, 0x248(%r1);" | |
"stfd %f24, 0x250(%r1);" | |
"stfd %f25, 0x258(%r1);" | |
"stfd %f26, 0x260(%r1);" | |
"stfd %f27, 0x268(%r1);" | |
"stfd %f28, 0x270(%r1);" | |
"stfd %f29, 0x278(%r1);" | |
"stfd %f30, 0x280(%r1);" | |
"stfd %f31, 0x288(%r1);" | |
// Pass a pointer to our local HookRegisters as r3 | |
"addi %r3, %r1, 0x70;" | |
// Call our hook handler | |
"bl ._ZN7Hooking11CallHandlerEP13HookRegisters;" | |
"nop;" | |
// Restore sprs | |
"ld %r0, 0x170(%r1);" | |
"mtlr %r0;" | |
"ld %r0, 0x178(%r1);" | |
"mtctr %r0;" | |
"ld %r0, 0x180(%r1);" | |
"mtcr %r0;" | |
"ld %r0, 0x188(%r1);" | |
"mtxer %r0;" | |
// Restore gprs | |
"ld %r0, 0x70(%r1);" | |
"nop;" | |
"ld %r2, 0x80(%r1);" | |
"ld %r3, 0x88(%r1);" | |
"ld %r4, 0x90(%r1);" | |
"ld %r5, 0x98(%r1);" | |
"ld %r6, 0xA0(%r1);" | |
"ld %r7, 0xA8(%r1);" | |
"ld %r8, 0xB0(%r1);" | |
"ld %r9, 0xB8(%r1);" | |
"ld %r10, 0xC0(%r1);" | |
"ld %r11, 0xC8(%r1);" | |
"ld %r12, 0xD0(%r1);" | |
"ld %r13, 0xD8(%r1);" | |
"ld %r14, 0xE0(%r1);" | |
"ld %r15, 0xE8(%r1);" | |
"ld %r16, 0xF0(%r1);" | |
"ld %r17, 0xF8(%r1);" | |
"ld %r18, 0x100(%r1);" | |
"ld %r19, 0x108(%r1);" | |
"ld %r20, 0x110(%r1);" | |
"ld %r21, 0x118(%r1);" | |
"ld %r22, 0x120(%r1);" | |
"ld %r23, 0x128(%r1);" | |
"ld %r24, 0x130(%r1);" | |
"ld %r25, 0x138(%r1);" | |
"ld %r26, 0x140(%r1);" | |
"ld %r27, 0x148(%r1);" | |
"ld %r28, 0x150(%r1);" | |
"ld %r29, 0x158(%r1);" | |
"ld %r30, 0x160(%r1);" | |
"ld %r31, 0x168(%r1);" | |
// Restore fprs | |
"lfd %f0, 0x190(%r1);" | |
"lfd %f1, 0x198(%r1);" | |
"lfd %f2, 0x1A0(%r1);" | |
"lfd %f3, 0x1A8(%r1);" | |
"lfd %f4, 0x1B0(%r1);" | |
"lfd %f5, 0x1B8(%r1);" | |
"lfd %f6, 0x1C0(%r1);" | |
"lfd %f7, 0x1C8(%r1);" | |
"lfd %f8, 0x1D0(%r1);" | |
"lfd %f9, 0x1D8(%r1);" | |
"lfd %f10, 0x1E0(%r1);" | |
"lfd %f11, 0x1E8(%r1);" | |
"lfd %f12, 0x1F0(%r1);" | |
"lfd %f13, 0x1F8(%r1);" | |
"lfd %f14, 0x200(%r1);" | |
"lfd %f15, 0x208(%r1);" | |
"lfd %f16, 0x210(%r1);" | |
"lfd %f17, 0x218(%r1);" | |
"lfd %f18, 0x220(%r1);" | |
"lfd %f19, 0x228(%r1);" | |
"lfd %f20, 0x230(%r1);" | |
"lfd %f21, 0x238(%r1);" | |
"lfd %f22, 0x240(%r1);" | |
"lfd %f23, 0x248(%r1);" | |
"lfd %f24, 0x250(%r1);" | |
"lfd %f25, 0x258(%r1);" | |
"lfd %f26, 0x260(%r1);" | |
"lfd %f27, 0x268(%r1);" | |
"lfd %f28, 0x270(%r1);" | |
"lfd %f29, 0x278(%r1);" | |
"lfd %f30, 0x280(%r1);" | |
"lfd %f31, 0x288(%r1);" | |
// Restore r1 and return | |
"ld %r1, 0x78(%r1);" | |
"blr;" | |
); | |
} | |
void Hooking::CallHandler(HookRegisters* registers) | |
{ | |
g_Hooks.Handler(registers); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#undef vector | |
#include <vector> | |
struct HookRegisters | |
{ | |
// General purpose registers (gprs) | |
uint64_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31; | |
// Special purpose registers (sprs) | |
uint64_t lr, ctr, cr, xer; | |
// Floating point registers (fprs) | |
double f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, f31; | |
}; | |
class Hooking | |
{ | |
public: | |
struct HookData | |
{ | |
void(*callback)(HookRegisters*); | |
uint32_t address; | |
uint32_t instruction; | |
}; | |
public: | |
// 0x10050 for vsh or 0x10080 for game are used by enstone but conflict with the ps3 toolbox rpc. | |
// 0x10200 is always .init_proc which has just enough space to place our main hook | |
Hooking(uint32_t mainHookAddress = 0x10200); | |
void Install(); | |
void Handler(HookRegisters* registers); | |
void AddToHandler(uint32_t address, void(*callback)(HookRegisters*)); | |
void ClearAll(); | |
private: | |
static void RedirectToHandler(); | |
static void HandleRegisters(); | |
static void CallHandler(HookRegisters* registers); | |
private: | |
std::vector<HookData> m_HookData{}; | |
uint32_t m_MainHookAddress{}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment