And all the examples I've found till now in a lot of different sources, namely - PSPLink, RemoteJoy, Hookcore, etc. - weren't really up 2 date.
Nor did they offer the feature of hooking Usermode Functions to Kernel Functions, that I needed.
Below you will find Code Sections of all the important parts of my hooking code.
I figured out the NID for 5.0 Firmware sceKernelQuerySystemCall by comparing the decrypted modules of 3.0 firmware and 5.0 firmware btw. :P
hook.h
Code: Select all
#ifndef PSP_HOOK_H
#define PSP_HOOK_H
// Hook Modes
#define HOOK_SYSCALL 0
#define HOOK_JUMP 1
// Hook Function - returns 0 on success, < 0 on error.
int hookAPI(const char * module, const char * library, unsigned int nid, void * function, int mode, unsigned int * orig_loader);
#endif
Code: Select all
#include <stdio.h>
#include <psputilsforkernel.h>
#include <systemctrl.h>
#include "interruptman.h"
#include "hook.h"
#include "debug.h"
// MIPS Opcodes
#define MIPS_NOP 0x00000000
#define MIPS_SYSCALL(NUM) (((NUM)<<6)|12)
#define MIPS_J(ADDR) (0x08000000 + ((((unsigned int)(ADDR))&0x0ffffffc)>>2))
#define MIPS_STACK_SIZE(SIZE) (0x27BD0000 + (((unsigned int)(SIZE)) & 0x0000FFFF))
#define MIPS_PUSH_RA(STACKPOS) (0xAFBF0000 + (((unsigned int)(STACKPOS)) & 0x0000FFFF))
#define MIPS_POP_RA(STACKPOS) (0x8FBF0000 + (((unsigned int)(STACKPOS)) & 0x0000FFFF))
#define MIPS_RETURN 0x03E00008
int hookJump(const char * module, const char * library, unsigned int nid, void * function, unsigned int * orig_loader)
{
  // Hooking Result
  int result = 0;
  
  // Check Arguments
  if(module && library && function)
  {
    // Find Function
    unsigned int * sfunc = (unsigned int*)sctrlHENFindFunction(module, library, nid);
    
    // Found Function
    if(sfunc)
    {
      // Backup Interrupts
      int interrupt = pspSdkDisableInterrupts();
      
      // Create Original Loader
      if(orig_loader)
      {
        // Backup Original Instructions
        orig_loader[0] = sfunc[0];
        orig_loader[1] = sfunc[1];
        orig_loader[2] = sfunc[2];
        orig_loader[3] = sfunc[3];
        orig_loader[4] = sfunc[4];
        orig_loader[5] = sfunc[5];
        orig_loader[6] = sfunc[6];
        orig_loader[7] = sfunc[7];
        
        // Jump Delay Slot (Just to be on the safe side...)
        orig_loader[8] = MIPS_NOP;
        
        // Jump to Original Code
        orig_loader[9] = MIPS_J(&sfunc[8]);
        
        // Jump Delay Slot
        orig_loader[10] = MIPS_NOP;
      }
      
      // Patch Function with Jump
      sfunc[0] = MIPS_STACK_SIZE(-4); // Allocate 4 Bytes on Stack
      sfunc[1] = MIPS_PUSH_RA(0); // Backup RA on Stack
      sfunc[2] = MIPS_SYSCALL(sceKernelQuerySystemCall(function)); // Syscall to our Hook
      sfunc[3] = MIPS_NOP; // Delay Slot
      sfunc[4] = MIPS_POP_RA(0); // Get RA from Stack
      sfunc[5] = MIPS_STACK_SIZE(4); // Free 4 Bytes on Stack
      sfunc[6] = MIPS_RETURN; // Return
      sfunc[7] = MIPS_NOP; // Delay Slot
      
      // Force Memory Mirroring
      sceKernelDcacheWritebackInvalidateRange(sfunc, sizeof(unsigned int) * 8);
      sceKernelIcacheInvalidateRange(sfunc, sizeof(unsigned int) * 8);
      
      // Enable Interrupts
      pspSdkEnableInterrupts(interrupt);
      
      // Hooking Debug Log
      char log[128];
      sprintf(log, "hookJump: Set Jump Hook on %08X to %08X (Module: %s, Library: %s, NID: %08X).\n", (unsigned int)sfunc, (unsigned int)function, module, library, nid);
      debuglog(log);
    }
    
    // Failed Finding Function
    else
    {
      // Result
      result = -5;
      
      // Log Error
      debuglog("hookJump: Couldn't find Function. NID might be incorrect.\n");
    }
  }
  
  // Invalid Arguments
  else
  {
    // Result
    result = -4;
    
    // Log Error
    debuglog("hookJump: Invalid Arguments.\n");
  }
  
  // Return Hooking Result
  return result;
}
int hookSyscall(const char * module, const char * library, unsigned int nid, void * function, unsigned int * orig_loader)
{
  // Hooking Result
  int result = 0;
  
  // Check Arguments
  if(module && library && function)
  {
    // Find Function
    unsigned int * sfunc = (unsigned int*)sctrlHENFindFunction(module, library, nid);
    
    // Found Function
    if(sfunc)
    {
      // Create Original Loader
      if(orig_loader)
      {
        // Jump to Original Code
        orig_loader[0] = MIPS_J(sfunc);
        
        // Jump Delay Slot
        orig_loader[1] = MIPS_NOP;
      }
      
      // Patch Syscall
      sctrlHENPatchSyscall((unsigned int)sfunc, function);
      
      // Hooking Debug Log
      char log[128];
      sprintf(log, "hookSyscall: Set Syscall Hook on %08X to %08X (Module: %s, Library: %s, NID: %08X).\n", (unsigned int)sfunc, (unsigned int)function, module, library, nid);
      debuglog(log);
    }
    
    // Failed Finding Function
    else
    {
      // Result
      result = -5;
      
      // Log Error
      debuglog("hookSyscall: Couldn't find Target Function. NID might be incorrect.\n");
    }
  }
  
  // Invalid Arguments
  else
  {
    // Result
    result = -4;
    
    // Log Error
    debuglog("hookSyscall: Invalid Arguments.\n");
  }
  
  // Return Hooking Result
  return result;
}
int hookAPI(const char * module, const char * library, unsigned int nid, void * function, int mode, unsigned int * orig_loader)
{
  // Hooking Result
  int result = 0;
  
  // Avoid Crash
  sceKernelDelayThread(10000);
  
  // Check Arguments
  if(module && library && function)
  {
    // Find Module in Memory
    SceModule * findmodule = (SceModule*)sceKernelFindModuleByName(module);
    
    // Found Module
    if(findmodule)
    {
      // Hook via Syscall
      if(mode == HOOK_SYSCALL) result = hookSyscall(module, library, nid, function, orig_loader);
      
      // Hook via Jump
      else if(mode == HOOK_JUMP) result = hookJump(module, library, nid, function, orig_loader);
      
      // Invalid Hook Mode
      else
      {
        // Result
        result = -3;
        
        // Log Error
        debuglog("hookAPI: Invalid Hook Mode.\n");
      }
    }
    
    // Couldn't Find Module
    else
    {
      // Result
      result = -2;
      
      // Log Error
      debuglog("hookAPI: Couldn't find Module. Might not be loaded yet.\n");
    }
  }
  
  // Invalid Arguments
  else
  {
    // Result
    result = -1;
    
    // Log Error
    debuglog("hookAPI: Invalid Arguments.\n");
  }
  
  // Avoid Crash
  sceKernelDelayThread(10000);
  
  // Return Hooking Result
  return result;
}
Code: Select all
#ifndef PSP_INTERRUPTMAN_H
#define PSP_INTERRUPTMAN_H
// Get Syscallnum from Function Address
int sceKernelQuerySystemCall(void * function);
#endif
Code: Select all
	.set noreorder
#include "pspstub.s"
	STUB_START "InterruptManagerForKernel",0x00090011,0x00010005
	STUB_FUNC  0xEB988556,sceKernelQuerySystemCall
	STUB_END
Code: Select all
#ifndef PSP_DEBUG_H
#define PSP_DEBUG_H
#include <string.h>
#define LOGFILE "ms0:/psphook.log"
// Debug Log
int debuglog(const char * string);
// Append Buffer to File
int appendBufferToFile(const char * path, void * buffer, int buflen);
#endif
Code: Select all
#include <pspiofilemgr.h>
#include "debug.h"
int debuglog(const char * string)
{
  // Append Data
  return appendBufferToFile(LOGFILE, (void*)string, strlen(string));
}
int appendBufferToFile(const char * path, void * buffer, int buflen)
{
  // Written Bytes
  int written = 0;
  
  // Open File for Appending
  SceUID file = sceIoOpen(path, PSP_O_APPEND | PSP_O_CREAT | PSP_O_WRONLY, 0777);
  
  // Opened File
  if(file >= 0)
  {
    // Write Buffer
    written = sceIoWrite(file, buffer, buflen);
    
    // Close File
    sceIoClose(file);
  }
  
  // Return Written Bytes
  return written;
}
1. Make sure you link your project against "-lpspsystemctrl_kernel" - else you will run into trouble with hooking, because my hooking code relies on the M33 SDK Functions.
2. Obviously - MAKE YOUR PROJECT A KERNEL ONE! :)
3. Export your Hook Replacement Functions, else hooking will fail. You've been warned. Any Export Mode should be fine, direct jumping or syscalling... as the hooking code will dynamically create a syscall one anyway...
4. Don't try and forward Kernel Memory Range Pointers in Usermode Real Functions... you know it will fail. :P
5. For hooking Usermode functions use the HOOK_JUMP flag.
6. For hooking Kernelmode functions use the HOOK_JUMP flag if you want ALL calls to jump into your function (both User & Kernel) or use the HOOK_SYSCALL flag if you only want User calls to jump into your function.
7. For Usermode Hooks, please make sure to use the pspSdkSetK1 functions to properly backup and restore K1 register... otherwise you will be very limited in what you can do inside your hooked function.
8. To keep up compatiblity with other PRX Modules that also hook stuff, please - by gods sake... use the HOOK_JUMP flag.
Unlike HOOK_SYSCALL, HOOK_JUMP is stackable...
Let's say someone hooks sceKernelThreadDelay (I know, really stupid but whatever...) and you want to hook it aswell...
HOOK_SYSCALL would overwrite the Syscall in the Syscalltable, and thus make the original function undetectable by you, making it impossible to hook.
HOOK_JUMP though... backups the original function instructions and writes your own... simple as that...
If someone uses HOOK_JUMP after another module already jumphooked the function, it will backup THEIR code, and write YOUR own...
So - it will build a chain...
First call would enter your function, you forward it to the "real function" you saved, which is the first hook from another module, which in turn forwards it to its own "real function" it saved... which is the real function.
Get what I mean? S-T-A-C-K-A-B-L-E.
So in theory, if everyone who wants to hook stuff used this code example of mine... every module could hook the same function without interfering with other modules.
Nice in theory isn't it? Hope that module developers will think about implementing my sample so we can make sure that as many modules as possible become compatible with each other.
9. As the Minimal PSPSDK Setup for Windows Operating Systems is getting more and more famous and spread on the Internet, you might run into problems with the Stubs File for sceKernelQuerySystemCall though, as MinGW doesn't know the difference between .s and .S files...
To fix this, edit your makefile with the following line.
Code: Select all
ASFLAGS = $(CFLAGS) -c -x assembler-with-cpp10. For those not knowing where to get the M33 SDK. Google for "4.01 M33 Download" - the 4.01 firmware package from Dark_Alex comes with the M33 SDK precompiled, just copy it into your PSPSDK include / lib folders.
11. This code is FAR from being sane! Whether a hook works or not pretty much depends on luck from what I can tell...
I discovered a few functions I found pretty much - unhookable - using this code.
To name some, sceNetAdhocctlInit & sceNetAdhocctlTerm aswell as sceIfhandleIoctl. The hook - technically - works, just execution doesn't... it won't even reach your function.
So... if your PSP crashes while using this code... do some trial and error and see if a hook's causing it to.
I suppose hooking User and Kernelmode functions all in one does come at its price...
12. Confirmed Unhookable Functions:
sceNetAdhocctlInit - Hook Error, will crash entering your hook.
sceNetAdhocctlTerm - Hook Error, will crash entering your hook.
sceNetAdhocMatchingInit - Hook Error, will crash entering your hook.
sceNetAdhocMatchingTerm - Hook Error, will crash entering your hook.
sceNetAdhocMatchingStart - Hooks fine, calling the "Real Function" inside your hook ALWAYS fails though... (Return Value != 0)
sceNetAdhocMatchingGetPoolMaxAlloc - Hook Error, will crash entering your hook.
sceNetIfhandleIoctl - Hook Error, will crash entering your hook.
Sidenote: I'm trying to figure out why this problems occur... I tested this Unhookable Functions with 1.0 Firmware Version Libraries from Ridge Racer EU UMD.
If you got a idea what part of my code could be causing this, please drop me a message.
How to use it~
Code: Select all
// Original Function Pointer
int (*RealFunction)(void) = NULL;
// Dynamic Original Function Call Buffer
int orig_call[11]; // Make it smaller than that and you die.
int FakeFunction(void)
{
  // Result
  int result = 0;
  
  // Capture Real Function Result
  result = RealFunction();
  
  // Get More POWAR!
  int k1 = pspSdkSetK1(0);
  
  // Do your shit here...
  
  // Give back POWAR!
  pspSdkSetK1(k1);
  
  // Return Result
  return result;
}
int main(int argc, char * argv[])
{
  // Result
  int result = 0;
  
  // Hook Stuff
  // ModuleName -> Module Name of the to-get-hooked Module.
  // LibraryName -> Library Name of the to-get-hooked Library.
  // 0x12345678 -> NID of the to-get-hooked Function
  // FakeFunction -> Your replacement function.
  // HOOK_JUMP -> Flag for hook mode, alternatively you can use HOOK_SYSCALL.
  // orig_call -> Pointer to an integer array to hold MIPS assembly for launching the original function.
  result = hookAPI("ModuleName", "LibraryName", 0x12345678, FakeFunction, HOOK_JUMP, orig_call);
  
  // Link Real Function Call
  RealFunction = (int(*)(void))orig_call;
  
  // Return Result
  return result;
}


