Skip to content

Instantly share code, notes, and snippets.

@TheRouletteBoi
Forked from jordywastaken/HookManager.cpp
Last active December 21, 2022 18:15
Show Gist options
  • Save TheRouletteBoi/712f060505e7ecab51a61a48667532ac to your computer and use it in GitHub Desktop.
Save TheRouletteBoi/712f060505e7ecab51a61a48667532ac to your computer and use it in GitHub Desktop.
PlayStation 3 hooking class
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
}
#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);
}
#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