Advertisement
TheRouletteBoi

PS3 Detour

Sep 26th, 2021 (edited)
813
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.59 KB | None | 0 0
  1. reference https://gist.github.com/iMoD1998/4aa48d5c990535767a3fc3251efc0348  (10x cleaner version than legacy detour class)
  2. reference https://github.com/skiff/libpsutil/blob/master/libpsutil/system/memory.cpp   (tocOverride idea)
  3. reference https://pastebin.com/yezsesij   (legacy detour class)
  4. Check https://pastebin.com/VCfMb46E  (for GetCurrentToc(), WriteProcessMemory, MARK_AS_EXECUTABLE)
  5.  
  6. TODO:
  7. - make derive class for imports and exports
  8. - make derive class for class symbol hooking. e.g: "17CNetworkObjectMgr" on gtav
  9. - make derive class for hooking a single instruction b or bl
  10. - make derive class for hooking a vtable functions or integrate with "class symbol hooking"
  11. - ???? HookByFnid @ImportExportHook "not implemented" seriously whats the point of the derived class. <- that needs to be changed
  12.  
  13.  
  14.  
  15. #include <string>
  16.  
  17. class DetourHook
  18. {
  19. public:
  20.    DetourHook() = default;
  21.    DetourHook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters = true, uint32_t tocOverride = 0);
  22.    DetourHook(DetourHook const&) = delete;
  23.    DetourHook(DetourHook&&) = delete;
  24.    DetourHook& operator=(DetourHook const&) = delete;
  25.    DetourHook& operator=(DetourHook&&) = delete;
  26.    virtual ~DetourHook();
  27.  
  28.    virtual void* Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters = true, uint32_t tocOverride = 0);
  29.    virtual void UnHook();
  30.  
  31.    template <typename R, typename... TArgs>
  32.    R GetOriginal(TArgs... args)
  33.    {
  34.       R(*original)(TArgs...) = (R(*)(TArgs...))stubOpd;
  35.       return original(args...);
  36.    }
  37.  
  38. private:
  39.    void RelocateBranch(uint32_t instructionAddress, bool preserveRegisters);
  40.    void RelocateBranchConditional(uint32_t instructionAddress, bool preserveRegisters);
  41.    void RelocateCode(uint32_t instructionAddress, bool preserveRegisters);
  42.    void JumpWithOptions(uint32_t fnAddress, uintptr_t fnCallback, uint32_t branchOptions, uint32_t conditionRegister, bool linked, bool preserveRegisters);
  43.    void Jump(uint32_t fnAddress, uintptr_t fnCallback, bool linked, bool preserveRegisters);
  44.  
  45. protected:
  46.    uint8_t* stubAddress;
  47.    uint32_t stubOpd[2];
  48.    uint8_t originalInstructions[30];
  49.    uint32_t hookAddress;
  50.    size_t originalLength;
  51.    size_t stubIndex;
  52.  
  53.    MARK_AS_EXECUTABLE static uint8_t stubs[200 * 20];
  54.    static size_t stubOffset;
  55. };
  56.  
  57. // list of fnids https://github.com/aerosoul94/ida_gel/blob/master/src/ps3/ps3.xml
  58. class ImportExportHook : public DetourHook
  59. {
  60. public:
  61.    enum HookType { Import = 0, Export = 1 };
  62. public:
  63.    ImportExportHook(HookType type, const std::string& libaryName,
  64.       uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters = true);
  65.    virtual ~ImportExportHook();
  66.  
  67.    virtual void* Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters = true, uint32_t tocOverride = 0) override;
  68.    virtual void UnHook() override;
  69.  
  70. private:
  71.    void* HookByFnid(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters = true);
  72.    opd_s* FindExportByName(const char* module, uint32_t fnid);
  73.    opd_s* FindImportByName(const char* module, uint32_t fnid);
  74.  
  75. private:
  76.    std::string libaryName;
  77.    uint32_t fnid;
  78. };
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86. #define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
  87.  
  88. #define ADDRESS_HIGHER(X) ( ( X >> 16 ) & 0xFFFF )
  89. #define ADDRESS_LOWER(X)  ( X & 0xFFFF )
  90.  
  91. #define POWERPC_INSTRUCTION_LENGTH 4
  92.  
  93. /*Opcodes*/
  94. #define POWERPC_BRANCH             0x48000000
  95. #define POWERPC_BRANCH_CONDITIONAL 0x40000000
  96.  
  97. /*Takes Human based syntax numbers and returns approbate bits ie. bcctr 20, 0*/
  98. #define POWERPC_BRANCH_OPTION_SET(X)      ( X << 21 )
  99. #define POWERPC_CONDITION_REGISTER_SET(X) ( X << 16 )
  100.  
  101. /*Takes powerpc bits and converts to human based syntax*/
  102. #define POWERPC_BRANCH_OPTION_GET(X)      ( X >> 21 )
  103. #define POWERPC_CONDITION_REGISTER_GET(X) ( X >> 16 )
  104.  
  105. const uint32_t jumpASMPreserve[] = {
  106.    0x9161FFD0, // stw %r11, -0x30(%r1)
  107.    0x3D600000, // lis %r11, 0
  108.    0x616B0000, // ori %r11, %r11, 0
  109.    0x7D6903A6, // mtctr %r11
  110.    0x8161FFD0, // lwz %r11, -0x30(%r1)
  111.    0x4C800420  // bcctr (Used For PatchInJumpEx bcctr 20, 0 == bctr)
  112. };
  113.  
  114. const uint32_t jumpASMNoPreserve[] = { /*Don't always have enough space to preserve registers*/
  115.    0x3D600000, // lis %r11, Destination@h
  116.    0x616B0000, // ori %r11, %r11, Destination@l
  117.    0x7D6903A6, // mtctr %r11
  118.    0x4C800420  // bcctr (Used For PatchInJumpEx bcctr 20, 0 == bctr)
  119. };
  120.  
  121. uint8_t DetourHook::stubs[]{};
  122. size_t DetourHook::stubOffset = 0;
  123.  
  124. DetourHook::DetourHook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters, uint32_t tocOverride)
  125.    : stubAddress(nullptr), hookAddress(0), originalLength(0), stubIndex(0)
  126. {
  127.    memset(stubOpd, 0, sizeof(stubOpd));
  128.    memset(originalInstructions, 0, sizeof(originalInstructions));
  129.  
  130.    Hook(fnAddress, fnCallback, preserveRegisters);
  131. }
  132.  
  133. DetourHook::~DetourHook()
  134. {
  135.    UnHook();
  136. }
  137.  
  138. void* DetourHook::Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters, uint32_t tocOverride)
  139. {
  140.    stubIndex = 0;
  141.    stubAddress = &stubs[stubOffset];
  142.  
  143.    size_t hookInstructionCount = preserveRegisters ? ARRAYSIZE(jumpASMPreserve) : ARRAYSIZE(jumpASMNoPreserve);
  144.  
  145.    for (int i = 0; i < hookInstructionCount; ++i)
  146.    {
  147.       uint32_t instructionAddress = (fnAddress + (i * POWERPC_INSTRUCTION_LENGTH));
  148.  
  149.       RelocateCode(instructionAddress, preserveRegisters);
  150.    }
  151.  
  152.    size_t hookByteLength = preserveRegisters ? sizeof(jumpASMPreserve) : sizeof(jumpASMNoPreserve);
  153.  
  154.    uint32_t afterJumpAddress = static_cast<uint32_t>(fnAddress + hookByteLength);
  155.  
  156.    Jump(reinterpret_cast<uint32_t>(&stubAddress[stubIndex]), afterJumpAddress, false, preserveRegisters);
  157.  
  158.    Jump(fnAddress, *reinterpret_cast<uintptr_t*>(fnCallback), false, preserveRegisters);
  159.  
  160.    // gotta add on the size of the last jump back to the start of the original function
  161.    stubOffset += stubIndex + hookByteLength;
  162.  
  163.    stubOpd[0] = reinterpret_cast<uint32_t>(stubAddress);
  164.    stubOpd[1] = tocOverride != 0 ? tocOverride : GetCurrentToc();
  165.  
  166.    return (void*)stubAddress;
  167. }
  168.  
  169. void DetourHook::UnHook()
  170. {
  171.    if (originalLength)
  172.    {
  173.       WriteProcessMemory(sys_process_getpid(), (void*)hookAddress, originalInstructions, originalLength);
  174.  
  175.       originalLength = 0;
  176.    }
  177. }
  178.  
  179. void DetourHook::RelocateBranch(uint32_t instructionAddress, bool preserveRegisters)
  180. {
  181.    /*
  182.  
  183.    B - Branch
  184.  
  185.    [Opcode]       [Address]              [Absolute] [Linked]
  186.    0-5              6-29                     30        31
  187.  
  188.    Example
  189.  
  190.    ‭010010    0000 0000 0000 0000 0000 0001   0         0‬
  191.  
  192.    b label
  193.    label:
  194.  
  195.    */
  196.  
  197.    uint32_t instructionOpcode = *(uint32_t*)instructionAddress;
  198.    uint32_t currentStubPos = (uint32_t)&stubAddress[stubIndex];
  199.  
  200.    if (instructionOpcode & 0x2) /*BA BLA*/
  201.    {
  202.       WriteProcessMemory(sys_process_getpid(), (void*)currentStubPos, &instructionOpcode, sizeof(instructionOpcode));
  203.       stubIndex += POWERPC_INSTRUCTION_LENGTH;
  204.    }
  205.    else
  206.    {
  207.       intptr_t branchOffset = instructionOpcode & 0x03FFFFFC;
  208.  
  209.       if (branchOffset & (1 << 25)) // If The MSB Is Set Make It Negative
  210.          branchOffset |= ~0x03FFFFFF;
  211.  
  212.       intptr_t originalAddress = (intptr_t)(instructionAddress + branchOffset);
  213.  
  214.       Jump(currentStubPos, originalAddress, instructionOpcode & 1, preserveRegisters);
  215.  
  216.       size_t hookSize = preserveRegisters ? sizeof(jumpASMPreserve) : sizeof(jumpASMNoPreserve);
  217.  
  218.       stubIndex += hookSize;
  219.    }
  220. }
  221.  
  222. void DetourHook::RelocateBranchConditional(uint32_t instructionAddress, bool preserveRegisters)
  223. {
  224.    /*
  225.  
  226.    BC - Branch Conditional
  227.  
  228.    [Opcode]   [Branch Options]     [Condition Register]         [Address]      [Absolute] [Linked]
  229.    0-5            6-10                    11-15                   16-29            30        31
  230.  
  231.    Example
  232.    010000         00100                   00001              0000 0000 0000 01      0         0‬
  233.  
  234.    */
  235.  
  236.    uint32_t instructionOpcode = *(uint32_t*)instructionAddress;
  237.    uint32_t currentStubPos = (uint32_t)&stubAddress[stubIndex];
  238.  
  239.    if (instructionOpcode & 0x2) /*Conditional Absolute*/
  240.    {
  241.       WriteProcessMemory(sys_process_getpid(), (void*)currentStubPos, &instructionOpcode, sizeof(instructionOpcode));
  242.       stubIndex += POWERPC_INSTRUCTION_LENGTH;
  243.    }
  244.    else
  245.    {
  246.       uint32_t branchOptions = instructionOpcode & 0x03E00000;
  247.       uint32_t conditionRegister = instructionOpcode & 0x001F0000;
  248.  
  249.       intptr_t branchOffset = instructionOpcode & 0x0000FFFC;
  250.  
  251.       if (branchOffset & (1 << 15)) // If The MSB Is Set Make It Negative
  252.          branchOffset |= ~0x0000FFFF;
  253.  
  254.       intptr_t originalAddress = (intptr_t)(instructionAddress + branchOffset);
  255.  
  256.       JumpWithOptions(currentStubPos, originalAddress, POWERPC_BRANCH_OPTION_GET(branchOptions), POWERPC_CONDITION_REGISTER_GET(conditionRegister), instructionOpcode & 1, preserveRegisters);
  257.  
  258.       size_t hookSize = preserveRegisters ? sizeof(jumpASMPreserve) : sizeof(jumpASMNoPreserve);
  259.  
  260.       stubIndex += hookSize;
  261.    }
  262. }
  263.  
  264. void DetourHook::RelocateCode(uint32_t instructionAddress, bool preserveRegisters)
  265. {
  266.    uint32_t instructionOpcode = *(uint32_t*)instructionAddress;
  267.    uint32_t currentStubPos = (uint32_t)&stubAddress[stubIndex];
  268.  
  269.    switch (instructionOpcode & 0xFC000000)
  270.    {
  271.    case POWERPC_BRANCH: /*B BL BA BLA*/
  272.       RelocateBranch(instructionAddress, preserveRegisters);
  273.       break;
  274.  
  275.    case POWERPC_BRANCH_CONDITIONAL: /*BEQ BNE BLT BGE */
  276.       RelocateBranchConditional(instructionAddress, preserveRegisters);
  277.       break;
  278.  
  279.    default:
  280.       WriteProcessMemory(sys_process_getpid(), (void*)currentStubPos, &instructionOpcode, sizeof(instructionOpcode));
  281.       stubIndex += POWERPC_INSTRUCTION_LENGTH;
  282.       break;
  283.    }
  284. }
  285.  
  286. void DetourHook::JumpWithOptions(uint32_t fnAddress, uintptr_t fnCallback, uint32_t branchOptions, uint32_t conditionRegister, bool linked, bool preserveRegisters)
  287. {
  288.    branchOptions &= 0x1F; // Options only takes 5 bits
  289.    conditionRegister &= 0x1F;
  290.  
  291.    if (preserveRegisters)
  292.    {
  293.       uint32_t instructions[ARRAYSIZE(jumpASMPreserve)];
  294.  
  295.       WriteProcessMemory(sys_process_getpid(), instructions, jumpASMPreserve, sizeof(jumpASMPreserve));
  296.  
  297.       instructions[1] |= ADDRESS_HIGHER(fnCallback);
  298.       instructions[2] |= ADDRESS_LOWER(fnCallback);
  299.       instructions[5] |= POWERPC_BRANCH_OPTION_SET(branchOptions) | POWERPC_CONDITION_REGISTER_SET(conditionRegister) | (uint32_t)linked;
  300.  
  301.       WriteProcessMemory(sys_process_getpid(), (void*)originalInstructions, (void*)fnAddress, sizeof(jumpASMPreserve));
  302.       WriteProcessMemory(sys_process_getpid(), (void*)fnAddress, instructions, sizeof(instructions));
  303.  
  304.       originalLength = sizeof(jumpASMPreserve);
  305.    }
  306.    else
  307.    {
  308.       uint32_t instructions[ARRAYSIZE(jumpASMNoPreserve)];
  309.  
  310.       WriteProcessMemory(sys_process_getpid(), instructions, jumpASMNoPreserve, sizeof(jumpASMNoPreserve));
  311.  
  312.       instructions[0] |= ADDRESS_HIGHER(fnCallback);
  313.       instructions[1] |= ADDRESS_LOWER(fnCallback);
  314.       instructions[3] |= POWERPC_BRANCH_OPTION_SET(branchOptions) | POWERPC_CONDITION_REGISTER_SET(conditionRegister) | (uint32_t)linked;
  315.  
  316.       WriteProcessMemory(sys_process_getpid(), (void*)originalInstructions, (void*)fnAddress, sizeof(jumpASMNoPreserve));
  317.       WriteProcessMemory(sys_process_getpid(), (void*)fnAddress, instructions, sizeof(instructions));
  318.  
  319.       originalLength = sizeof(jumpASMNoPreserve);
  320.    }
  321.  
  322.    hookAddress = fnAddress;
  323. }
  324.  
  325. void DetourHook::Jump(uint32_t fnAddress, uintptr_t fnCallback, bool linked, bool preserveRegisters)
  326. {
  327.    JumpWithOptions(fnAddress, fnCallback, 20, 0, linked, preserveRegisters);
  328. }
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336. ImportExportHook::ImportExportHook(HookType type, const std::string& libaryName,
  337.    uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters)
  338.    : /*DetourHook(0x00000000, fnCallback, preserveRegisters, tocOverride), */libaryName(libaryName), fnid(fnid)
  339. {
  340.    HookByFnid(type, libaryName, fnid, fnCallback, preserveRegisters);
  341. }
  342.  
  343. ImportExportHook::~ImportExportHook()
  344. {
  345.    UnHook();
  346. }
  347.  
  348. void* ImportExportHook::Hook(uint32_t fnAddress, uintptr_t fnCallback, bool preserveRegisters, uint32_t tocOverride)
  349. {
  350.    // not implemented
  351.    return nullptr;
  352. }
  353.  
  354. void ImportExportHook::UnHook()
  355. {
  356.    // not implemented
  357. }
  358.  
  359. void* ImportExportHook::HookByFnid(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback, bool preserveRegisters)
  360. {
  361.    opd_s* fnOpd = nullptr;
  362.  
  363.    switch (type)
  364.    {
  365.       case HookType::Import:
  366.       {
  367.          fnOpd = FindImportByName(libaryName.c_str(), fnid);
  368.          break;
  369.       }
  370.       case HookType::Export:
  371.       {
  372.          fnOpd = FindExportByName(libaryName.c_str(), fnid);
  373.          break;
  374.       }
  375.    }
  376.  
  377.    if (fnOpd == nullptr)
  378.       return nullptr;
  379.  
  380.    return DetourHook::Hook(fnOpd->sub, fnCallback, preserveRegisters, fnOpd->toc);
  381. }
  382.  
  383. opd_s* ImportExportHook::FindExportByName(const char* module, std::uint32_t fnid)
  384. {
  385.    uint32_t* sysProcessPrxInfo = *reinterpret_cast<uint32_t**>(0x101DC); // 0x101DC or 0x101E4
  386.    uint32_t exportAdressTable = sysProcessPrxInfo[4];
  387.    exportStub_s* exportStub = reinterpret_cast<exportStub_s*>(exportAdressTable);
  388.  
  389.    while (exportStub->ssize == 0x1C00)
  390.    {
  391.       if (!strcmp(module, exportStub->name))
  392.       {
  393.          for (int16_t i = 0; i < exportStub->exports; i++)
  394.          {
  395.             if (exportStub->fnid[i] == fnid)
  396.             {
  397.                return exportStub->stub[i];
  398.             }
  399.          }
  400.       }
  401.       exportStub++;
  402.    }
  403.  
  404.    return nullptr;
  405. }
  406.  
  407. opd_s* ImportExportHook::FindImportByName(const char* module, uint32_t fnid)
  408. {
  409.    uint32_t* sysProcessPrxInfo = *reinterpret_cast<uint32_t**>(0x101DC); // 0x101DC or 0x101E4
  410.    uint32_t importAdressTable = sysProcessPrxInfo[6];
  411.    importStub_s* importStub = reinterpret_cast<importStub_s*>(importAdressTable);
  412.    while (importStub->ssize == 0x2C00)
  413.    {
  414.       if (!strcmp(module, importStub->name))
  415.       {
  416.          for (int16_t i = 0; i < importStub->imports; i++)
  417.          {
  418.             if (importStub->fnid[i] == fnid)
  419.             {
  420.                return importStub->stub[i];
  421.             }
  422.          }
  423.       }
  424.       importStub++;
  425.    }
  426.  
  427.    return nullptr;
  428. }
  429.  
  430.  
  431.  
  432.  
  433. struct opd_s
  434. {
  435.    uint32_t sub;
  436.    uint32_t toc;
  437. };
  438.  
  439. struct importStub_s
  440. {
  441.    int16_t ssize;
  442.    int16_t header1;
  443.    int16_t header2;
  444.    int16_t imports;
  445.    int32_t zero1;
  446.    int32_t zero2;
  447.    const char* name;
  448.    uint32_t* fnid;
  449.    opd_s** stub;
  450.    int32_t zero3;
  451.    int32_t zero4;
  452.    int32_t zero5;
  453.    int32_t zero6;
  454. };
  455.  
  456. struct exportStub_s
  457. {
  458.    int16_t ssize;
  459.    int16_t header1;
  460.    int16_t header2;
  461.    int16_t exports; // number of exports
  462.    int32_t zero1;
  463.    int32_t zero2;
  464.    const char* name;
  465.    uint32_t* fnid;
  466.    opd_s** stub;
  467. };
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487. EXAMPLES
  488.  
  489. // hook any function using detour class
  490. DetourHook* StatSetIntHk;
  491. uint32_t StatSetIntHook(uint32_t statHash, uint32_t value, uint32_t save)
  492. {
  493.    printf("StatSetIntHook\n");
  494.    printf("statHash 0x%X\n", statHash);
  495.  
  496.    return StatSetIntHk->GetOriginal<uint32_t>(statHash, value, save);
  497. }
  498.  
  499. https://imgur.com/rdBtu09
  500. StatSetIntHk = new DetourHook(0x42BE0C, (uintptr_t)StatSetIntHook);
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508. ImportExportHook* sysPpuThreadCreateHk;
  509. int sysPpuThreadCreateHook(sys_ppu_thread_t* thread_id, void(*entry)(uint64_t),
  510.    uint64_t arg, int prio, size_t stacksize, uint64_t flags, const char* threadname)
  511. {
  512.    printf("sysPpuThreadCreateHook\n");
  513.    printf("thread_id: 0x%016llX\n", thread_id);
  514.    printf("entry: 0x%016llX\n", entry);
  515.    printf("arg: 0x%016llX\n", arg);
  516.    printf("prio: 0x%X\n", prio);
  517.    printf("stacksize: 0x%X\n", stacksize);
  518.    printf("flags: 0x%016llX\n", flags);
  519.    printf("threadname: %s\n", threadname);
  520.  
  521.  
  522.    return sysPpuThreadCreateHk->GetOriginal<int>(thread_id, entry, arg, prio, stacksize, flags, threadname);
  523. }
  524.  
  525. sysPpuThreadCreateHk = new ImportExportHook(ImportExportHook::Import, "sysPrxForUser", 0x24A1EA07, (uintptr_t)sysPpuThreadCreateHook);
  526.  
  527.  
  528.  
  529.  
  530. ImportExportHook* cellFsOpenHk;
  531. CellFsErrno cellFsOpenHook(const char* path, int flags, int* fd, const void* arg, uint64_t size)
  532. {
  533.    printf("cellFsOpenHook\n");
  534.    printf("path: %s\n", path);
  535.    printf("flags: 0x%X\n", flags);
  536.    printf("fd: 0x%X\n", fd);
  537.    printf("arg: 0x%X\n", arg);
  538.    printf("size: 0x%X\n", size);
  539.  
  540.    if (strcmp(path, "/dev_hdd0/game/BLES01807/USRDIR/dlc/dlc_mpPilot/DLC.edat") == 0)
  541.    {
  542.       path = "/dev_hdd0/tmp/Semjases/Mods/dlc/dlc_mpPilot/DLC.edat";
  543.    }
  544.  
  545.    return cellFsOpenHk->GetOriginal<CellFsErrno>(path, flags, fd, arg, size);
  546. }
  547.  
  548. cellFsOpenHk = new ImportExportHook(ImportExportHook::Import, "sys_fs", 0x718BF5F8, (uintptr_t)cellFsOpenHook);
  549.  
  550.  
  551.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement