Call Syscalls from plain binary ASM?

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Hellcat
Posts: 83
Joined: Wed Jan 24, 2007 2:52 pm

Call Syscalls from plain binary ASM?

Post by Hellcat »

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 :)
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

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:

Code: Select all

MY_CONST EQU 3
In a .S file, you can still do that, or you can do:

Code: Select all

#define MY_CONST 3
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:

Code: Select all

	li a0,1000
	jal sceKernelDelayThread
	nop
Don't forget about that delay slot! Of course, the above could be done like this:

Code: Select all

	jal sceKernelDelayThread
	li a0,1000
Note that the above is calling USER level functions from user mode.
Hellcat
Posts: 83
Joined: Wed Jan 24, 2007 2:52 pm

Post by Hellcat »

Thanks :) That already helps alot!

What I don't get is, when I just do a "jal sceKernelDelayThread", where and how does it get the actual address of "sceKernelDelayThread" to jump to?

Anyway, this is enough to get started already, I think, thanks again! :)
FreePlay
Posts: 71
Joined: Wed Jan 04, 2006 6:53 pm
Location: Schenectady, New York, USA

Post by FreePlay »

J.F.,

I think he's trying to go about using functions without requiring *any* external code.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

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.

Code: Select all

    code_buffer[curr_index] = JAL_OP | (((u32)&sceKernelDelayThread & 0x0FFFFFFC) >> 2);
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.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

I don't understand how this works either.

Code: Select all

	0x0000003C&#58; 0xAE02123C '<...' - sw         $v0, 4668&#40;$s0&#41;
	0x00000040&#58; 0x3C0602BF '...<' - lui        $a2, 0x2BF
; Data ref 0x000010F0 "SystemControl"
	0x00000044&#58; 0x262410F0 '..$&' - addiu      $a0, $s1, 4336
; Data ref 0x00001100 "SystemCtrlForKernel"
	0x00000048&#58; 0x26451100 '..E&' - addiu      $a1, $s2, 4352
	0x0000004C&#58; 0x0C0003AA '....' - jal        SystemCtrlForKernel_159AF5CC
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)
Bubbletune
Posts: 22
Joined: Sat Jan 03, 2009 6:51 am

Post by Bubbletune »

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:

Code: Select all

	/* declare the buffer to hold it &#40;normally alloc in user mem&#41; */
	unsigned int code&#91;2&#93;;
	
	/* and a pointer towards it as the macros will change it */
	unsigned int *p = code;

	/* li $a0, 1000000 */
	mips_addiu&#40;p, mips_a0, mips_zero, 1000000&#41;;
	
	/* syscall &#91;syscall of DelayThread&#93; */
	mips_syscall&#40;p, sceKernelQuerySystemCall&#40;sctrlHENFindFunction&#40;"sceThreadManager", "ThreadManForUser", 0xCEADEB47&#41;&#41;&#41;; 
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.

:)
ne0h
Posts: 386
Joined: Thu Feb 21, 2008 2:15 am

Post by ne0h »

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.
uuu, finally I know what's the relocation table, thanks
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

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?
Hellcat
Posts: 83
Joined: Wed Jan 24, 2007 2:52 pm

Post by Hellcat »

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?
THAT exactely is my situation in this case!

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....
Bubbletune
Posts: 22
Joined: Sat Jan 03, 2009 6:51 am

Post by Bubbletune »

Hellcat wrote:
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?
THAT exactely is my situation in this case!

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....
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 :)
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

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 :)
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.
Bubbletune
Posts: 22
Joined: Sat Jan 03, 2009 6:51 am

Post by Bubbletune »

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.
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.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

Bubbletune 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.
But in the VSH we also have SO MANY useful stubs to jump into :D :D :D
ne0h
Posts: 386
Joined: Thu Feb 21, 2008 2:15 am

Post by ne0h »

Hellcat,
do you know how to get functions address only of the functions imported by the game?
Hellcat
Posts: 83
Joined: Wed Jan 24, 2007 2:52 pm

Post by Hellcat »

You can use PRXTool to do disasm of the main binary executable of the game, it will give you the stub adresses for everything the game imports.

You can the use those to call the functions the game imports.

That's what has been done for the Sparta-SDK by Freeplay and MaTiAz.
ne0h
Posts: 386
Joined: Thu Feb 21, 2008 2:15 am

Post by ne0h »

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?
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

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?
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.

You can only jump stuff already in memory.
ne0h
Posts: 386
Joined: Thu Feb 21, 2008 2:15 am

Post by ne0h »

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???
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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.
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
m0skit0
Posts: 191
Joined: Tue Jun 02, 2009 8:58 pm

Post by m0skit0 »

Awesome post!!! (sorry I had to say it)
The Incredible Bill Gates wrote:The obvious mathematical breakthrough would be development of an easy way to factor large prime numbers.
kralyk
Posts: 114
Joined: Sun Apr 06, 2008 8:18 pm
Location: Czech Republic, central EU

Post by kralyk »

how about using mips sceKernelQuerySystemCall(desired_function)?

Whats the difference between jumping to a syscall directly and using sceKernelQuerySystemCall?
...sorry for my english...
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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.
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
Post Reply