Last active
February 25, 2022 12:41
-
-
Save TheRouletteBoi/b8800db83a6741fbf3fd4de7bef74b01 to your computer and use it in GitHub Desktop.
PS3 Detour class (LEGACY) and enstone hooking. PowerPC, PPC, PS3, Playstation 3
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
// 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