| View previous topic :: View next topic |
| Author |
Message |
roby65
Joined: 01 Jun 2008 Posts: 55 Location: Mid Italy
|
Posted: Fri Mar 06, 2009 11:28 pm Post subject: Hooks? |
|
|
Can someone explain me how to hook a function?
i know on windows how hook works, is that similar to this or there are some differences? |
|
| Back to top |
|
 |
coolkehon
Joined: 20 Oct 2008 Posts: 355
|
Posted: Sat Mar 07, 2009 1:30 am Post subject: |
|
|
| i would like to add to this question what is a hook i keep seeing it everyonce in a while libconfig, SDL, etc and also how do i use / create a hook |
|
| Back to top |
|
 |
Pirata Nervo
Joined: 09 Oct 2007 Posts: 409
|
|
| Back to top |
|
 |
NoEffex
Joined: 27 Nov 2008 Posts: 108
|
Posted: Sat Mar 07, 2009 7:28 am Post subject: |
|
|
In the CFW systemctrl_kernel library(probably others too, but that's the one I know off the top of my head), you can hook syscalls like
int func_addr = sctrlHENFindFunction(modname, libname, nid);
sctrlHENPatchSyscall(func_addr, &function_name);
That's one of the easier ways to do it. _________________ Programming with:
Geany + Latest PSPSDK from svn |
|
| Back to top |
|
 |
Torch

Joined: 28 May 2008 Posts: 842
|
Posted: Sun Mar 08, 2009 12:46 am Post subject: |
|
|
For hooking user to kernel syscall functions the above method is used. This will not effect a call to the function from a kernel module, it only effects user mode to kernel syscalls.
For hooking kernel-kernel or user-user functions, you need to go the address of the function, and replace the first instructions to jump to the address of your hook function. Then in your hook function, you can either process the data, or jump back into the original function. |
|
| Back to top |
|
 |
Pirata Nervo
Joined: 09 Oct 2007 Posts: 409
|
Posted: Sun Mar 08, 2009 6:23 am Post subject: |
|
|
@Torch, is assembly the only way to do it? _________________
Upgrade your PSP |
|
| Back to top |
|
 |
Torch

Joined: 28 May 2008 Posts: 842
|
Posted: Sun Mar 08, 2009 6:25 am Post subject: |
|
|
| Pirata Nervo wrote: | | @Torch, is assembly the only way to do it? |
Yes. Because the user-user or kernel-kernel jumps are directly in code from one module to a function address in another module. The return address is stored in $ra register to go back to the original code which called it. |
|
| Back to top |
|
 |
slasher2661996
Joined: 22 Feb 2009 Posts: 91 Location: Melbourne Australia ZOMG
|
Posted: Sun Mar 08, 2009 8:38 am Post subject: |
|
|
| Torch could you post an example? |
|
| Back to top |
|
 |
Torch

Joined: 28 May 2008 Posts: 842
|
Posted: Sun Mar 08, 2009 4:38 pm Post subject: |
|
|
| Code: | #define JAL_OPCODE 0x0C000000
#define J_OPCODE 0x08000000
#define MAKE_JUMP(a, f) _sw(J_OPCODE | (((u32)(f) & 0x0ffffffc) >> 2), a);
#define MAKE_CALL(a, f) _sw(JAL_OPCODE | (((u32)(f) >> 2) & 0x03ffffff), a);
...
...
int orig_jump(int var1, int var2...)
{
asm("1st instruction from original function");
asm("2nd instruction from original function");
asm("j original_function_address+8"); //will return back to 'hooked' after original function is finished
asm("nop");
return 0; //should not reach here
}
int hooked(int var1, int var2...)
{
//do stuff
return orig_jump(var1, var2...) //calls original function
}
//To do the patch
MAKE_JUMP(address of original, hooked)
//you need to add a nop after the jump too
|
Last edited by Torch on Sun Mar 08, 2009 8:59 pm; edited 2 times in total |
|
| Back to top |
|
 |
Torch

Joined: 28 May 2008 Posts: 842
|
Posted: Sun Mar 08, 2009 8:54 pm Post subject: |
|
|
| There was a small error, I edited the post. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun Mar 08, 2009 10:34 pm Post subject: |
|
|
branch control instructions are : J, JAL, JR, JALR, Bxx, etc.
NOTE: if one of the first two instructions in the original function is a relative branch transfer, you'll have an issue because you need to recompute the target offset so you need a stub like it if insn2 is a relative branch instruction :
| Code: |
original_function_stub:
insn1
beq ..., 0f // insn2 modified (was beq ..., original_function_exit)
insn3
j original_function_fallback
nop
0: j original_function_exit // ok
nop
...
and
/* existing function to patch in a module */
original_function:
insn1 ----> J hooked_function
insn2 ----> nop
insn3
original_function_fallback: // = ((int)&original_function_1) + 3
...
|
examples of auto-generated stub functions :
| Code: |
original_function_1_stub:
insn1
j original_function_1_fallback
insn2
original_function_2_stub:
insn1 // insn1 is a branch control instruction
insn2 // only insn2 can fit a branch delay slot here
j original_function_2_fallback
nop
original_function_3_stub:
insn1
insn2 // insn2 is a branch control instruction
nop // necessary because the next J cannot fit a branch delay slot
j original_function_3_fallback
nop
...
|
examples of patched functions :
| Code: |
/* existing function 1 to patch in a module */
original_function_1:
insn1 ----> J hooked_function_1
insn2 ----> nop
original_function_1_fallback: // = ((int)&original_function_1) + 2
...
/* existing function 2 to patch in a module */
original_function_2:
insn1 ----> J hooked_function_2
insn2 ----> nop
original_function_2_fallback: // = ((int)&original_function_2) + 2
...
/* existing function 3 to patch in a module */
original_function_3:
insn1 ----> J hooked_function_3
insn2 ----> nop
original_function_3_fallback: // = ((int)&original_function_3) + 2
...
|
your hooked functions :
| Code: |
... hooked_function_1(...)
{
... your code ...
... original_function_1_stub(...);
[... your code ...]
}
... hooked_function_2(...)
{
... your code ...
... original_function_2_stub(...);
[... your code ...]
}
... hooked_function_3(...)
{
... your code ...
... original_function_3_stub(...);
[... your code ...]
}
...
|
Here is an example of an untested function to do all the stuff :
| Code: |
void *patch_jump(int *original, int *hooked, int *stub)
{
if (is_branch_control_instruction(original[0]))
{
if (is_relative_branch_control_instruction(original[0]))
{
stub[0] = (original[0]&0xFFFF0000)|4; // insn1 modified
stub[1] = original[1]; // insn2
MAKE_JUMP(&stub[2], (int)(original + 2)); // J original_function_fallback
stub[3] = 0; // nop
MAKE_JUMP(&stub[4], (int)(original + 0 + (original[0]&0xFFFF)));
stub[5] = 0; // nop
writeback_dcache_and_invalidate_icache_range(stub, stub + 6);
}
else
{
stub[0] = original[0]; // insn1
stub[1] = original[1]; // insn2
MAKE_JUMP(&stub[2], (int)(original + 2)); // J original_function_fallback
stub[3] = 0; // nop
writeback_dcache_and_invalidate_icache_range(stub, stub + 4);
}
}
else if (is_branch_control_instruction(original[1]))
{
if (is_relative_branch_control_instruction(original[1]))
{
stub[0] = original[0]; // insn1
stub[1] = (original[1]&0xFFFF0000)|4; // insn2 modified
stub[2] = original[2]; // insn3
MAKE_JUMP(&stub[3], (int)(original + 3)); // J original_function_fallback
stub[4] = 0; // nop
MAKE_JUMP(&stub[5], (int)(original + 1 + (original[1]&0xFFFF)));
stub[6] = 0; // nop
writeback_dcache_and_invalidate_icache_range(stub, stub + 7);
}
else
{
stub[0] = original[0]; // insn1
stub[1] = original[1]; // insn2
stub[2] = 0; // nop
MAKE_JUMP(&stub[3], (int)(original + 2)); // J original_function_fallback
stub[4] = 0; // nop
writeback_dcache_and_invalidate_icache_range(stub, stub + 5);
}
}
else
{
stub[0] = original[0]; // insn1
MAKE_JUMP(&stub[1], (int)(original + 2)); // J original_function_fallback
stub[2] = original[1]; // insn2
writeback_dcache_and_invalidate_icache_range(stub, stub + 3);
}
MAKE_JUMP(&original[0], hooked); // insn1 ---> J hooked_function
original[1] = 0; // insn2 ---> nop
writeback_dcache_and_invalidate_icache_range(original, original + 2);
return stub;
}
|
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun Mar 08, 2009 11:54 pm Post subject: |
|
|
I edited heavily the previous post so the stub generator can handle the case when one of first two instructions in the original function contains a relative branch instruction. You need a .S file to contain your stub to overwrite (for each original function to patch, you need a stub function of 8 instructions) :
| Code: |
.global your_stub_function
.enter your_stub_function
your_stub_function:
jr $ra
nop
nop
nop
nop
nop
nop
nop
.end your_stub_function
...
|
when you want to patch an original function with your hooked function, you also pass the stub function address :
| Code: |
extern int stub_function(int);
int hooked_function(int a0)
{
int result;
// do your stuff here
result = stub_function(a0);
// do your other stuff here
return result;
}
...
patch_jump((int *)&original_function, (int *)&hooked_function, (int *)&stub_function);
...
|
|
|
| Back to top |
|
 |
Pirata Nervo
Joined: 09 Oct 2007 Posts: 409
|
Posted: Mon Mar 09, 2009 2:36 am Post subject: |
|
|
Thank you very much hlide and Torch :) _________________
Upgrade your PSP |
|
| Back to top |
|
 |
|