forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Easy Hooking Example - User & Kernel

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
Coldbird



Joined: 08 Feb 2007
Posts: 155

PostPosted: Tue Apr 14, 2009 9:39 am    Post subject: Easy Hooking Example - User & Kernel Reply with quote

First of, I'm posting this here because hooking has been bothering me for quite some time now.

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:
#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

hook.c
Code:
#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;
}

interruptman.h
Code:
#ifndef PSP_INTERRUPTMAN_H
#define PSP_INTERRUPTMAN_H

// Get Syscallnum from Function Address
int sceKernelQuerySystemCall(void * function);

#endif

InterruptManagerForKernel.S
Code:
   .set noreorder

#include "pspstub.s"

   STUB_START "InterruptManagerForKernel",0x00090011,0x00010005
   STUB_FUNC  0xEB988556,sceKernelQuerySystemCall
   STUB_END

debug.h
Code:
#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

debug.c
Code:
#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;
}

Things to keep in mind while using~

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:
ASFLAGS = $(CFLAGS) -c -x assembler-with-cpp


This practically forces all Stubs files to be handled like .S files. Not a nice workaround, but it works.

10. 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:
// 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;
}

_________________
Been gone for some time. Now I'm back. Someone mind getting me up-2-date?


Last edited by Coldbird on Fri Apr 17, 2009 6:33 am; edited 12 times in total
Back to top
View user's profile Send private message MSN Messenger
jean



Joined: 05 Jan 2008
Posts: 489

PostPosted: Tue Apr 14, 2009 6:16 pm    Post subject: Reply with quote

Very nice for those (like me!) too lazy to dig in sources and do error-and-retry tests a million times. Thanks for sharing.
Back to top
View user's profile Send private message
Coldbird



Joined: 08 Feb 2007
Posts: 155

PostPosted: Tue Apr 14, 2009 9:06 pm    Post subject: Reply with quote

jean wrote:
Very nice for those (like me!) too lazy to dig in sources and do error-and-retry tests a million times. Thanks for sharing.

I'm glad it's of use to you. Took me some time to figure and work out a proper solution to this problem.

Especially because all I could find in previous sources was this apihook function thing which totally didn't do what I wanted it to do.
_________________
Been gone for some time. Now I'm back. Someone mind getting me up-2-date?
Back to top
View user's profile Send private message MSN Messenger
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Thu Apr 16, 2009 12:34 am    Post subject: Reply with quote

Thanks a lot :)
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Coldbird



Joined: 08 Feb 2007
Posts: 155

PostPosted: Thu Apr 16, 2009 12:46 am    Post subject: Reply with quote

No problem. I'm still trying to figure out why some functions won't hook properly with HOOK_JUMP, like the three ones I mentioned in the warnings.

I disassembled the affected functions but couldn't find a reason why they aren't hooking properly.

If you guys figure out what might be causing those few selected functions to not hook, please drop me a message.

Edit found a bug in my code, please check out hook.c for the fixed code.
Edit 2 found a crash related to too fast repeative hooking, placed a few thread delays in the hooking function to avoid this.
Edit 3 found a bug in my code that MIGHT have caused a few of the "broken hooks". I didn't invalidate all the memory I modified for the hooks...
_________________
Been gone for some time. Now I'm back. Someone mind getting me up-2-date?
Back to top
View user's profile Send private message MSN Messenger
Smong



Joined: 04 Sep 2007
Posts: 82

PostPosted: Sat Apr 18, 2009 8:28 am    Post subject: Reply with quote

Are you still having trouble with this? You may want to try making your stack allocations a multiple of 16 bytes instead of just 4 bytes.
_________________
(+[__]%)
Back to top
View user's profile Send private message
Coldbird



Joined: 08 Feb 2007
Posts: 155

PostPosted: Sat Apr 18, 2009 8:20 pm    Post subject: Reply with quote

Well - yes I do.
Some of the functions Im hooking with this example code still deal me trouble.

Now that I think of it, I've never seen allocation of as small memory regions as 4 bytes in the asm code...

You think that could be it? I will try that later on today.
Thanks for the tip.
_________________
Been gone for some time. Now I'm back. Someone mind getting me up-2-date?
Back to top
View user's profile Send private message MSN Messenger
kralyk



Joined: 06 Apr 2008
Posts: 114
Location: Czech Republic, central EU

PostPosted: Tue Jun 30, 2009 12:24 pm    Post subject: Reply with quote

The problem seems to be in the syscall query.
When I substitute the MIPS_SYSCALL with just NOP, it's ok.
I mean, it's not ok, it doesn't work of course, but it doesn't crash
the psp so that should show that the problem is in the syscall...

dunno whats wrong with the syscall though, any ideas?
_________________
...sorry for my english...
Back to top
View user's profile Send private message
Torky



Joined: 30 Jul 2009
Posts: 1

PostPosted: Thu Jul 30, 2009 3:59 am    Post subject: Reply with quote

help please :)

the function seems to be hooked.

Quote:
hookJump: Set Jump Hook on 880F5848 to 8822E600 (Module: scePower_Service, Library: scePower_driver, NID: 69958B65).


but i never get the "test" line in the psphook.log file. whats wrong with my code?

Code:
#include <stdio.h>
#include <pspkernel.h>
#include <psputilsforkernel.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <string.h>
#include <pspdebug.h>
#include <pspsuspend.h>
#include <psppower.h>
#include <pspreg.h>
#include <psprtc.h>
#include <psputils.h>
#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include "hook.h"
#include "debug.h"

PSP_MODULE_INFO("test", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
// Original Function Pointer
int (*scePowerBatteryDisableUsbCharging)(void) = NULL;

// Dynamic Original Function Call Buffer
int orig_call[11]; // Make it smaller than that and you die.

int scePowerBatteryDisableUsbCharging_fake(void)
{
  // Result
  int result = 0;

      debuglog("test\n");
  result = scePowerBatteryDisableUsbCharging();

 
  // Return Result
  return result;
}

int module_start(SceSize args, void *argp)
{
  // Result
  int result = 0;
 
  result = hookAPI("scePower_Service", "scePower_driver", 0x69958B65, scePowerBatteryDisableUsbCharging_fake, HOOK_JUMP, orig_call);
 
  // Link Real Function Call
  scePowerBatteryDisableUsbCharging = (int(*)(void))orig_call;

  // Return Result
  return result;
}



Code:
TARGET = test
OBJS = test.o InterruptManagerForKernel.o debug.o hook.o exports.o
BUILD_PRX=1
PRX_EXPORTS=exports.exp
# Use the kernel's small inbuilt libc
USE_KERNEL_LIBC = 1
# Use only kernel libraries
USE_KERNEL_LIBS = 1

INCDIR =
CFLAGS = -O2 -G0
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

LIBDIR =

LIBS = -lpspsystemctrl_kernel

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build_prx.mak


Code:
PSP_BEGIN_EXPORTS

# These four lines are mandatory (although you can add other functions like module_stop)
# syslib is a psynonym for the single mandatory export.
PSP_EXPORT_START(syslib, 0, 0x8000)
PSP_EXPORT_FUNC_HASH(module_start)
PSP_EXPORT_END

PSP_EXPORT_START(MyLib, 0, 0x0001)
PSP_EXPORT_FUNC_HASH(scePowerBatteryDisableUsbCharging_fake)
PSP_EXPORT_END

PSP_END_EXPORTS
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group