Skip to content

Instantly share code, notes, and snippets.

@TheRouletteBoi
Last active September 26, 2024 23:13
Show Gist options
  • Save TheRouletteBoi/e1e9925699ee8d708881e167e397058b to your computer and use it in GitHub Desktop.
Save TheRouletteBoi/e1e9925699ee8d708881e167e397058b to your computer and use it in GitHub Desktop.
Hooking any function including imports and exports. PowerPC, PPC, PS3, Playstation 3
#include "DetourHook.hpp"
#define POWERPC_REGISTERINDEX_R0 0
#define POWERPC_REGISTERINDEX_R1 1
#define POWERPC_REGISTERINDEX_R2 2
#define POWERPC_REGISTERINDEX_R3 3
#define POWERPC_REGISTERINDEX_R4 4
#define POWERPC_REGISTERINDEX_R5 5
#define POWERPC_REGISTERINDEX_R6 6
#define POWERPC_REGISTERINDEX_R7 7
#define POWERPC_REGISTERINDEX_R8 8
#define POWERPC_REGISTERINDEX_R9 9
#define POWERPC_REGISTERINDEX_R10 10
#define POWERPC_REGISTERINDEX_R11 11
#define POWERPC_REGISTERINDEX_R12 12
#define POWERPC_REGISTERINDEX_R13 13
#define POWERPC_REGISTERINDEX_R14 14
#define POWERPC_REGISTERINDEX_R15 15
#define POWERPC_REGISTERINDEX_R16 16
#define POWERPC_REGISTERINDEX_R17 17
#define POWERPC_REGISTERINDEX_R18 18
#define POWERPC_REGISTERINDEX_R19 19
#define POWERPC_REGISTERINDEX_R20 20
#define POWERPC_REGISTERINDEX_R21 21
#define POWERPC_REGISTERINDEX_R22 22
#define POWERPC_REGISTERINDEX_R23 23
#define POWERPC_REGISTERINDEX_R24 24
#define POWERPC_REGISTERINDEX_R25 25
#define POWERPC_REGISTERINDEX_R26 26
#define POWERPC_REGISTERINDEX_R27 27
#define POWERPC_REGISTERINDEX_R28 28
#define POWERPC_REGISTERINDEX_R29 29
#define POWERPC_REGISTERINDEX_R30 30
#define POWERPC_REGISTERINDEX_R31 31
#define POWERPC_REGISTERINDEX_SP 1
#define POWERPC_REGISTERINDEX_RTOC 2
#define MASK_N_BITS(N) ( ( 1 << ( N ) ) - 1 )
#define POWERPC_HI(X) ( ( X >> 16 ) & 0xFFFF )
#define POWERPC_LO(X) ( X & 0xFFFF )
// PowerPC most significant bit is addressed as bit 0 in documentation.
#define POWERPC_BIT32(N) ( 31 - N )
// Opcode is bits 0-5.
// Allowing for op codes ranging from 0-63.
#define POWERPC_OPCODE(OP) (uint32_t)( OP << 26 )
#define POWERPC_OPCODE_ADDI POWERPC_OPCODE( 14 )
#define POWERPC_OPCODE_ADDIS POWERPC_OPCODE( 15 )
#define POWERPC_OPCODE_BC POWERPC_OPCODE( 16 )
#define POWERPC_OPCODE_B POWERPC_OPCODE( 18 )
#define POWERPC_OPCODE_BCCTR POWERPC_OPCODE( 19 )
#define POWERPC_OPCODE_ORI POWERPC_OPCODE( 24 )
#define POWERPC_OPCODE_EXTENDED POWERPC_OPCODE( 31 ) // Use extended opcodes.
#define POWERPC_OPCODE_STW POWERPC_OPCODE( 36 )
#define POWERPC_OPCODE_LWZ POWERPC_OPCODE( 32 )
#define POWERPC_OPCODE_LD POWERPC_OPCODE( 58 )
#define POWERPC_OPCODE_STD POWERPC_OPCODE( 62 )
#define POWERPC_OPCODE_MASK POWERPC_OPCODE( 63 )
#define POWERPC_EXOPCODE(OP) ( OP << 1 )
#define POWERPC_EXOPCODE_BCCTR POWERPC_EXOPCODE( 528 )
#define POWERPC_EXOPCODE_MTSPR POWERPC_EXOPCODE( 467 )
// SPR field is encoded as two 5 bit bitfields.
#define POWERPC_SPR(SPR) (uint32_t)( ( ( SPR & 0x1F ) << 5 ) | ( ( SPR >> 5 ) & 0x1F ) )
// Instruction helpers.
// rD - Destination register.
// rS - Source register.
// rA/rB - Register inputs.
// SPR - Special purpose register.
// UIMM/SIMM - Unsigned/signed immediate.
#define POWERPC_ADDI(rD, rA, SIMM) (uint32_t)( POWERPC_OPCODE_ADDI | ( rD << POWERPC_BIT32( 10 ) ) | ( rA << POWERPC_BIT32( 15 ) ) | SIMM )
#define POWERPC_ADDIS(rD, rA, SIMM) (uint32_t)( POWERPC_OPCODE_ADDIS | ( rD << POWERPC_BIT32( 10 ) ) | ( rA << POWERPC_BIT32( 15 ) ) | SIMM )
#define POWERPC_LIS(rD, SIMM) POWERPC_ADDIS( rD, 0, SIMM ) // Mnemonic for addis %rD, 0, SIMM
#define POWERPC_LI(rD, SIMM) POWERPC_ADDI( rD, 0, SIMM ) // Mnemonic for addi %rD, 0, SIMM
#define POWERPC_MTSPR(SPR, rS) (uint32_t)( POWERPC_OPCODE_EXTENDED | ( rS << POWERPC_BIT32( 10 ) ) | ( POWERPC_SPR( SPR ) << POWERPC_BIT32( 20 ) ) | POWERPC_EXOPCODE_MTSPR )
#define POWERPC_MTCTR(rS) POWERPC_MTSPR( 9, rS ) // Mnemonic for mtspr 9, rS
#define POWERPC_ORI(rS, rA, UIMM) (uint32_t)( POWERPC_OPCODE_ORI | ( rS << POWERPC_BIT32( 10 ) ) | ( rA << POWERPC_BIT32( 15 ) ) | UIMM )
#define POWERPC_BCCTR(BO, BI, LK) (uint32_t)( POWERPC_OPCODE_BCCTR | ( BO << POWERPC_BIT32( 10 ) ) | ( BI << POWERPC_BIT32( 15 ) ) | ( LK & 1 ) | POWERPC_EXOPCODE_BCCTR )
#define POWERPC_STD(rS, DS, rA) (uint32_t)( POWERPC_OPCODE_STD | ( rS << POWERPC_BIT32( 10 ) ) | ( rA << POWERPC_BIT32( 15 ) ) | ( (int16_t)DS & 0xFFFF ) )
#define POWERPC_LD(rS, DS, rA) (uint32_t)( POWERPC_OPCODE_LD | ( rS << POWERPC_BIT32( 10 ) ) | ( rA << POWERPC_BIT32( 15 ) ) | ( (int16_t)DS & 0xFFFF ) )
// Branch related fields.
#define POWERPC_BRANCH_LINKED 1
#define POWERPC_BRANCH_ABSOLUTE 2
#define POWERPC_BRANCH_TYPE_MASK ( POWERPC_BRANCH_LINKED | POWERPC_BRANCH_ABSOLUTE )
#define POWERPC_BRANCH_OPTIONS_ALWAYS ( 20 )
uint8_t DetourHook::s_TrampolineBuffer[]{};
size_t DetourHook::s_TrampolineSize = 0;
DetourHook::DetourHook()
: m_HookTarget(nullptr), m_HookAddress(nullptr), m_TrampolineAddress(nullptr), m_OriginalLength(0)
{
memset(m_TrampolineOpd, 0, sizeof(m_TrampolineOpd));
memset(m_OriginalInstructions, 0, sizeof(m_OriginalInstructions));
}
DetourHook::DetourHook(uint32_t fnAddress, uintptr_t fnCallback)
: m_HookTarget(nullptr), m_HookAddress(nullptr), m_TrampolineAddress(nullptr), m_OriginalLength(0)
{
memset(m_TrampolineOpd, 0, sizeof(m_TrampolineOpd));
memset(m_OriginalInstructions, 0, sizeof(m_OriginalInstructions));
Hook(fnAddress, fnCallback);
}
DetourHook::~DetourHook()
{
UnHook();
}
size_t DetourHook::GetHookSize(const void* branchTarget, bool linked, bool preserveRegister)
{
return JumpWithOptions(nullptr, branchTarget, linked, preserveRegister, POWERPC_BRANCH_OPTIONS_ALWAYS, 0, POWERPC_REGISTERINDEX_R0);
}
size_t DetourHook::Jump(void* destination, const void* branchTarget, bool linked, bool preserveRegister)
{
return JumpWithOptions(destination, branchTarget, linked, preserveRegister, POWERPC_BRANCH_OPTIONS_ALWAYS, 0, POWERPC_REGISTERINDEX_R0);
}
size_t DetourHook::JumpWithOptions(void* destination, const void* branchTarget, bool linked, bool preserveRegister, uint32_t branchOptions, uint8_t conditionRegisterBit, uint8_t registerIndex)
{
uint32_t BranchFarAsm[] = {
POWERPC_LIS(registerIndex, POWERPC_HI((uint32_t)branchTarget)), // lis %rX, branchTarget@hi
POWERPC_ORI(registerIndex, registerIndex, POWERPC_LO((uint32_t)branchTarget)), // ori %rX, %rX, branchTarget@lo
POWERPC_MTCTR(registerIndex), // mtctr %rX
POWERPC_BCCTR(branchOptions, conditionRegisterBit, linked) // bcctr (bcctr 20, 0 == bctr)
};
uint32_t BranchFarAsmPreserve[] = {
POWERPC_STD(registerIndex, -0x30, POWERPC_REGISTERINDEX_R1), // std %rX, -0x30(%r1)
POWERPC_LIS(registerIndex, POWERPC_HI((uint32_t)branchTarget)), // lis %rX, branchTarget@hi
POWERPC_ORI(registerIndex, registerIndex, POWERPC_LO((uint32_t)branchTarget)), // ori %rX, %rX, branchTarget@lo
POWERPC_MTCTR(registerIndex), // mtctr %rX
POWERPC_LD(registerIndex, -0x30, POWERPC_REGISTERINDEX_R1), // ld %rX, -0x30(%r1)
POWERPC_BCCTR(branchOptions, conditionRegisterBit, linked) // bcctr (bcctr 20, 0 == bctr)
};
uint32_t* BranchAsm = preserveRegister ? BranchFarAsmPreserve : BranchFarAsm;
size_t BranchAsmSize = preserveRegister ? sizeof(BranchFarAsmPreserve) : sizeof(BranchFarAsm);
if (destination)
WriteProcessMemory(sys_process_getpid(), destination, BranchAsm, BranchAsmSize);
return BranchAsmSize;
}
size_t DetourHook::RelocateBranch(uint32_t* destination, uint32_t* source)
{
uint32_t Instruction = *source;
uint32_t InstructionAddress = (uint32_t)source;
// Absolute branches dont need to be handled.
if (Instruction & POWERPC_BRANCH_ABSOLUTE)
{
WriteProcessMemory(sys_process_getpid(), destination, &Instruction, sizeof(Instruction));
return sizeof(Instruction);
}
int32_t BranchOffsetBitSize = 0;
int32_t BranchOffsetBitBase = 0;
uint32_t BranchOptions = 0;
uint8_t ConditionRegisterBit = 0;
switch (Instruction & POWERPC_OPCODE_MASK)
{
// B - Branch
// [Opcode] [Address] [Absolute] [Linked]
// 0-5 6-29 30 31
//
// Example
// 010010 0000 0000 0000 0000 0000 0001 0 0
case POWERPC_OPCODE_B:
BranchOffsetBitSize = 24;
BranchOffsetBitBase = 2;
BranchOptions = POWERPC_BRANCH_OPTIONS_ALWAYS;
ConditionRegisterBit = 0;
break;
// 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 00 0000 0000 0001 0 0
case POWERPC_OPCODE_BC:
BranchOffsetBitSize = 14;
BranchOffsetBitBase = 2;
BranchOptions = (Instruction >> POWERPC_BIT32(10)) & MASK_N_BITS(5);
ConditionRegisterBit = (Instruction >> POWERPC_BIT32(15)) & MASK_N_BITS(5);
break;
}
// Even though the address part of the instruction begins from bit 29 in the case of bc and b.
// The value of the first bit is 4 as all addresses are aligned to for 4 for code therefore,
// the branch offset can be caluclated by anding in place and removing any suffix bits such as the
// link register or absolute flags.
int32_t BranchOffset = Instruction & (MASK_N_BITS(BranchOffsetBitSize) << BranchOffsetBitBase);
// Check if the MSB of the offset is set.
if (BranchOffset >> ((BranchOffsetBitSize + BranchOffsetBitBase) - 1))
{
// Add the nessasary bits to our integer to make it negative.
BranchOffset |= ~MASK_N_BITS(BranchOffsetBitSize + BranchOffsetBitBase);
}
void* BranchAddress = reinterpret_cast<void*>(InstructionAddress + BranchOffset);
return JumpWithOptions(destination, BranchAddress, Instruction & POWERPC_BRANCH_LINKED, true, BranchOptions, ConditionRegisterBit, POWERPC_REGISTERINDEX_R0);
}
size_t DetourHook::RelocateCode(uint32_t* destination, uint32_t* source)
{
uint32_t Instruction = *source;
switch (Instruction & POWERPC_OPCODE_MASK)
{
case POWERPC_OPCODE_B: // B BL BA BLA
case POWERPC_OPCODE_BC: // BEQ BNE BLT BGE
return RelocateBranch(destination, source);
default:
WriteProcessMemory(sys_process_getpid(), destination, &Instruction, sizeof(Instruction));
return sizeof(Instruction);
}
}
void DetourHook::Hook(uintptr_t fnAddress, uintptr_t fnCallback, uintptr_t tocOverride)
{
m_HookAddress = reinterpret_cast<void*>(fnAddress);
m_HookTarget = reinterpret_cast<void*>(*reinterpret_cast<uintptr_t*>(fnCallback));
// Get the size of the hook but don't hook anything yet
size_t HookSize = GetHookSize(m_HookTarget, false, false);
// Save the original instructions for unhooking later on.
WriteProcessMemory(sys_process_getpid(), m_OriginalInstructions, m_HookAddress, HookSize);
m_OriginalLength = HookSize;
// Create trampoline and copy and fix instructions to the trampoline.
m_TrampolineAddress = &s_TrampolineBuffer[s_TrampolineSize];
for (size_t i = 0; i < (HookSize / sizeof(uint32_t)); i++)
{
uint32_t* InstructionAddress = reinterpret_cast<uint32_t*>((uint32_t)m_HookAddress + (i * sizeof(uint32_t)));
s_TrampolineSize += RelocateCode((uint32_t*)&s_TrampolineBuffer[s_TrampolineSize], InstructionAddress);
}
// Trampoline branches back to the original function after the branch we used to hook.
void* AfterBranchAddress = reinterpret_cast<void*>((uint32_t)m_HookAddress + HookSize);
s_TrampolineSize += Jump(&s_TrampolineBuffer[s_TrampolineSize], AfterBranchAddress, false, true);
// Finally write the branch to the function that we are hooking.
Jump(m_HookAddress, m_HookTarget, false, false);
m_TrampolineOpd[0] = reinterpret_cast<uint32_t>(m_TrampolineAddress);
m_TrampolineOpd[1] = tocOverride != 0 ? tocOverride : GetCurrentToc();
}
bool DetourHook::UnHook()
{
if (m_HookAddress && m_OriginalLength)
{
WriteProcessMemory(sys_process_getpid(), m_HookAddress, m_OriginalInstructions, m_OriginalLength);
m_OriginalLength = 0;
m_HookAddress = nullptr;
return true;
}
return false;
}
ImportExportHook::ImportExportHook(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback)
: DetourHook(), m_LibaryName(libaryName), m_Fnid(fnid)
{
HookByFnid(type, libaryName, fnid, fnCallback);
}
ImportExportHook::~ImportExportHook()
{
UnHook();
}
void ImportExportHook::Hook(uintptr_t fnAddress, uintptr_t fnCallback, uintptr_t tocOverride)
{
// not implemented
}
bool ImportExportHook::UnHook()
{
// not implemented
return false;
}
void ImportExportHook::HookByFnid(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback)
{
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;
DetourHook::Hook(fnOpd->func, fnCallback, fnOpd->toc);
}
opd_s* ImportExportHook::FindExportByName(const char* module, uint32_t fnid)
{
#ifdef VSH_PROC
uint32_t* segment15 = *reinterpret_cast<uint32_t**>(0x1008C); // 0x1008C or 0x10094
uint32_t exportAdressTable = segment15[0x984 / sizeof(uint32_t)];
exportStub_s* exportStub = reinterpret_cast<exportStub_s*>(exportAdressTable);
#else
uint32_t* sysProcessPrxInfo = *reinterpret_cast<uint32_t**>(0x101DC); // 0x101DC or 0x101E4
uint32_t exportAdressTable = sysProcessPrxInfo[4];
exportStub_s* exportStub = reinterpret_cast<exportStub_s*>(exportAdressTable);
#endif
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)
{
#ifdef VSH_PROC
uint32_t* segment15 = *reinterpret_cast<uint32_t**>(0x1008C); // 0x1008C or 0x10094
uint32_t exportAdressTable = segment15[0x984 / sizeof(uint32_t)];
importStub_s* importStub = reinterpret_cast<importStub_s*>(exportAdressTable);
#else
uint32_t* sysProcessPrxInfo = *reinterpret_cast<uint32_t**>(0x101DC); // 0x101DC or 0x101E4
uint32_t importAdressTable = sysProcessPrxInfo[6];
importStub_s* importStub = reinterpret_cast<importStub_s*>(importAdressTable);
#endif
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;
}
/**
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>
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;
};
#define MARK_AS_EXECUTABLE __attribute__((section(".text")))
class DetourHook
{
public:
DetourHook();
DetourHook(uintptr_t fnAddress, uintptr_t fnCallback);
DetourHook(DetourHook const&) = delete;
DetourHook(DetourHook&&) = delete;
DetourHook& operator=(DetourHook const&) = delete;
DetourHook& operator=(DetourHook&&) = delete;
virtual ~DetourHook();
virtual void Hook(uintptr_t fnAddress, uintptr_t fnCallback, uintptr_t tocOverride = 0);
virtual bool UnHook();
// also works
/*template<typename T>
T GetOriginal() const
{
return T(m_TrampolineOpd);
}*/
template <typename R, typename... TArgs>
R GetOriginal(TArgs... args)
{
R(*original)(TArgs...) = (R(*)(TArgs...))m_TrampolineOpd;
return original(args...);
}
private:
/***
* Writes an unconditional branch to the destination address that will branch to the target address.
* @param destination Where the branch will be written to.
* @param branchTarget The address the branch will jump to.
* @param linked Branch is a call or a jump? aka bl or b
* @param preserveRegister Preserve the register clobbered after loading the branch address.
* @returns size of relocating the instruction in bytes
*/
size_t Jump(void* destination, const void* branchTarget, bool linked, bool preserveRegister);
/***
* Writes both conditional and unconditional branches using the count register to the destination address that will branch to the target address.
* @param destination Where the branch will be written to.
* @param branchTarget The address the branch will jump to.
* @param linked Branch is a call or a jump? aka bl or b
* @param preserveRegister Preserve the register clobbered after loading the branch address.
* @param branchOptions Options for determining when a branch to be followed.
* @param conditionRegisterBit The bit of the condition register to compare.
* @param registerIndex Register to use when loading the destination address into the count register.
* @returns size of relocating the instruction in bytes
*/
size_t JumpWithOptions(void* destination, const void* branchTarget, bool linked, bool preserveRegister,
uint32_t branchOptions, uint8_t conditionRegisterBit, uint8_t registerIndex);
/***
* Copies and fixes relative branch instructions to a new location.
* @param destination Where to write the new branch.
* @param source Address to the instruction that is being relocated.
* @returns size of relocating the instruction in bytes
*/
size_t RelocateBranch(uint32_t* destination, uint32_t* source);
/***
* Copies an instruction enusuring things such as PC relative offsets are fixed.
* @param destination Where to write the new instruction(s).
* @param source Address to the instruction that is being copied.
* @returns size of relocating the instruction in bytes
*/
size_t RelocateCode(uint32_t* destination, uint32_t* source);
/***
* Get's size of method hook in bytes
* @param branchTarget The address the branch will jump to.
* @param linked Branch is a call or a jump? aka bl or b
* @param preserveRegister Preserve the register clobbered after loading the branch address.
* @returns size of hook in bytes
*/
size_t GetHookSize(const void* branchTarget, bool linked, bool preserveRegister);
protected:
const void* m_HookTarget; // The funtion we are pointing the hook to.
void* m_HookAddress; // The function we are hooking.
uint8_t* m_TrampolineAddress; // Pointer to the trampoline for this detour.
uint32_t m_TrampolineOpd[2]; // opd_s of the trampoline for this detour.
uint8_t m_OriginalInstructions[30]; // Any bytes overwritten by the hook.
size_t m_OriginalLength; // The amount of bytes overwritten by the hook.
// Shared
MARK_AS_EXECUTABLE static uint8_t s_TrampolineBuffer[1024];
static size_t s_TrampolineSize;
};
// 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);
virtual ~ImportExportHook();
virtual void Hook(uintptr_t fnAddress, uintptr_t fnCallback, uintptr_t tocOverride = 0) override;
virtual bool UnHook() override;
static opd_s* FindExportByName(const char* module, uint32_t fnid);
static opd_s* FindImportByName(const char* module, uint32_t fnid);
private:
void HookByFnid(HookType type, const std::string& libaryName, uint32_t fnid, uintptr_t fnCallback);
private:
std::string m_LibaryName;
uint32_t m_Fnid;
};
#include "DetourHook.hpp"
// 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);
}
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);
}
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);
}
int main()
{
// https://imgur.com/rdBtu09
StatSetIntHk = new DetourHook(0x42BE0C, (uintptr_t)StatSetIntHook);
sysPpuThreadCreateHk = new ImportExportHook(ImportExportHook::Import, "sysPrxForUser", 0x24A1EA07, (uintptr_t)sysPpuThreadCreateHook);
cellFsOpenHk = new ImportExportHook(ImportExportHook::Import, "sys_fs", 0x718BF5F8, (uintptr_t)cellFsOpenHook);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment