Skip to content

Instantly share code, notes, and snippets.

@TheRouletteBoi
Last active February 25, 2022 12:40
Show Gist options
  • Save TheRouletteBoi/f4fb4fda8ab957920eb5d07e191793cb to your computer and use it in GitHub Desktop.
Save TheRouletteBoi/f4fb4fda8ab957920eb5d07e191793cb to your computer and use it in GitHub Desktop.
Hooking method by using a single branch. PowerPC, PPC, PS3, Playstation 3
/** Initial Commit by gopro2027 **/
/** Revision #2 by gopro2027 **/
/**
* Added "original" into function hook
* Fixed branch instruction
*/
/** Revision #3 by TheRouLetteBoi **/
/**
* Addded 2 examples
* Automatically increment and find hooks using STL
* Cleaned up code so it is easier to understand
* Changed detour location to 0x10080 to support all games
* Renamed one_hook to HookHandler
* Removed PatchInJump
* Removed "some" not all redundant parameters
* Fixed warnings
*/
/**
reference https://pastebin.com/yezsesij (enstone hooking. scroll to the bottom)
reference https://pastebin.com/RBYPZEb5 (original)
GOAL:
- Make a hooking method without the need of a stub. that way we can use it on HEN and hopefully in Kernel LV2
- Have the ability to hook functions with less than 4 instructions
TODO
- Change executable detour location from 0xA104E8 to 0x10000 (ELF segment) so it works on any game
- Get rid of empty memory addresses (0x10065600) and use the stack
- Get rid of redundant parameters
- Fix warnings
- Make into a class?
- Find a better way to using get "original"
- Use __builtin_return_address() to get LR
- Use __builtin_get_toc() to get r2
- Use __reg(3) __reg(4) ect.. to get registers
*/
#undef vector
#include <vector>
#include <algorithm>
#define MAKE_JUMP(addr, to) *(uint32_t *)(addr) = (0x12 << 26) | ((((to-(addr))>>2)&0xFFFFFF) << 2)
#define __NAKED __attribute__((naked))
using original_t = void(*)();
using hooked_t =
uint64_t(*)(original_t,
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
struct hookCache
{
uint32_t hookAddress;
uint32_t originalInstruction;
uint64_t functionCallback;
};
std::vector<hookCache> hookList;
// three free memory locations (24 bytes)
#define ONE_HOOK_LR *(uint32_t*)0x10065600
#define ONE_HOOK_R2 *(uint32_t*)0x10065610
#define ONE_HOOK_BRANCHDATA *(uint32_t*)0x10065608
// need to add another one of these functions if the function you are hooking does not start with one of these two instructions
__NAKED void Stub_mflr_r0()
{
__asm("mflr %r0");
// can't put comments on the code below but it's grabbing the address to branch to and r2 and loading them up
__asm("lis %r11, 0x1006");
__asm("addi %r11, %r11, 0x5610");
__asm("lwz %r2, 0x0(%r11)"); // r2 = *(uint32_t*)(0x10065610)
__asm("lis %r11, 0x1006");
__asm("addi %r11, %r11, 0x5608");
__asm("lwz %r11, 0x0(%r11)"); // r11 = *(uint32_t*)(0x10065608)
__asm("mtctr %r11");
__asm("bctr"); // jump_to r11
}
__NAKED void Stub_r1_0x70()
{
__asm("stdu %r1, -0x70(%r1)");
// can't put comments on the code below but it's grabbing the address to branch to and r2 and loading them up
__asm("lis %r11, 0x1006");
__asm("addi %r11, %r11, 0x5610");
__asm("lwz %r2, 0x0(%r11)"); // r2 = *(uint32_t*)(0x10065610)
__asm("lis %r11, 0x1006");
__asm("addi %r11, %r11, 0x5608");
__asm("lwz %r11, 0x0(%r11)"); // r11 = *(uint32_t*)(0x10065608)
__asm("mtctr %r11");
__asm("bctr"); // jump_to r11
}
uint32_t ResolveBranch(uint32_t branchAddress)
{
uint32_t instruction = *(uint32_t*)(branchAddress);
int32_t offset = instruction & 0x3FFFFFC;
if (offset & (1 << 25))
offset |= ~0x03FFFFFF;
return branchAddress + offset;
}
uint64_t HookHandler(uint64_t r3, uint64_t r4, uint64_t r5, uint64_t r6, uint64_t r7, uint64_t r8, uint64_t r9,
uint64_t r10, uint64_t r11, uint64_t r12, uint64_t r13, uint64_t r14, uint64_t r15, uint64_t r16, uint64_t r17,
uint64_t r18, uint64_t r19, uint64_t r20, uint64_t r21)
{
uint32_t lr_val = ONE_HOOK_LR;
printf("LR found: 0x%X\n", lr_val);
uint32_t branched_from = lr_val - 0x4; // link register -0x4 is the branch command
uint32_t hookedAddress = ResolveBranch(branched_from);
printf("hooked address discovered: 0x%X\n", hookedAddress);
auto currentHook = std::find_if(hookList.begin(), hookList.end(), [&hookedAddress](const hookCache& cache)
{
return cache.hookAddress == hookedAddress;
});
ONE_HOOK_BRANCHDATA = hookedAddress + 4; // go to the next instruction after it
original_t original = nullptr;
uint64_t ret = 0;
if (hookList.end() != currentHook)
{
// find the original instruction depending on our hook
if ((*currentHook).originalInstruction == 0x7C0802A6) // mflr %r0
original = &Stub_mflr_r0;
else if ((*currentHook).originalInstruction == 0xF821FF91) // stdu %r1, -0x70(%r1)
original = &Stub_r1_0x70;
if (original != nullptr)
{
hooked_t func = (hooked_t)&(*currentHook).functionCallback;
ret = func(original, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21);
}
}
return ret;
}
__NAKED void HookHandlerAsm()
{
__asm("mflr %r0");//this will link back to the previous func
__asm("stdu %r1, -0x70(%r1)");
__asm("std %r0, 0x60(%r1)");
//now locate the link register from the previous function
//branched to - branched from = dif (lower 26 bits of instruction)
//branched to = dif + branched from
__asm("lis %r11, 0x1006");//assume r11 is never used
__asm("addi %r11, %r11, 0x5600");//ONE_HOOK_LR
__asm("stw %r0, 0x0(%r11)");//stores the lr to get back to the original call point into the spot we like
__asm("lis %r11, 0x1006");//assume r11 is never used
__asm("addi %r11, %r11, 0x5610");//ONE_HOOK_R2
__asm("stw %r2, 0x0(%r11)");//stores the r2 for us to reload later because it is used in many functions
__asm("bl ._Z11HookHandleryyyyyyyyyyyyyyyyyyy");//if you get a linker error then it is probably because of this
__asm("ld %r0, 0x60(%r1)");
__asm("mtlr %r0");//this will be the link register to the
__asm("addi %r1, %r1, 0x70");
__asm("blr");//goes all the way back to the function that called our hooked function
}
void SetupHook(uint32_t fnAddress, uintptr_t fnCallback)
{
uint32_t instructions[4]{};
instructions[0] = 0x3D600000 + ((fnCallback >> 16) & 0xFFFF); // lis %r11, fnCallback@h
instructions[1] = 0x616B0000 + (fnCallback & 0xFFFF); // ori %r11, %r11, fnCallback@l
instructions[2] = 0x7D6903A6; // mtctr %r11
instructions[3] = 0x4E800420; // bctr
WriteProcessMemory(sys_process_getpid(), (void*)fnAddress, instructions, sizeof(instructions));
}
void InstallHook()
{
SetupHook(0x10080, *(uintptr_t*)HookHandlerAsm);
}
void AddToHandler(uint32_t fnAddress, uintptr_t fnCallback)
{
hookList.push_back({
fnAddress,
*reinterpret_cast<uint32_t*>(fnAddress),
*reinterpret_cast<uint64_t*>(fnCallback)
});
MAKE_JUMP(fnAddress, 0x10080);
}
/** EXAMPLES **/
using GetLabelTextByHash_t = const char*(*)(uintptr_t labelHashMap, uint32_t labelHash, uintptr_t nameHash);
const char* GetLabelTextByHashHook(GetLabelTextByHash_t original, uintptr_t labelHashMap, uint32_t labelHash, uintptr_t nameHash)
{
if (labelHash == 0x478FDC87)
return "EPIC GAMER STYLE";
return original(labelHashMap, labelHash, nameHash);
}
using AssignPhysicalIndex_t = uintptr_t(*)(uintptr_t networkPlayerMgr, uintptr_t netGamePlayer, uint8_t index);
uintptr_t AssignPhysicalIndexHook(AssignPhysicalIndex_t original, uintptr_t networkPlayerMgr, uintptr_t netGamePlayer, uint8_t index)
{
printf("AssignPhysicalIndexHook\n");
printf("netGamePlayer 0x%X\n", netGamePlayer);
return original(networkPlayerMgr, netGamePlayer, index);
}
int main()
{
InstallHook();
// https://imgur.com/usuPNXK
AddToHandler(0xD91468, (uintptr_t)GetLabelTextByHashHook);
// https://imgur.com/yMbnnDC
AddToHandler(0xA15618, (uintptr_t)AssignPhysicalIndexHook);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment