Advertising (This ad goes away for registered users. You can Login or Register)

[Eloader] 2. Basic concepts

Forum rules
Forum rule Nº 15 is strictly enforced in this subforum.
Locked
m0skit0
Guru
Posts: 3817
Joined: Mon Sep 27, 2010 6:01 pm

[Eloader] 2. Basic concepts

Post by m0skit0 »

Originally posted by m0skit0 on advancedpsp.tk.
Retrieved by ultimakillz, http://h4ck.fi.st/index.php/topic,78.0.html


So as said in the introduction, our objective is to make our own sceKernelLoadExec()/sceKernelLoadModule(). First thing we need to know is what kind of executable PSP uses. Well, as its non-portable brothers, PSP uses ELF executables. ELF stands for Executable and Linkable Format. But those ELFs are wrapped inside a DATA.PSP file, which in turn is embedded into an EBOOT.PBP file. To simplify things, we're going straight to the ELFs themselves, skipping all the onion layers removing (EBOOT.PBP and DATA.PSP).

ELFs contain code and data for a program to run. But to run a program in a decent OS you need more information, which is also stored in the ELF. An ELF file is divided into multiple sections, each one containing different type of information. Let's see what information an ELF contains.

Loading address. Well, an ELF, as an executable, needs to be loaded in memory to be run. But at what address should it be loaded? In PSP there are two kinds of ELFs: static and relocatable. Static ones have no relocation information. This means addresses and references into the code are fixed numbers, so we need to always load the code at the same fixed address or it will not work properly. Relocatable ones (better known as PRX, PSP Relocatable Executable) have no fixed loading address, so the kernel can choose where to load them. This is more flexible but need relocation information, that is, how to change the references inside the code with the real loading address. To simplify, we're not going to consider relocatable ELFs by now (for more info about relocation: http://en.wikipedia.org/wiki/Relocation ... r_science))

Imports.
An ELF can have calls to external functions provided by the OS, commonly called system calls. Those system calls are just petitions from the application to the OS, such as "open this file", "write this to screen", etc... This code is not included on the application itself (that is, the ELF) but on the OS. Some calls are on the kernel space, some are on user space. To access user space calls, PSP uses direct jumps, using plain j MIPS instructions. For kernel space calls, PSP uses syscall MIPS instructions. So the ELF has a section called .sceStub.text, where all the system calls are stored. If you prxtool -w an ELF file generated by PSPSDK, you'll find something like this:

Code: Select all

; ==== Section .sceStub.text - Address 0x0890F24C Size 0x000000F8 Flags 0x0006

; ======================================================
; Subroutine sceDisplaySetMode - Address 0x0890F24C
sceDisplaySetMode:      ; Refs: 0x08900BA0
   0x0890F24C: 0x03E00008 '....' - jr         $ra
   0x0890F250: 0x00000000 '....' - nop       

; End Subroutine sceDisplaySetMode
; ======================================================
Well, you can see the sceDisplaySetMode() system call code. But wait... ¿jr $ra and nop? This will do nothing, just return to the caller!! Well, those calls have to be resolved by the ELF loader. Here the ELF loader is going to insert the real system call when it loads the ELF to be executed into memory. If the ELF loader doesn't resolve this stubs, the executable will just receive nothing from those syscalls. An example of resolved stub would be like this:

(direct jump - user space system call)

Code: Select all

000002ac:    0a7cfc80   j   0x9f3f200
000002b0:    00000000   nop

(syscall - kernel space system call)
Código: Seleccionar todo
08C9298c:    03e00008   jr   $ra         
08C92990:    0008b68c   syscall   0x022da
As you can see, the ELF loader changed the stubs code. So the result is a double jump to make the system call: the code calls the stub, the stub calls the real system call. This way, you have to resolve the system call only once, and not everytime it appears on the code.

I think this is all for basic concepts, let's see how to get the ELF load and resolve those imports.
Advertising
I wanna lots of mov al,0xb
Image
"just not into this RA stuffz"
tbg
Posts: 111
Joined: Mon Sep 27, 2010 4:35 pm

2. Conceptos básicos.

Post by tbg »

Texto extraído de m0skit0 en advancedpsp.tk.
Obtenido por Ultimakillz, http://h4ck.fi.st/index.php/topic,78.0.html


Como he dicho en la introducción, nuestro objetivo es el de hacer nuestro propio sceKernelLoadExec()/sceKernelLoadModule(). Lo primero que necesitamos es saber qué tipo de ejecutables usa la PSP. Bien, al igual que sus hermanos no-portatiles, hace uso de ejecutables ELF. ELF significa Executable and Linkable Format. Pero estos ELFs están dentro del archivo DATA.PSP, que está a su vez dentro de un archivo EBOOT.PBP. Para simplificar las cosas, vamos directamente a los ELFs, saltándonos las capas de cebolla (EBOOT.PBP y DATA.PSP).

ELFs contienen código y datos para que el programa se ejecute. Pero para cargar un programa en un OS? decente necesitas más información, que está almacenado en el ELF. Un archivo ELF está dividido en múltiples secciones, cada uno contiene diferente tipo de información. Veamos qué información contienen los ELFs.

Carga de direcciones. Bueno, un ELF, como los ejecutables, necesitan estar cargados en memoria para que se ejecuten. ¿Pero en qué dirección deben ser cargados? En PSP hay dos tipos de ELFs: estático y reubicable.
Estático no tiene información de reubicación. Esto significa que las direcciones y las referencias dentro del código son números fijos, así que necesitamos que siempre carge el código en la misma dirección fija o no funcionará correctamente.
Reubicable (o más conocido como PRX, PSP Relocatable Executable) no tiene una dirección fija, por lo que el kernel puede elegir donde cargarlo. Esto es más flexible pero necesita información reubicable, esto es, cómo cambiar las referencias dentro del código con las direcciones de carga reales. Para simplificar, no vamos a considerar por el momento los ELF's reubicables por ahora (par más información sobre reubicación [en inglés]: http://en.wikipedia.org/wiki/Relocation ... science%29)

Importados: Un ELF puede tener llamadas externas a funciones proporcionadas por el OS, comúnmente llamadas system call. Estas llamadas del sistema son solo peticiones desde la aplicación al OS, así como "abre este archivo", "escribe esto en pantalla", etc... Este código no está incluido en la aplicación misma (en el ELF) si no en el OS. Algunas llamadas están en el espacio del kernel, otras están el espacio usuario. Para acceder a las llamadas del espacio usuario, PSP usa saltos directos, haciendo uso de simples instrucciones j MIPS. Para las llamadas del espacio kernel, PSP usa instrucciones syscall MIPS. Así que el ELF tiene una sección llamada .sceStub.text, donde están todas las llamadas almacenadas. Si pones prxtool -w en PSPSDK, se generará un archivo como este:

Code: Select all

; ==== Section .sceStub.text - Address 0x0890F24C Size 0x000000F8 Flags 0x0006

; ======================================================
; Subroutine sceDisplaySetMode - Address 0x0890F24C
sceDisplaySetMode:      ; Refs: 0x08900BA0
    0x0890F24C: 0x03E00008 '....' - jr         $ra
    0x0890F250: 0x00000000 '....' - nop       

; End Subroutine sceDisplaySetMode
; ======================================================
Bien, podemos ver el código de la llamada del sistema sceDisplaySetMode(). Pero espera...¿jr $ra y nop? ¡¡Esto no hará nada, solo volverá a la llamada!! Bueno, estas llamadas tienen que ser resueltas por el ELF loader. Aquí el ELF loader va a insertar la llamada del sistema real donde se cargarán los ELF para ser ejecutados en la memoria. Si el ELF loader no resuelve este stub¹, el ejecutable no recibirá ninguna llamada desde estas syscalls. Un ejemplo para resolver este stub sería:

Code: Select all

000002ac:    0a7cfc80   j   0x9f3f200
000002b0:    00000000   nop

(syscall - kernel space system call)
Código: Seleccionar todo
08C9298c:    03e00008   jr   $ra         
08C92990:    0008b68c   syscall   0x022da
Como puedes ver, el ELF loader ha cambiado el código del stub. El resultado es un doble salto para hacer llamadas del sistema: el código llama al stub, el stub llama a la llamada real del sistema. Esta vez, tendrás que resolver la llamada del sistema una vez, y no cada vez que aparezca en el código.

Creo que estos son todos los conceptos básicos, vamos a ver cómo cargar el ELF y como resolver esas importaciones.
--------------------------
? Sistema Operativo en inglés.
¹ Un stub es un trozo de código hecho para representar alguna funcionalidad de un componente.
Advertising
TBG : Team Extraction member
Locked

Return to “Programming and Security”