Call Syscalls from plain binary ASM?
Call Syscalls from plain binary ASM?
I know I'm probably going to be stoned to death, but I'll take my chance and ask anyway....
Let's say I have a small block of raw ASM code, injected to somewhere in the PSPs RAM and jumped in to.
Is there a good and known way of calling syscalls (like sceIoOpen and stuff) from there?
Since I'm not having any imports and the like I can't think of a decent way of doing that (besides manually letting the code run through the whole RAM to find the libs I need and fetch the adresses of the calls).
Any hint to make it more easy? :)
Secondly, how do I get the compiler to just make a plain binary from some ASM source, w/o headers, footers or anything else....
Any help apreciated, thanks :)
Let's say I have a small block of raw ASM code, injected to somewhere in the PSPs RAM and jumped in to.
Is there a good and known way of calling syscalls (like sceIoOpen and stuff) from there?
Since I'm not having any imports and the like I can't think of a decent way of doing that (besides manually letting the code run through the whole RAM to find the libs I need and fetch the adresses of the calls).
Any hint to make it more easy? :)
Secondly, how do I get the compiler to just make a plain binary from some ASM source, w/o headers, footers or anything else....
Any help apreciated, thanks :)
Firstly, you want to just use GAS, the gnu assembler. It's part of the normal toolchain. Look at gas tutorials for the x86, then substitute MIPS for x86. You'll find various .s and .S files in the PSP SDK source you can look at for examples of syntax. The difference is the .S files are run through the c preprocessor so that you can make defines and such just like with c, even though it's assembly.
For example, in a .s file you would define a constant like this:
In a .S file, you can still do that, or you can do:
If you're mixing C and asm, the latter method might be easier as you can make one set of defines in a .h file and include it in both c and asm files.
Secondly, it's EXTREMELY easy to call PSP system functions from asm: just put the arguments in a0-a3 and t0-t3 (if more than four args), then do a jal to the function name. For example:
Don't forget about that delay slot! Of course, the above could be done like this:
Note that the above is calling USER level functions from user mode.
For example, in a .s file you would define a constant like this:
Code: Select all
MY_CONST EQU 3
Code: Select all
#define MY_CONST 3
Secondly, it's EXTREMELY easy to call PSP system functions from asm: just put the arguments in a0-a3 and t0-t3 (if more than four args), then do a jal to the function name. For example:
Code: Select all
li a0,1000
jal sceKernelDelayThread
nop
Code: Select all
jal sceKernelDelayThread
li a0,1000
You mean building the code on the fly inside the app, like Dynamic Recompiling? Same statements still apply, he just has to "compile" the code himself, ORing the address of the function into the opcode for JAL and then storing that at the correct location in memory, then flushing the data cache and invalidating the code cache. That's quite a bit more complex, but still follows the same guidelines as far as the assembly language goes.
The function addresses for the SDK functions are done the way any function address is.
Something like that. If you look at the sdk libraries, they're often nothing more than lots of stubs that call the actually library function. The stubs themselves change according to what mode the code is in vs what mode the lib function is.
The encoding of the instructions themselves are in the MIPS32 Architecture: Vol 2. You can find that just about anywhere online. Looking at an existing DR for the PSP might be helpful as well. For that, check out something like Daedalus.
The function addresses for the SDK functions are done the way any function address is.
Code: Select all
code_buffer[curr_index] = JAL_OP | (((u32)&sceKernelDelayThread & 0x0FFFFFFC) >> 2);
The encoding of the instructions themselves are in the MIPS32 Architecture: Vol 2. You can find that just about anywhere online. Looking at an existing DR for the PSP might be helpful as well. For that, check out something like Daedalus.
I don't understand how this works either.
The instruction 0x0C0003AA just jumps to a hardcoded address right?? Assuming thats how it is, how do you know that the function will always be at that address ?? I'm a noob at MIPS..
(Ironically the above is code to find another function :P)
Code: Select all
0x0000003C: 0xAE02123C '<...' - sw $v0, 4668($s0)
0x00000040: 0x3C0602BF '...<' - lui $a2, 0x2BF
; Data ref 0x000010F0 "SystemControl"
0x00000044: 0x262410F0 '..$&' - addiu $a0, $s1, 4336
; Data ref 0x00001100 "SystemCtrlForKernel"
0x00000048: 0x26451100 '..E&' - addiu $a1, $s2, 4352
0x0000004C: 0x0C0003AA '....' - jal SystemCtrlForKernel_159AF5CC
(Ironically the above is code to find another function :P)
-
- Posts: 22
- Joined: Sat Jan 03, 2009 6:51 am
I use this trick a lot when I want a small snippet of code to reside in user memory (I don't know if that's what you want to do but it's a great example so I'll just use that here :P), I just allocate a user heap and copy some pure assembly code in there, then hook a function in user memory with it. :) Anyways, you'll need to do some dynamic linking on the buffer, both jumps, syscalls, imports and accessing of global memory.
Instead of seperately compiling it as a binary, I usually use MIPS opcode macros in C code, such as these. Copy the entire bit from [--- NEW FILE: mips-codegen.h ---] till [--- NEW FILE: test.c ---] (the end of the mips-codegen.h file) in a seperate header file and save it. Note that the 'j' instruction is called mips_jump, and the 'jal' instruction is called mips_jumpl in that header file, but you're free to change it.
Include it in your code and you can use it like this:
Our 'code' buffer now contains the instructions to execute sceKernelDelayThread(1000000), and you can jump in to it, or place a hook towards it. Note that instructions like 'li' are actually pseudo-instructions, and what they really do is 'addiu' with the source register set to zero.
@Torch ELF (and PRX) files contain a relocation table with all addresses that require relocation (because they start at zero), which the ELF loader will apply when loading the module. However, talking about the jump, what you mentioned is the opcode, you should search the function name in that assembly and you'll find the stub of that function, which looks like a simple 'jr $ra, nop' in the assembly. However, again, the ELF loader replaces these useless instructions with a jump towards the function exported in the other module, so theoretically you're taking two jumps before you reach the actual function.
:)
Instead of seperately compiling it as a binary, I usually use MIPS opcode macros in C code, such as these. Copy the entire bit from [--- NEW FILE: mips-codegen.h ---] till [--- NEW FILE: test.c ---] (the end of the mips-codegen.h file) in a seperate header file and save it. Note that the 'j' instruction is called mips_jump, and the 'jal' instruction is called mips_jumpl in that header file, but you're free to change it.
Include it in your code and you can use it like this:
Code: Select all
/* declare the buffer to hold it (normally alloc in user mem) */
unsigned int code[2];
/* and a pointer towards it as the macros will change it */
unsigned int *p = code;
/* li $a0, 1000000 */
mips_addiu(p, mips_a0, mips_zero, 1000000);
/* syscall [syscall of DelayThread] */
mips_syscall(p, sceKernelQuerySystemCall(sctrlHENFindFunction("sceThreadManager", "ThreadManForUser", 0xCEADEB47)));
@Torch ELF (and PRX) files contain a relocation table with all addresses that require relocation (because they start at zero), which the ELF loader will apply when loading the module. However, talking about the jump, what you mentioned is the opcode, you should search the function name in that assembly and you'll find the stub of that function, which looks like a simple 'jr $ra, nop' in the assembly. However, again, the ELF loader replaces these useless instructions with a jump towards the function exported in the other module, so theoretically you're taking two jumps before you reach the actual function.
:)
THAT exactely is my situation in this case!Torch wrote:But when you need to write code, such as code which an exploit jumps into, how would external calls be resolved then? In such cases you would need to manually find the functions right?
The MIPS itself isn't the problem, finding the function tables is.
When the injected code is loaded and jumped in to, there's no background process that resolves stubs and such, I'm in the empty void, left alone.
So, for doing anything usefull I'd need to find a way to call some syscalls by finding the addresses to JAL to.
Can't be that hard, previous things (like the 2.00->1.50 downgrader or eLoader) did it, I think.
I'll take a closer look at the old downgrader, I think....
-
- Posts: 22
- Joined: Sat Jan 03, 2009 6:51 am
I've wondered that for ages, due to the fact HEN source codes were never released (just the samples). I think they search the stubs of the game being exploited, which should be at the same address in most cases as far as I know.Hellcat wrote:THAT exactely is my situation in this case!Torch wrote:But when you need to write code, such as code which an exploit jumps into, how would external calls be resolved then? In such cases you would need to manually find the functions right?
The MIPS itself isn't the problem, finding the function tables is.
When the injected code is loaded and jumped in to, there's no background process that resolves stubs and such, I'm in the empty void, left alone.
So, for doing anything usefull I'd need to find a way to call some syscalls by finding the addresses to JAL to.
Can't be that hard, previous things (like the 2.00->1.50 downgrader or eLoader) did it, I think.
I'll take a closer look at the old downgrader, I think....
Edit: Suspicion confirmed, reversed a bit of 3.50 HEN and it turns out it simply jumps right in to the imports of Lumines with hardcoded addresses :)
The advantages of everyone's hardware and probably path of execution being 100% identical....Bubbletune wrote: I've wondered that for ages, due to the fact HEN source codes were never released (just the samples). I think they search the stubs of the game being exploited, which should be at the same address in most cases as far as I know.
Edit: Suspicion confirmed, reversed a bit of 3.50 HEN and it turns out it simply jumps right in to the imports of Lumines with hardcoded addresses :)
Also probably why the exploits required to try multiple times. Due to all environmental conditions being identical for everyone, the address are bound to turn out to be the same once in a while, even if there is a dynamic element involved.
-
- Posts: 22
- Joined: Sat Jan 03, 2009 6:51 am
In the case of game exploits this is less likely, as the game will be exactly the same for everyone when using the same savedata. In the VSH however, there is so, so, so many stuff being done by lots of modules, it's just a matter of luck to have the correct address.Torch wrote:The advantages of everyone's hardware and probably path of execution being 100% identical....
Also probably why the exploits required to try multiple times. Due to all environmental conditions being identical for everyone, the address are bound to turn out to be the same once in a while, even if there is a dynamic element involved.
But in the VSH we also have SO MANY useful stubs to jump into :D :D :DBubbletune wrote: In the case of game exploits this is less likely, as the game will be exactly the same for everyone when using the same savedata. In the VSH however, there is so, so, so many stuff being done by lots of modules, it's just a matter of luck to have the correct address.
Ok, good...
Now, we have some sceKernelLoad\Start* functions, I've see that some modules in the UMD are not compressed with ~SCE or ~PSP signature, only plain ELF, can I load another module with my own imports?
I know that prabably is not possible but why?
Now, we have some sceKernelLoad\Start* functions, I've see that some modules in the UMD are not compressed with ~SCE or ~PSP signature, only plain ELF, can I load another module with my own imports?
I know that prabably is not possible but why?
Get Xplora!
No, you can't do anything like that until there is a working HEN core. The Sony checks will still be present to decrypt the module etc.ne0h wrote:Ok, good...
Now, we have some sceKernelLoad\Start* functions, I've see that some modules in the UMD are not compressed with ~SCE or ~PSP signature, only plain ELF, can I load another module with my own imports?
I know that prabably is not possible but why?
You can only jump stuff already in memory.
Yes but, some files like mpeg.prx are not encrypted, how is it loaded?
Have this ELFs the Sony signature or something else? or are simple ELF files?
EDIT:
I've that only the user mode prx's is unencrypted, why?
There's no signcheck on user modules???
Have this ELFs the Sony signature or something else? or are simple ELF files?
EDIT:
I've that only the user mode prx's is unencrypted, why?
There's no signcheck on user modules???
Get Xplora!
To answer the original question : there's an opcode, syscall 0xnnnn, which will directly invoke a syscall.
The tricky part is figuring out what the syscall ID that you want is. In the early days, syscall tables were static, varying only depending on the firmware and mode (VSH, game, etc.) in use.
But later firmwares (from around 2.50) started messing with that to make it harder to do exploits. Suffice to say, the most reliable way to find the syscall ID for a given function now is to find it imported by another module in your current environment, and read the syscall opcode from that module's import table.
But if you can find it already imported, then as has been said elsewhere, you might as well just jump into the jump table in the import data.
If you want to mess with this stuff further, you'll need to look into how the ELF import tables are laid out (they're just done according to the ELF standards). Using that knowledge you can search through RAM for stuff that looks like a module import table, and retrieve the info you need.
You can PM me for further details if you want to take it further, I'm in the process of revisiting all this stuff for the gripshift exploit.
The tricky part is figuring out what the syscall ID that you want is. In the early days, syscall tables were static, varying only depending on the firmware and mode (VSH, game, etc.) in use.
But later firmwares (from around 2.50) started messing with that to make it harder to do exploits. Suffice to say, the most reliable way to find the syscall ID for a given function now is to find it imported by another module in your current environment, and read the syscall opcode from that module's import table.
But if you can find it already imported, then as has been said elsewhere, you might as well just jump into the jump table in the import data.
If you want to mess with this stuff further, you'll need to look into how the ELF import tables are laid out (they're just done according to the ELF standards). Using that knowledge you can search through RAM for stuff that looks like a module import table, and retrieve the info you need.
You can PM me for further details if you want to take it further, I'm in the process of revisiting all this stuff for the gripshift exploit.
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
The PSP Homebrew Database needs you!
sKQuerySystemCall returns the syscall ID, IIRC.
That's the easy way to find the syscall ID if you happen to have access to kernel mode and have the function address / syscall ID for sKQuerySystemCall in hand.
But if you're working at a very low level in raw assembly and don't have access to niceties such as getting the loader to fix up your import table for you, then sKQuerySystemCall may just be a distant dream.
That's the easy way to find the syscall ID if you happen to have access to kernel mode and have the function address / syscall ID for sKQuerySystemCall in hand.
But if you're working at a very low level in raw assembly and don't have access to niceties such as getting the loader to fix up your import table for you, then sKQuerySystemCall may just be a distant dream.
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
The PSP Homebrew Database needs you!