Skip to content

Instantly share code, notes, and snippets.

@TheRouletteBoi
Last active February 25, 2022 12:41
Show Gist options
  • Save TheRouletteBoi/b8800db83a6741fbf3fd4de7bef74b01 to your computer and use it in GitHub Desktop.
Save TheRouletteBoi/b8800db83a6741fbf3fd4de7bef74b01 to your computer and use it in GitHub Desktop.
PS3 Detour class (LEGACY) and enstone hooking. PowerPC, PPC, PS3, Playstation 3
// https://pastebin.com/yezsesij
static uint32_t GetFunctionBranch(uint32_t address)
{
uint32_t dest, temp;
dest = *(uint32_t*)address;
temp = dest;
dest = temp & 0x03FFFFFC;
if (temp & 0x02000000) dest |= 0xFC000000;
dest = address + dest;
return dest;
}
bool bCheckIfCMP(int ptr)
{
unsigned char b = *(unsigned char *)ptr;
unsigned char b2 = *(unsigned char *)(ptr + 1);
if (b == 0x40 || b == 0x41)
{
if (b2 == 0x9A || b2 == 0x82 || b2 == 0x99
|| b2 == 0x81 || b2 == 0x98 || b2 == 0x80)
return true;
}
return false;
}
bool IsValidPtr(void *value)
{
if (value == 0)
{
return false;
}
/*if ((uint32_t)(value) > 0x10000)
{
if (*(uint32_t *)(value) == 0)
{
return false;
}
}*/
return true;
}
struct importStub_s
{
int16_t ssize;
int16_t header1;
int16_t header2;
int16_t imports;
int32_t zero1;
int32_t zero2;
const char* name;
uint32_t* fnid;
opd_s** stub;
int32_t zero3;
int32_t zero4;
int32_t zero5;
int32_t zero6;
} *g_imports;
struct exportStub_s
{
int16_t ssize;
int16_t header1;
int16_t header2;
int16_t exports;
int32_t zero1;
int32_t zero2;
const char* name;
uint32_t* fnid;
opd_s** stub;
} *g_exports;
/*
skate 3
+ 0x30 export_adress_table
+ 0x38 import_adress_table
gta v
+ 0x38 export_adress_table // gta v doesn't have any exports
+ 0x40 import_adress_table
minecraft
+ 0x38 export_adress_table // minecraft doesn't have any exports
+ 0x40 import_adress_table
*/
opd_s * find_export(const char* module, uint32_t fnid)
{
uint32_t temp_prt = *(uint32_t *)(0x10000 + 0x1AC);
printf("temp_prt: 0x%X\n", temp_prt);
uint32_t export_adress_table = *(uint32_t *)(temp_prt + 0x38);
printf("export_adress_table: 0x%X\n", export_adress_table);
uint16_t *temp_exp = (uint16_t*)export_adress_table;
printf("temp_exp: 0x%X\n", temp_exp);
// while ((--temp_exp)->ssize == 0x1C00);
g_exports = (exportStub_s*)(temp_exp + 1);
printf("g_exports: 0x%X\n", g_exports);
exportStub_s* temp = g_exports;
printf("find_export temp: 0x%X\n", temp);
while (temp->ssize == 0x1C00)
{
printf("temp->name: %s\n", temp->name);
if (!strcmp(module, temp->name))
{
printf("temp->exports: 0x%X\n", temp->exports);
for (int16_t i = 0; i < temp->exports; i++)
{
if (temp->fnid[i] == fnid)
{
printf("temp->fnid[%i]: 0x%X\n", i, temp->fnid[i]);
return temp->stub[i];
}
}
}
temp++;
}
return NULL;
}
opd_s * find_import(const char* module, uint32_t fnid)
{
uint32_t temp_prt = *(uint32_t *)(0x10000 + 0x1AC);
printf("temp_prt: 0x%X\n", temp_prt);
uint32_t import_adress_table = *(uint32_t *)(temp_prt + 0x40);
printf("import_adress_table: 0x%X\n", import_adress_table);
uint16_t *temp_imp = (uint16_t*)import_adress_table;
printf("temp_imp: 0x%X\n", temp_imp);
while (*temp_imp++ != 0x2C00);
g_imports = (importStub_s*)(temp_imp - 1);
printf("g_imports: 0x%X\n", g_imports);
importStub_s* temp = g_imports;
printf("find_import temp: 0x%X\n", temp);
while (temp->ssize == 0x2C00)
{
printf("temp->name: %s\n", temp->name);
if (!strcmp(module, temp->name))
{
printf("temp->imports: 0x%X\n", temp->imports);
for (int16_t i = 0; i < temp->imports; i++)
{
printf("temp->fnid[%i]: 0x%X\n", i, temp->fnid[i]);
if (temp->fnid[i] == fnid)
{
return temp->stub[i];
}
}
}
temp++;
}
return NULL;
}
__attribute__((section(".text"))) uint8_t DetourAsm[500] = { 0 }; // was 0x3000, changed it to a smaller size because when I use 0x3000 it crashes my thread. I believe the reason it does that is because of the PS3 memory limit. use __attribute__((section(".text"))) to make the buffer executable
uint32_t DetourAsmIndex;
/*
TODO:
- make a stub for branchHook if possible???
- clean up FindExportByName FindImportByName
- make derived classes for different types of hooks
*/
template <class R>
class DetourHook
{
public:
// Made by Xx jAmes t xX ported and adapted to PS3 by TheRouLetteBoi
// This .h is used to edit functions to detour to your own custom one
//
// you may want to change the size of uint8_t DetourAsm[500] = { 0 }; depending on how many hooks you have but 500 should be enough for about 10 hooks
explicit DetourHook() : m_saveStub(0), m_moduleTOC(GAME_TOC) { } // __builtin_get_toc()
virtual ~DetourHook() { }
DetourHook(DetourHook const&) = delete;
DetourHook(DetourHook&&) = delete;
DetourHook& operator=(DetourHook const&) = delete;
DetourHook& operator=(DetourHook&&) = delete;
public:
enum class BranchhookType
{
BRANCH_HOOK,
BRANKLINK_HOOK,
};
public:
/***
* e.g
* detour_vmHook->Hook(0x9B4D00, (uint32_t)VM_HOOK);
* In the hook
* return detour_vmHook->GetOriginal(r3, globals, scrProgram, scrThread);
*/
virtual bool Hook(uint32_t address, uint32_t destination)
{
// prevent buffer overflow
if (g_DetourAsmCount > (MAX_DETOUR_ASM_SIZE - 2)) // if (g_DetourAsmCount > (sizeof(g_DetourAsm) - 2))
return false;
if (m_cache.address != address || m_saveStub == 0)
{
m_saveStub = (uint32_t)&g_DetourAsm[g_DetourAsmCount];
// save the address in case we take-down the detour
m_cache.address = address;
// Copy the asm bytes before we replace it with the hook
WriteProcessMemory(sys_process_getpid(), m_cache.originalAsm, (void*)address, 0x10);
// increment the index for the space we are using for the stub
g_DetourAsmCount += DetourFunctionStart(address, m_saveStub, destination);
return true;
}
return false;
}
/***
* e.g
* detour_cloneCreateHook->HookVMT(0x1C707E0, (uint32_t)CLONE_CREATE_HOOK);
* In the hook
* return detour_cloneCreateHook->GetOriginalVMT(netObjectMgr, netGamePlayerClient, netGamePlayerSelf, netObjType, objectId, sequenceId, syncData, timestamp);
*/
virtual bool HookVMT(uint32_t address, uint32_t destination)
{
if (m_cache.address != address)
{
// save the address in case we take-down the detour
m_cache.address = address;
// Copy the opd_s before we replace it with the hook
WriteProcessMemory(sys_process_getpid(), (void*)&m_cache.originalAsm, (void*)address, m_cache.originalSize = 0x8);
return VMTSwapHook(address, destination);
}
return false;
}
/***
* e.g
* detour_sysPpuThreadCreate = new DetourHook<int>;
* detour_sysPpuThreadCreate->HookIAT("sysPrxForUser", 0x24A1EA07, (uint32_t)SYS_PPU_THREAD_CREATE_HOOK);
* In the hook
* return detour_sysPpuThreadCreate->GetOriginalImportExport(thread_id, entry, arg, prio, stacksize, flags, threadname);
*
* e.g
* detour_cellFsOpen = new DetourHook<CellFsErrno>;
* detour_cellFsOpen->HookIAT("sys_fs", 0x718BF5F8, (uint32_t)CELL_FS_OPEN_HOOK);
* In the hook
* return detour_cellFsOpen->GetOriginalImportExport(path, flags, fd, arg, size);
*/
virtual bool HookIAT(const char* libaryName, uint32_t fnid, uint32_t destination) // IAT Hooking - "Import Address Table"
{
m_importExportCache.m_ImportExportOriginal = FindImportByName(libaryName, fnid);
if (m_importExportCache.m_ImportExportOriginal->sub == 0)
return false;
return Hook(m_importExportCache.m_ImportExportOriginal->sub, destination);
}
virtual bool HookEAT(const char* libaryName, uint32_t fnid, uint32_t destination) // EAT Hooking - "Export Address Table"
{
m_importExportCache.m_ImportExportOriginal = FindExportByName(libaryName, fnid);
if (m_importExportCache.m_ImportExportOriginal->sub == 0)
return false;
return Hook(m_importExportCache.m_ImportExportOriginal->sub, destination);
}
/***
* e.g
* detour_networkObjectMgr = new DetourHook<uint32_t>;
* detour_networkObjectMgr->HookClass(0x192F490, 18, (uint32_t)CLONE_CREATE_HOOK);
* detour_networkObjectMgr->HookClass(0x192F490, 20, (uint32_t)CLONE_SYNC_HOOK);
* detour_networkObjectMgr->HookClass(0x192F490, 22, (uint32_t)CLONE_REMOVE_HOOK);
* Since you have 3 hooks
* return detour_networkObjectMgr->GetOriginalClass(18, netObjectMgr, netGamePlayerClient, netGamePlayerSelf, netObjType, objectId, sequenceId, syncData, timestamp);
* return detour_networkObjectMgr->GetOriginalClass(20, networkObjectMgr, netGamePlayerClient, netGamePlayerSelf, netObjType, objectId, syncData, sequenceId, timestamp);
* return detour_networkObjectMgr->GetOriginalClass(22, networkObjectMgr, netGamePlayerClient, netGamePlayerSelf, objectId, r7);
*/
virtual bool HookClass(uint32_t classAddr, uint16_t vmtFunctionIndex, uint32_t destination)
{
if (ScanClassForFunctions(classAddr))
{
return VMTSwapHookAtIndex(vmtFunctionIndex, destination);
}
return false;
}
/***
* e.g
* detour_networkObjectMgr->HookClass("17CNetworkObjectMgr", 18, (uint32_t)CLONE_CREATE_HOOK);
* detour_networkObjectMgr->HookClass("17CNetworkObjectMgr", 20, (uint32_t)CLONE_SYNC_HOOK);
* detour_networkObjectMgr->HookClass("17CNetworkObjectMgr", 22, (uint32_t)CLONE_REMOVE_HOOK);
* Since you have 3 hooks
* return detour_networkObjectMgr->GetOriginalClass(18, netObjectMgr, netGamePlayerClient, netGamePlayerSelf, netObjType, objectId, sequenceId, syncData, timestamp);
* return detour_networkObjectMgr->GetOriginalClass(20, networkObjectMgr, netGamePlayerClient, netGamePlayerSelf, netObjType, objectId, syncData, sequenceId, timestamp);
* return detour_networkObjectMgr->GetOriginalClass(22, networkObjectMgr, netGamePlayerClient, netGamePlayerSelf, objectId, r7);
*/
virtual bool HookClass(const char* className, uint16_t vmtFunctionIndex, uint32_t destination)
{
uint32_t addr = FindClassByName(className);
if (addr == 0)
return false;
return HookClass(addr, vmtFunctionIndex, destination);
}
/***
* e.g
* detour_vmHook->HookInstruction(0x9B770C, (uint32_t)VM_HOOK, DetourHook<uint32_t>::BranchhookType::BRANKLINK_HOOK);
* In the hook
* return detour_vmHook->GetOriginalBranchLink(r3, globals, scrProgram, scrThread);
*/
virtual bool HookInstruction(uint32_t address, uint32_t destination, BranchhookType type = BranchhookType::BRANKLINK_HOOK) // HookSingleInstruction
{
if (m_cache.address != address)
{
m_cache.address = address;
WriteProcessMemory(sys_process_getpid(), (void*)&m_cache.originalAsm, (void*)address, m_cache.originalSize = 0x4);
// this should be a new variable instead of using the cache, but doing it for memory's sake
m_cache.originalAsm[1] = GetFunctionBranch(m_cache.address);
return BranchHook(address, destination, type);
}
return false;
}
// TODO: this is untested so test it soon
virtual void UnHook()
{
if (m_cache.address)
{
WriteProcessMemory(sys_process_getpid(), (void*)m_cache.address, (const void*)m_cache.originalAsm, 0x10);
}
}
// TODO: this is untested so test it soon
virtual void UnHookVMT()
{
if (m_cache.address)
{
WriteProcessMemory(sys_process_getpid(), (void*)m_cache.address, (const void*)m_cache.originalAsm, 0x8);
}
}
// TODO: this is untested so test it soon
virtual void UnHookClass()
{
if (m_classCache.m_hasBeenScanned)
{
for (int i = 0; i < m_classCache.m_vmtFunctionCount; i++)
{
WriteProcessMemory(sys_process_getpid(), (void*)m_classCache.m_vmt[i], (const void*)&m_classCache.m_redirectMap[i], 0x8);
}
if (m_classCache.m_redirectMap)
{
delete[] m_classCache.m_redirectMap;
}
m_classCache.m_hasBeenScanned = false;
}
}
// TODO: this is untested so test it soon
virtual void UnHookInstruction()
{
if (m_cache.address)
{
WriteProcessMemory(sys_process_getpid(), (void*)m_cache.address, (const void*)m_cache.originalAsm, 0x4);
}
}
// No more virtual :(
template <typename... TArgs>
R GetOriginal(TArgs... args)
{
volatile opd_s opd = { m_saveStub, m_moduleTOC };
return ((R(*)(...)) & opd)(args...);
}
template <typename... TArgs>
R GetOriginalVMT(TArgs... args)
{
volatile opd_s opd = { m_cache.originalAsm[0], m_cache.originalAsm[1] };
return ((R(*)(...)) & opd)(args...);
}
template <typename... TArgs>
R GetOriginalClass(uint32_t vmtFunctionIndex, TArgs... args)
{
volatile opd_s opd = { m_classCache.m_redirectMap[vmtFunctionIndex].sub, m_classCache.m_redirectMap[vmtFunctionIndex].toc };
return ((R(*)(...)) & opd)(args...);
}
template <typename... TArgs>
R GetOriginalImportExport(TArgs... args)
{
volatile opd_s opd = { m_saveStub, m_importExportCache.m_ImportExportOriginal->toc };
return ((R(*)(...)) & opd)(args...);
}
// this will only work if you hook a function that starts with a "bl sub_123456"
template <typename... TArgs>
R GetOriginalBranchLink(TArgs... args)
{
volatile opd_s opd = { m_cache.originalAsm[1], GAME_TOC };
return ((R(*)(...)) & opd)(args...);
}
private:
/***
* This function will get any 'b' or 'bl' and any 'cmp' function added to the stub that it replaces
* @return the size of the stub in byte lengths
*/
virtual uint32_t DetourFunctionStart(uint32_t functionAddress, uint32_t stubAddress, uint32_t destination)
{
destination = GetRawDestination(uint32_t, destination);
uint32_t writeLength = 0;
uint32_t branchBytes;
uint32_t tempFuncAddr;
bool bTemp;
for (int i = 0; i < 4; i++)
{
tempFuncAddr = functionAddress + (i * 4);
uint8_t b = *reinterpret_cast<uint8_t*>(tempFuncAddr);
// b or bl
if (b == 0x48 || b == 0x49 || b == 0x4B)
{
branchBytes = GetFunctionBranch(tempFuncAddr);
bTemp = (*reinterpret_cast<uint32_t*>(tempFuncAddr) & 1) != 0;
PatchInJump(reinterpret_cast<uint32_t*>(stubAddress + writeLength), branchBytes, bTemp, false);
writeLength += 0x10;
// if it was a 'b loc_' call, we won't need to anything else to the stub
if (!bTemp)
{
goto DoHook;
}
}
// beq or bne, ble or bgt, bge or blt
else if (CheckIfCMP(tempFuncAddr))
{
branchBytes = *reinterpret_cast<uint32_t*>(tempFuncAddr & 0xFFFF);
// if bTemp is true the op code is 'beq'
bTemp = b == 0x41;
// check if the branch location is within the stub
if (branchBytes <= 0x10 && branchBytes > 0)
{
if (branchBytes <= (0x10 - (i * 4)))
{
write_mem<uint32_t>((stubAddress + writeLength), *reinterpret_cast<uint32_t*>(tempFuncAddr));
writeLength += 4;
}
else
{
goto branch_else;
}
}
else
{
branch_else:
// make a jump past the call if the cmp != what it is checking
write_mem<uint32_t>(stubAddress + writeLength, (((0x40000000 + ((*reinterpret_cast<uint32_t*>(tempFuncAddr) & 0x00FF0000)) + 0x14)) + (bTemp ? 0x00000000 : 0x01000000)));
writeLength += 4;
PatchInJump(reinterpret_cast<uint32_t*>(stubAddress + writeLength), (tempFuncAddr + branchBytes), false, false);
writeLength += 0x10;
}
}
// if the function op code is null it is invalid
else if (*reinterpret_cast<uint32_t*>(tempFuncAddr) == 0)
{
break;
}
else
{
write_mem<uint32_t>((stubAddress + writeLength), *reinterpret_cast<uint32_t*>(tempFuncAddr));
writeLength += 4;
}
}
// make the stub call the orig function
PatchInJump(reinterpret_cast<uint32_t*>(stubAddress + writeLength), (functionAddress + 0x10), false, false);
writeLength += 0x10;
DoHook:
// apply the hook
PatchInJump(reinterpret_cast<uint32_t*>(functionAddress), destination, false, false);
return writeLength;
}
virtual bool VMTSwapHook(uint32_t address, uint32_t destination) // VMT Hooking / Pointer redirections
{
// replace the virtual table function with ours to intercept
if (write_mem<uint64_t>(address, *reinterpret_cast<uint64_t*>(destination)))
return true;
return false;
}
virtual bool VMTSwapHookAtIndex(int16_t vmtFunctionIndex, uint32_t destination)
{
return VMTSwapHook(m_classCache.m_vmt[vmtFunctionIndex], destination);
}
// makes a b or bl at the giving address
virtual bool BranchHook(uint32_t address, uint32_t destination, BranchhookType type)
{
destination = GetRawDestination(uint32_t, destination);
uint32_t branch;
if (type == BranchhookType::BRANCH_HOOK)
{
branch = (0x48000000 + ((destination - address) & 0x3FFFFFF));
}
else // type == BranchhookType::BRANKLINK_HOOK // branch link
{
branch = (0x48000000 + ((destination - address) & 0x3FFFFFF));
branch = branch += 1;
}
return write_mem<uint32_t>(address, branch);
}
uint16_t GetClassFunctionsCount()
{
uint16_t count = 0;
for (;; count++)
{
// if you have more than 500 virtual table functions you have a problem and i don't support you :)
if (m_classCache.m_vmt[count] == 0 || count > 500)
break;
}
return count;
}
bool ScanClassForFunctions(uint32_t& classAddr)
{
if (!m_classCache.m_hasBeenScanned)
{
// save the address in case we take-down the detour
m_cache.address = classAddr;
m_classCache.m_vmt = (uint32_t*)classAddr;
m_classCache.m_vmtFunctionCount = GetClassFunctionsCount();
// make sure this class thats virtual functions
if (m_classCache.m_vmtFunctionCount == 0)
return false;
// allocate an array to store our virtual table functions
m_classCache.m_redirectMap = new opd_s[m_classCache.m_vmtFunctionCount];
if (m_classCache.m_redirectMap == nullptr)
return false;
// clear the heap memory
memset(m_classCache.m_redirectMap, 0, sizeof(opd_s) * m_classCache.m_vmtFunctionCount);
// save a copy of the virtual table function addresses in case we need to restore them
for (int i = 0; i < m_classCache.m_vmtFunctionCount; i++)
write_mem<uint64_t>((uint32_t)&m_classCache.m_redirectMap[i], *reinterpret_cast<uint64_t*>(m_classCache.m_vmt[i]));
m_classCache.m_hasBeenScanned = true;
}
return true;
}
private:
struct HookCache
{
uint32_t address;
uint32_t originalAsm[4]; // 4 instructions
uint32_t originalSize;
HookCache() : address(0), originalSize(sizeof(uint32_t) * 4) { memset(originalAsm, 0, sizeof(originalAsm)); }
};
struct ClassHookCache
{
opd_s* m_redirectMap;
uint32_t* m_vmt;
uint16_t m_vmtFunctionCount;
bool m_hasBeenScanned;
ClassHookCache() : m_vmtFunctionCount(0), m_hasBeenScanned(false) { }
};
struct ImportExportHookCache
{
opd_s* m_ImportExportOriginal; // import export opd_s(sub, toc)
};
HookCache m_cache;
ClassHookCache m_classCache;
ImportExportHookCache m_importExportCache;
uint32_t m_saveStub;
uint32_t m_moduleTOC; // get the TOC of our sprx so we can use it to call our function later
};
-----------------------------------------------------------------------------------------------------------------------------
// this was me trying to get enstones hooking method working
uint64_t HookHandler(uint64_t a1, uint64_t a2)
{
printf("HookHandler\n");
printf("a1: 0x%X\n", a1);
printf("a2: 0x%X\n", a2);
/*
bool bVar1;
uint uVar2;
ulonglong uVar3;
ulonglong uVar4;
uint* puVar5;
undefined8 uVar6;
int iVar7;
uint uVar8;
uVar6 = *(undefined8*)(param_2 + 0x100);
while (*(char*)(param_1 + 0x18) == '\0')
{
sleep(100);
}
iVar7 = 0;
uVar8 = 0;
uVar2 = *(uint*)(param_1 + 0x14);
while (true)
{
bVar1 = uVar8 == uVar2;
uVar3 = (ulonglong)uVar8;
uVar4 = param_1 + 4U & 0xffffffff;
uVar8 = uVar8 + 1;
if (bVar1)
break;
puVar5 = (uint*)FUN_d00ff7ec(uVar4, uVar3);
if ((int)uVar6 - 4U == puVar5[1])
{
iVar7 = iVar7 + 1;
if (*(char*)(puVar5 + 2) == '\0')
{
ccapi_syscall(0x241); // enable syscall
*(undefined*)(puVar5 + 2) = 1;
}
(*(code*)(ulonglong) * (uint*)(ulonglong)*puVar5)(param_2 & 0xffffffff);
}
}
if (iVar7 == 0)
{
trapWord(0x1f, &stack0xffffffffffffff50, &stack0xffffffffffffff50);
}
return uVar4;
*/
return 1;
}
__attribute__((naked)) uint64_t HookHandlerAsm2(uint32_t a1)
{
__asm__(
"mr %r4, %r3;"
"addis %r3, %r2, -1;"
"addic %r3, %r3, 0x6CFC;"
"b ._Z11HookHandleryy;"
);
}
__attribute__((naked)) uint64_t HookHandlerAsm1() // uint32_t r3, uint32_t r4, uint32_t r5, uint32_t r6, uint32_t r7, uint32_t r8, uint32_t r9, uint32_t r10, uint32_t r11, uint32_t r12, uint32_t r13, uint32_t r14, uint32_t r15, uint32_t r16, uint32_t r17, uint32_t r18, uint32_t r19, uint32_t r20, uint32_t r21
{
__asm__(
"std %r0, 0x70(%r1);"
"addi %r0, %r1, 0x300;"
"std %r0, 0x78(%r1);"
"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);"
"mfctr %r0;"
"std %r0, 0x178(%r1);"
"mfcr %r0;"
"std %r0, 0x180(%r1);"
"mfxer %r0;"
"std %r0, 0x188(%r1);"
"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);"
"addi %r3, %r1, 0x70;"
"bl ._Z15HookHandlerAsm2j;"
"nop;"
"ld %r0, 0x170(%r1);"
"mtlr %r0;"
"ld %r0, 0x178(%r1);"
"mtctr %r0;"
"ld %r0, 0x180(%r1);"
"mtcr %r0;"
"ld %r0, 0x188(%r1);"
"mtxer %r0;"
"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);"
"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);"
"ld %r1, 0x78(%r1);"
"blr;"
);
}
// Destination = HookHandler
bool SetupHookHandler(uint32_t hookHandlerInstallationAddress, void* hookHandler) // enstone hooking method
{
// todo: add check to see if it's been hooked already
printf("SetupHookHandler\n");
printf("hookHandler: 0x%X\n", hookHandler);
uint32_t opcode[12];
opcode[0] = 0xF821FD01; // stdu r1,-0x300(r1)
opcode[1] = 0xF8410080; // std r2,0x80(r1)
opcode[2] = 0xF8610088; // std r3,0x88(r1)
opcode[3] = 0x7C4802A6; // mfspr r2,lr
opcode[4] = 0xF8410170; // std r2,0x170(r1) 0xC699EC
opcode[5] = 0x38600000; // li r3, 0x0
opcode[6] = 0x64630000 + ((((uint32_t)hookHandler) >> 16) & 0xFFFF); // oris r3,r3,0x188 opd@hi
opcode[7] = 0x60630000 + (((uint32_t)hookHandler) & 0xFFFF); // ori r3,r3,0x150 opd@low
opcode[8] = 0x80430004; // lwz r2,0x4(r3)
opcode[9] = 0x80630000; // lwz r3,0x0(r3) 0x18882B0 (sprx toc)
opcode[10] = 0x7C6803A6; // mtspr lr,r3
opcode[11] = 0x4E800020; // blr
WriteProcessMemory((void*)hookHandlerInstallationAddress, opcode, sizeof(opcode));
return true;
}
void HookAnyToHandler(uint32_t someTypeOfAllocator, uint32_t Destination, uint32_t Address)
{
printf("HookAnyToHandler\n");
SetupHookHandler(0x10080, HookHandlerAsm1);
//printf("Destination: 0x%X\n", Destination);
//Destination = (void*)*(uint32_t*)Destination; // opd_s
//printf("Destination: 0x%X\n", Destination);
uint32_t branchTo = 0x10080;
uint32_t branchFrom = Address;
// branch link hook
// 0x48000001
// 0x4C000001
// branch hook
// 0x48000000
// 0x4C000000
uint32_t branchInstruction = (branchTo > branchFrom) ?
0x48000001 + (branchTo - branchFrom) :
0x4C000001 - (branchFrom - branchTo);
printf("branchInstruction: 0x%X\n", branchInstruction);
WriteProcessMemory((void*)branchFrom, (const void*)&branchInstruction, 4);
// todo: it seems to have some type of std:: function. maybe std::bind or std::invoke or something else idk
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment