Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- reference https://gist.github.com/iMoD1998/4aa48d5c990535767a3fc3251efc0348 (10x cleaner version than legacy detour class)
- reference https://github.com/skiff/libpsutil/blob/master/libpsutil/system/memory.cpp (tocOverride idea)
- reference https://pastebin.com/yezsesij (legacy detour class)
- Check https://pastebin.com/VCfMb46E (for GetCurrentToc(), WriteProcessMemory, MARK_AS_EXECUTABLE)
- TODO:
- - make derive class for imports and exports
- - make derive class for class symbol hooking. e.g: "17CNetworkObjectMgr" on gtav
- - make derive class for hooking a single instruction b or bl
- - make derive class for hooking a vtable functions or integrate with "class symbol hooking"
- - ???? HookByFnid @ImportExportHook "not implemented" seriously whats the point of the derived class. <- that needs to be changed
- #include <string>
- class DetourHook
- {
- public:
- DetourHook() = default;
- DetourHook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters = true, uint32_t tocOverride = 0);
- DetourHook(DetourHook const&) = delete;
- DetourHook(DetourHook&&) = delete;
- DetourHook& operator=(DetourHook const&) = delete;
- DetourHook& operator=(DetourHook&&) = delete;
- virtual ~DetourHook();
- virtual void* Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters = true, uint32_t tocOverride = 0);
- virtual void UnHook();
- template <typename R, typename... TArgs>
- R GetOriginal(TArgs... args)
- {
- R(*original)(TArgs...) = (R(*)(TArgs...))stubOpd;
- return original(args...);
- }
- private:
- void RelocateBranch(uint32_t instructionAddress, bool preserveRegisters);
- void RelocateBranchConditional(uint32_t instructionAddress, bool preserveRegisters);
- void RelocateCode(uint32_t instructionAddress, bool preserveRegisters);
- void JumpWithOptions(uint32_t fnAddress, uintptr_t fnCallback, uint32_t branchOptions, uint32_t conditionRegister, bool linked, bool preserveRegisters);
- void Jump(uint32_t fnAddress, uintptr_t fnCallback, bool linked, bool preserveRegisters);
- protected:
- uint8_t* stubAddress;
- uint32_t stubOpd[2];
- uint8_t originalInstructions[30];
- uint32_t hookAddress;
- size_t originalLength;
- size_t stubIndex;
- MARK_AS_EXECUTABLE static uint8_t stubs[200 * 20];
- static size_t stubOffset;
- };
- // list of fnids https://github.com/aerosoul94/ida_gel/blob/master/src/ps3/ps3.xml
- class ImportExportHook : public DetourHook
- {
- public:
- enum HookType { Import = 0, Export = 1 };
- public:
- ImportExportHook(HookType type, const std::string& libaryName,
- uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters = true);
- virtual ~ImportExportHook();
- virtual void* Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters = true, uint32_t tocOverride = 0) override;
- virtual void UnHook() override;
- private:
- void* HookByFnid(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters = true);
- opd_s* FindExportByName(const char* module, uint32_t fnid);
- opd_s* FindImportByName(const char* module, uint32_t fnid);
- private:
- std::string libaryName;
- uint32_t fnid;
- };
- #define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
- #define ADDRESS_HIGHER(X) ( ( X >> 16 ) & 0xFFFF )
- #define ADDRESS_LOWER(X) ( X & 0xFFFF )
- #define POWERPC_INSTRUCTION_LENGTH 4
- /*Opcodes*/
- #define POWERPC_BRANCH 0x48000000
- #define POWERPC_BRANCH_CONDITIONAL 0x40000000
- /*Takes Human based syntax numbers and returns approbate bits ie. bcctr 20, 0*/
- #define POWERPC_BRANCH_OPTION_SET(X) ( X << 21 )
- #define POWERPC_CONDITION_REGISTER_SET(X) ( X << 16 )
- /*Takes powerpc bits and converts to human based syntax*/
- #define POWERPC_BRANCH_OPTION_GET(X) ( X >> 21 )
- #define POWERPC_CONDITION_REGISTER_GET(X) ( X >> 16 )
- const uint32_t jumpASMPreserve[] = {
- 0x9161FFD0, // stw %r11, -0x30(%r1)
- 0x3D600000, // lis %r11, 0
- 0x616B0000, // ori %r11, %r11, 0
- 0x7D6903A6, // mtctr %r11
- 0x8161FFD0, // lwz %r11, -0x30(%r1)
- 0x4C800420 // bcctr (Used For PatchInJumpEx bcctr 20, 0 == bctr)
- };
- const uint32_t jumpASMNoPreserve[] = { /*Don't always have enough space to preserve registers*/
- 0x3D600000, // lis %r11, Destination@h
- 0x616B0000, // ori %r11, %r11, Destination@l
- 0x7D6903A6, // mtctr %r11
- 0x4C800420 // bcctr (Used For PatchInJumpEx bcctr 20, 0 == bctr)
- };
- uint8_t DetourHook::stubs[]{};
- size_t DetourHook::stubOffset = 0;
- DetourHook::DetourHook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters, uint32_t tocOverride)
- : stubAddress(nullptr), hookAddress(0), originalLength(0), stubIndex(0)
- {
- memset(stubOpd, 0, sizeof(stubOpd));
- memset(originalInstructions, 0, sizeof(originalInstructions));
- Hook(fnAddress, fnCallback, preserveRegisters);
- }
- DetourHook::~DetourHook()
- {
- UnHook();
- }
- void* DetourHook::Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters, uint32_t tocOverride)
- {
- stubIndex = 0;
- stubAddress = &stubs[stubOffset];
- size_t hookInstructionCount = preserveRegisters ? ARRAYSIZE(jumpASMPreserve) : ARRAYSIZE(jumpASMNoPreserve);
- for (int i = 0; i < hookInstructionCount; ++i)
- {
- uint32_t instructionAddress = (fnAddress + (i * POWERPC_INSTRUCTION_LENGTH));
- RelocateCode(instructionAddress, preserveRegisters);
- }
- size_t hookByteLength = preserveRegisters ? sizeof(jumpASMPreserve) : sizeof(jumpASMNoPreserve);
- uint32_t afterJumpAddress = static_cast<uint32_t>(fnAddress + hookByteLength);
- Jump(reinterpret_cast<uint32_t>(&stubAddress[stubIndex]), afterJumpAddress, false, preserveRegisters);
- Jump(fnAddress, *reinterpret_cast<uintptr_t*>(fnCallback), false, preserveRegisters);
- // gotta add on the size of the last jump back to the start of the original function
- stubOffset += stubIndex + hookByteLength;
- stubOpd[0] = reinterpret_cast<uint32_t>(stubAddress);
- stubOpd[1] = tocOverride != 0 ? tocOverride : GetCurrentToc();
- return (void*)stubAddress;
- }
- void DetourHook::UnHook()
- {
- if (originalLength)
- {
- WriteProcessMemory(sys_process_getpid(), (void*)hookAddress, originalInstructions, originalLength);
- originalLength = 0;
- }
- }
- void DetourHook::RelocateBranch(uint32_t instructionAddress, bool preserveRegisters)
- {
- /*
- B - Branch
- [Opcode] [Address] [Absolute] [Linked]
- 0-5 6-29 30 31
- Example
- 010010 0000 0000 0000 0000 0000 0001 0 0
- b label
- label:
- */
- uint32_t instructionOpcode = *(uint32_t*)instructionAddress;
- uint32_t currentStubPos = (uint32_t)&stubAddress[stubIndex];
- if (instructionOpcode & 0x2) /*BA BLA*/
- {
- WriteProcessMemory(sys_process_getpid(), (void*)currentStubPos, &instructionOpcode, sizeof(instructionOpcode));
- stubIndex += POWERPC_INSTRUCTION_LENGTH;
- }
- else
- {
- intptr_t branchOffset = instructionOpcode & 0x03FFFFFC;
- if (branchOffset & (1 << 25)) // If The MSB Is Set Make It Negative
- branchOffset |= ~0x03FFFFFF;
- intptr_t originalAddress = (intptr_t)(instructionAddress + branchOffset);
- Jump(currentStubPos, originalAddress, instructionOpcode & 1, preserveRegisters);
- size_t hookSize = preserveRegisters ? sizeof(jumpASMPreserve) : sizeof(jumpASMNoPreserve);
- stubIndex += hookSize;
- }
- }
- void DetourHook::RelocateBranchConditional(uint32_t instructionAddress, bool preserveRegisters)
- {
- /*
- BC - Branch Conditional
- [Opcode] [Branch Options] [Condition Register] [Address] [Absolute] [Linked]
- 0-5 6-10 11-15 16-29 30 31
- Example
- 010000 00100 00001 0000 0000 0000 01 0 0
- */
- uint32_t instructionOpcode = *(uint32_t*)instructionAddress;
- uint32_t currentStubPos = (uint32_t)&stubAddress[stubIndex];
- if (instructionOpcode & 0x2) /*Conditional Absolute*/
- {
- WriteProcessMemory(sys_process_getpid(), (void*)currentStubPos, &instructionOpcode, sizeof(instructionOpcode));
- stubIndex += POWERPC_INSTRUCTION_LENGTH;
- }
- else
- {
- uint32_t branchOptions = instructionOpcode & 0x03E00000;
- uint32_t conditionRegister = instructionOpcode & 0x001F0000;
- intptr_t branchOffset = instructionOpcode & 0x0000FFFC;
- if (branchOffset & (1 << 15)) // If The MSB Is Set Make It Negative
- branchOffset |= ~0x0000FFFF;
- intptr_t originalAddress = (intptr_t)(instructionAddress + branchOffset);
- JumpWithOptions(currentStubPos, originalAddress, POWERPC_BRANCH_OPTION_GET(branchOptions), POWERPC_CONDITION_REGISTER_GET(conditionRegister), instructionOpcode & 1, preserveRegisters);
- size_t hookSize = preserveRegisters ? sizeof(jumpASMPreserve) : sizeof(jumpASMNoPreserve);
- stubIndex += hookSize;
- }
- }
- void DetourHook::RelocateCode(uint32_t instructionAddress, bool preserveRegisters)
- {
- uint32_t instructionOpcode = *(uint32_t*)instructionAddress;
- uint32_t currentStubPos = (uint32_t)&stubAddress[stubIndex];
- switch (instructionOpcode & 0xFC000000)
- {
- case POWERPC_BRANCH: /*B BL BA BLA*/
- RelocateBranch(instructionAddress, preserveRegisters);
- break;
- case POWERPC_BRANCH_CONDITIONAL: /*BEQ BNE BLT BGE */
- RelocateBranchConditional(instructionAddress, preserveRegisters);
- break;
- default:
- WriteProcessMemory(sys_process_getpid(), (void*)currentStubPos, &instructionOpcode, sizeof(instructionOpcode));
- stubIndex += POWERPC_INSTRUCTION_LENGTH;
- break;
- }
- }
- void DetourHook::JumpWithOptions(uint32_t fnAddress, uintptr_t fnCallback, uint32_t branchOptions, uint32_t conditionRegister, bool linked, bool preserveRegisters)
- {
- branchOptions &= 0x1F; // Options only takes 5 bits
- conditionRegister &= 0x1F;
- if (preserveRegisters)
- {
- uint32_t instructions[ARRAYSIZE(jumpASMPreserve)];
- WriteProcessMemory(sys_process_getpid(), instructions, jumpASMPreserve, sizeof(jumpASMPreserve));
- instructions[1] |= ADDRESS_HIGHER(fnCallback);
- instructions[2] |= ADDRESS_LOWER(fnCallback);
- instructions[5] |= POWERPC_BRANCH_OPTION_SET(branchOptions) | POWERPC_CONDITION_REGISTER_SET(conditionRegister) | (uint32_t)linked;
- WriteProcessMemory(sys_process_getpid(), (void*)originalInstructions, (void*)fnAddress, sizeof(jumpASMPreserve));
- WriteProcessMemory(sys_process_getpid(), (void*)fnAddress, instructions, sizeof(instructions));
- originalLength = sizeof(jumpASMPreserve);
- }
- else
- {
- uint32_t instructions[ARRAYSIZE(jumpASMNoPreserve)];
- WriteProcessMemory(sys_process_getpid(), instructions, jumpASMNoPreserve, sizeof(jumpASMNoPreserve));
- instructions[0] |= ADDRESS_HIGHER(fnCallback);
- instructions[1] |= ADDRESS_LOWER(fnCallback);
- instructions[3] |= POWERPC_BRANCH_OPTION_SET(branchOptions) | POWERPC_CONDITION_REGISTER_SET(conditionRegister) | (uint32_t)linked;
- WriteProcessMemory(sys_process_getpid(), (void*)originalInstructions, (void*)fnAddress, sizeof(jumpASMNoPreserve));
- WriteProcessMemory(sys_process_getpid(), (void*)fnAddress, instructions, sizeof(instructions));
- originalLength = sizeof(jumpASMNoPreserve);
- }
- hookAddress = fnAddress;
- }
- void DetourHook::Jump(uint32_t fnAddress, uintptr_t fnCallback, bool linked, bool preserveRegisters)
- {
- JumpWithOptions(fnAddress, fnCallback, 20, 0, linked, preserveRegisters);
- }
- ImportExportHook::ImportExportHook(HookType type, const std::string& libaryName,
- uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters)
- : /*DetourHook(0x00000000, fnCallback, preserveRegisters, tocOverride), */libaryName(libaryName), fnid(fnid)
- {
- HookByFnid(type, libaryName, fnid, fnCallback, preserveRegisters);
- }
- ImportExportHook::~ImportExportHook()
- {
- UnHook();
- }
- void* ImportExportHook::Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters, uint32_t tocOverride)
- {
- // not implemented
- return nullptr;
- }
- void ImportExportHook::UnHook()
- {
- // not implemented
- }
- void* ImportExportHook::HookByFnid(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters)
- {
- opd_s* fnOpd = nullptr;
- switch (type)
- {
- case HookType::Import:
- {
- fnOpd = FindImportByName(libaryName.c_str(), fnid);
- break;
- }
- case HookType::Export:
- {
- fnOpd = FindExportByName(libaryName.c_str(), fnid);
- break;
- }
- }
- if (fnOpd == nullptr)
- return nullptr;
- return DetourHook::Hook(fnOpd->sub, fnCallback, preserveRegisters, fnOpd->toc);
- }
- opd_s* ImportExportHook::FindExportByName(const char* module, std::uint32_t fnid)
- {
- uint32_t* sysProcessPrxInfo = *reinterpret_cast<uint32_t**>(0x101DC); // 0x101DC or 0x101E4
- uint32_t exportAdressTable = sysProcessPrxInfo[4];
- exportStub_s* exportStub = reinterpret_cast<exportStub_s*>(exportAdressTable);
- while (exportStub->ssize == 0x1C00)
- {
- if (!strcmp(module, exportStub->name))
- {
- for (int16_t i = 0; i < exportStub->exports; i++)
- {
- if (exportStub->fnid[i] == fnid)
- {
- return exportStub->stub[i];
- }
- }
- }
- exportStub++;
- }
- return nullptr;
- }
- opd_s* ImportExportHook::FindImportByName(const char* module, uint32_t fnid)
- {
- uint32_t* sysProcessPrxInfo = *reinterpret_cast<uint32_t**>(0x101DC); // 0x101DC or 0x101E4
- uint32_t importAdressTable = sysProcessPrxInfo[6];
- importStub_s* importStub = reinterpret_cast<importStub_s*>(importAdressTable);
- while (importStub->ssize == 0x2C00)
- {
- if (!strcmp(module, importStub->name))
- {
- for (int16_t i = 0; i < importStub->imports; i++)
- {
- if (importStub->fnid[i] == fnid)
- {
- return importStub->stub[i];
- }
- }
- }
- importStub++;
- }
- return nullptr;
- }
- struct opd_s
- {
- uint32_t sub;
- uint32_t toc;
- };
- 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;
- };
- struct exportStub_s
- {
- int16_t ssize;
- int16_t header1;
- int16_t header2;
- int16_t exports; // number of exports
- int32_t zero1;
- int32_t zero2;
- const char* name;
- uint32_t* fnid;
- opd_s** stub;
- };
- EXAMPLES
- // hook any function using detour class
- DetourHook* StatSetIntHk;
- uint32_t StatSetIntHook(uint32_t statHash, uint32_t value, uint32_t save)
- {
- printf("StatSetIntHook\n");
- printf("statHash 0x%X\n", statHash);
- return StatSetIntHk->GetOriginal<uint32_t>(statHash, value, save);
- }
- https://imgur.com/rdBtu09
- StatSetIntHk = new DetourHook(0x42BE0C, (uintptr_t)StatSetIntHook);
- ImportExportHook* sysPpuThreadCreateHk;
- int sysPpuThreadCreateHook(sys_ppu_thread_t* thread_id, void(*entry)(uint64_t),
- uint64_t arg, int prio, size_t stacksize, uint64_t flags, const char* threadname)
- {
- printf("sysPpuThreadCreateHook\n");
- printf("thread_id: 0x%016llX\n", thread_id);
- printf("entry: 0x%016llX\n", entry);
- printf("arg: 0x%016llX\n", arg);
- printf("prio: 0x%X\n", prio);
- printf("stacksize: 0x%X\n", stacksize);
- printf("flags: 0x%016llX\n", flags);
- printf("threadname: %s\n", threadname);
- return sysPpuThreadCreateHk->GetOriginal<int>(thread_id, entry, arg, prio, stacksize, flags, threadname);
- }
- sysPpuThreadCreateHk = new ImportExportHook(ImportExportHook::Import, "sysPrxForUser", 0x24A1EA07, (uintptr_t)sysPpuThreadCreateHook);
- ImportExportHook* cellFsOpenHk;
- CellFsErrno cellFsOpenHook(const char* path, int flags, int* fd, const void* arg, uint64_t size)
- {
- printf("cellFsOpenHook\n");
- printf("path: %s\n", path);
- printf("flags: 0x%X\n", flags);
- printf("fd: 0x%X\n", fd);
- printf("arg: 0x%X\n", arg);
- printf("size: 0x%X\n", size);
- if (strcmp(path, "/dev_hdd0/game/BLES01807/USRDIR/dlc/dlc_mpPilot/DLC.edat") == 0)
- {
- path = "/dev_hdd0/tmp/Semjases/Mods/dlc/dlc_mpPilot/DLC.edat";
- }
- return cellFsOpenHk->GetOriginal<CellFsErrno>(path, flags, fd, arg, size);
- }
- cellFsOpenHk = new ImportExportHook(ImportExportHook::Import, "sys_fs", 0x718BF5F8, (uintptr_t)cellFsOpenHook);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement