Hacking OSDriver kernel exploit - a technical description

Marionumber1

Well-Known Member
OP
Member
Joined
Nov 7, 2010
Messages
1,234
Trophies
3
XP
4,045
Country
United States
I was not able to use the read/write syscalls while executing a game (via pygecko).
It turns out that the syscall table modified by the kernel exploit is not the one used by games (at least on 5.3.2).

So I added the read/write syscalls into the other syscall tables, and it worked.
On 5.3.2 the syscall table used by games is the one located at 0xFFE85070.

Then it's possible that there may be tables for the loader, foreground apps, and background apps. Thanks for pointing that out.
 

CosmoCortney

i snack raw pasta and chew lollipops
Member
Joined
Apr 18, 2013
Messages
1,768
Trophies
2
Location
on the cool side of the pillow
Website
follow-the-white-rabbit.wtf
XP
3,017
Country
Germany
I was not able to use the read/write syscalls while executing a game (via pygecko).
It turns out that the syscall table modified by the kernel exploit is not the one used by games (at least on 5.3.2).

So I added the read/write syscalls into the other syscall tables, and it worked.
On 5.3.2 the syscall table used by games is the one located at 0xFFE85070.

Then it's possible that there may be tables for the loader, foreground apps, and background apps. Thanks for pointing that out.

So.. range 01 can be mapped as read/write and executable?
 

Marionumber1

Well-Known Member
OP
Member
Joined
Nov 7, 2010
Messages
1,234
Trophies
3
XP
4,045
Country
United States
So.. range 01 can be mapped as read/write and executable?

The kern_read() and kern_write() syscalls access memory with kernel permissions, but that doesn't let you write read-only memory. What they do is let you bypass the kernel-only flag and write kernel data. You can use this to modify the address table and map the 0x01000000 range as writable, provided you find the writable flag (probably in PPC manuals).
 

golden45

Well-Known Member
Member
Joined
Jun 23, 2015
Messages
108
Trophies
0
Age
124
XP
473
Country
France
So.. range 01 can be mapped as read/write and executable?

The kern_read() and kern_write() syscalls access memory with kernel permissions, but that doesn't let you write read-only memory. What they do is let you bypass the kernel-only flag and write kernel data. You can use this to modify the address table and map the 0x01000000 range as writable, provided you find the writable flag (probably in PPC manuals).

We could also map the third entry of the kernel address table (default virtual address : 0x02000000), which seams to be where the application code is put.
This third entry is modified for each application/game, here is what I found so far :

(virt_addr, range_len, phys_addr, flags)
in browser : 0x0D800000, 0x02800000, 0x4D800000, 0x2ff09400
MarioKart8 : 0x0E280000, 0x01D80000, 0x8E280000, 0x2ff09400
Splatoon : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
WindWaker : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
Bayon2demo : 0x0D400000, 0x02C00000, 0x8D400000, 0x2ff09400
SonicLWdemo: 0x0A600000, 0x05A00000, 0x8A600000, 0x2ff09400
WiiuParams : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
 

CosmoCortney

i snack raw pasta and chew lollipops
Member
Joined
Apr 18, 2013
Messages
1,768
Trophies
2
Location
on the cool side of the pillow
Website
follow-the-white-rabbit.wtf
XP
3,017
Country
Germany
The kern_read() and kern_write() syscalls access memory with kernel permissions, but that doesn't let you write read-only memory. What they do is let you bypass the kernel-only flag and write kernel data. You can use this to modify the address table and map the 0x01000000 range as writable, provided you find the writable flag (probably in PPC manuals).
Oh, I see. It first sounded like it would refer to making the 01 range writable to me :)

We could also map the third entry of the kernel address table (default virtual address : 0x02000000), which seams to be where the application code is put.
This third entry is modified for each application/game, here is what I found so far :

(virt_addr, range_len, phys_addr, flags)
in browser : 0x0D800000, 0x02800000, 0x4D800000, 0x2ff09400
MarioKart8 : 0x0E280000, 0x01D80000, 0x8E280000, 0x2ff09400
Splatoon : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
WindWaker : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
Bayon2demo : 0x0D400000, 0x02C00000, 0x8D400000, 0x2ff09400
SonicLWdemo: 0x0A600000, 0x05A00000, 0x8A600000, 0x2ff09400
WiiuParams : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400

So, this is where the .rpx is loaded?
 

shinyquagsire23

SALT/Sm4sh Leak Guy
Member
Joined
Nov 18, 2012
Messages
1,977
Trophies
2
Age
26
Location
Las Vegas
XP
3,765
Country
United States
Oh, I see. It first sounded like it would refer to making the 01 range writable to me :)



So, this is where the .rpx is loaded?
Yeah, that's where it is for certain, I only just found out yesterday that it wasn't even readable for some reason so I assumed it was a per-process mapping, but it's not.

EDIT: I made a derp.
 
Last edited by shinyquagsire23,

shinyquagsire23

SALT/Sm4sh Leak Guy
Member
Joined
Nov 18, 2012
Messages
1,977
Trophies
2
Age
26
Location
Las Vegas
XP
3,765
Country
United States
Hmm.. I assume it's not writable, too. Am I right?
Highly doubtful of that yeah. I know for certain it's not under the 0x01xxxxxx or 0x0exxxxxx areas which are RX.

Edit: If the kernel table entry can be remapped as RWX I'm pretty sure you'd be able to start using the area from Gecko, I'm personally trying to get at the area for some .text mods myself.
 

Marionumber1

Well-Known Member
OP
Member
Joined
Nov 7, 2010
Messages
1,234
Trophies
3
XP
4,045
Country
United States
This third entry is modified for each application/game, here is what I found so far :

(virt_addr, range_len, phys_addr, flags)
in browser : 0x0D800000, 0x02800000, 0x4D800000, 0x2ff09400
MarioKart8 : 0x0E280000, 0x01D80000, 0x8E280000, 0x2ff09400
Splatoon : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
WindWaker : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
Bayon2demo : 0x0D400000, 0x02C00000, 0x8D400000, 0x2ff09400
SonicLWdemo: 0x0A600000, 0x05A00000, 0x8A600000, 0x2ff09400
WiiuParams : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400

Interesting, I had done some experiments to see where app code ended up, but never checked to see that the address table got modified too. This seems to confirm my hypothesis that the application code address is designed to make it end at 0x10000000. I noticed it with the browser and Mii Maker, but it's nice to have more solid proof. It also verifies my other hypothesis, which is that they throw app code at the end of the app data area in physical memory.

The base, length, and physical address are modified, but flags are still unchanged from their default. This implies that you're right, and we can also remap it as writable.
 

shinyquagsire23

SALT/Sm4sh Leak Guy
Member
Joined
Nov 18, 2012
Messages
1,977
Trophies
2
Age
26
Location
Las Vegas
XP
3,765
Country
United States
I was not able to use the read/write syscalls while executing a game (via pygecko).
It turns out that the syscall table modified by the kernel exploit is not the one used by games (at least on 5.3.2).

So I added the read/write syscalls into the other syscall tables, and it worked.
On 5.3.2 the syscall table used by games is the one located at 0xFFE85070.
I did some experimentation and found that FFEA9CE0 is the location for the syscall table used while in the home menu.

EDIT: And while I'm at it:
Code:
(virt_addr, range_len, phys_addr, flags)
0x0dd00000, 0x2300000, 0x8dd00000, 0x2ff09400
Is what you'll want for looking at the home menu's .text area.

And in addition to this, you can find these offsets from non-kernel-only definitions. In the 0x0e300000 area there's several structures which contain ELFs, the name of the loaded module rpl/rpx, and where it's loaded. For example, 0x0e382500 is the structure for men.rpx, and 0x0e382500+0x204 will have the offset which the .text is located at. At 0x0e382500+0x204 it actually has several pointers, going in this order: .syscall, .text, and I'm guessing maybe some .data locations or something.

Other EDIT: 0x0e300000 isn't mapped while in the browser, so not 100% solid I suppose. Although if you have kernel you can just find the offset fairly easily anyhow.

Last EDIT: So by mapping kern_read and kern_write for the menu with TCPGecko in the browser, I managed to remap the .text region as RWX. After gaining kernel read/write while in the menu, changing 0xFFEAAA10+0x2C from 0x2ff09400 to 0x2FF09C00 lets me write in the 0x0dd00000 area! I'm not sure if the RWX mappings are changed between app launches though, but this is enough to give you temporary RWX access while the game/app runs.. Actually it seems only kernel write access is needed to modify the .text region, no remapping needed.
 
Last edited by shinyquagsire23,

Lory171

Well-Known Member
Newcomer
Joined
Jun 20, 2015
Messages
45
Trophies
0
Age
27
XP
170
Country
Italy
We could also map the third entry of the kernel address table (default virtual address : 0x02000000), which seams to be where the application code is put.
This third entry is modified for each application/game, here is what I found so far :

(virt_addr, range_len, phys_addr, flags)
in browser : 0x0D800000, 0x02800000, 0x4D800000, 0x2ff09400
MarioKart8 : 0x0E280000, 0x01D80000, 0x8E280000, 0x2ff09400
Splatoon : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
WindWaker : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400
Bayon2demo : 0x0D400000, 0x02C00000, 0x8D400000, 0x2ff09400
SonicLWdemo: 0x0A600000, 0x05A00000, 0x8A600000, 0x2ff09400
WiiuParams : 0x0E000000, 0x02000000, 0x8E000000, 0x2ff09400

the file cos.xml inside the code folder have a different max_codesize for different games, i don't know if it's related but it look like that
Game1: <max_codesize type="hexBinary" length="4">0E000000</max_codesize>
Game2: <max_codesize type="hexBinary" length="4">03200000</max_codesize>
 

golden45

Well-Known Member
Member
Joined
Jun 23, 2015
Messages
108
Trophies
0
Age
124
XP
473
Country
France
the file cos.xml inside the code folder have a different max_codesize for different games, i don't know if it's related but it look like that
Game1: <max_codesize type="hexBinary" length="4">0E000000</max_codesize>
Game2: <max_codesize type="hexBinary" length="4">03200000</max_codesize>

It is related yes. With this length, the virtual address is then calculated.
This virtual address range is filled from the start with :
- the .syscall and .text sections of the RPX
- functions to jump to the imported functions of the RPX.
- elf structures for the RPLs, thoses structures are linked to each other.
- code parts linked to the elf structures
- zero data
- data in tables (most likely)

(AFAIK)
 

Onion_Knight

Well-Known Member
Member
Joined
Feb 6, 2014
Messages
878
Trophies
0
Age
45
XP
997
Country
I did some experimentation and found that FFEA9CE0 is the location for the syscall table used while in the home menu.

EDIT: And while I'm at it:
Code:
(virt_addr, range_len, phys_addr, flags)
0x0dd00000, 0x2300000, 0x8dd00000, 0x2ff09400
Is what you'll want for looking at the home menu's .text area.

And in addition to this, you can find these offsets from non-kernel-only definitions. In the 0x0e300000 area there's several structures which contain ELFs, the name of the loaded module rpl/rpx, and where it's loaded. For example, 0x0e382500 is the structure for men.rpx, and 0x0e382500+0x204 will have the offset which the .text is located at. At 0x0e382500+0x204 it actually has several pointers, going in this order: .syscall, .text, and I'm guessing maybe some .data locations or something.

Other EDIT: 0x0e300000 isn't mapped while in the browser, so not 100% solid I suppose. Although if you have kernel you can just find the offset fairly easily anyhow.

Last EDIT: So by mapping kern_read and kern_write for the menu with TCPGecko in the browser, I managed to remap the .text region as RWX. After gaining kernel read/write while in the menu, changing 0xFFEAAA10+0x2C from 0x2ff09400 to 0x2FF09C00 lets me write in the 0x0dd00000 area! I'm not sure if the RWX mappings are changed between app launches though, but this is enough to give you temporary RWX access while the game/app runs.. Actually it seems only kernel write access is needed to modify the .text region, no remapping needed.


If I'm wanting to run TCPGecko on the menu, I need to modify my Kernel Address table to this one correct?
 

golden45

Well-Known Member
Member
Joined
Jun 23, 2015
Messages
108
Trophies
0
Age
124
XP
473
Country
France
If I'm wanting to run TCPGecko on the menu, I need to modify my Kernel Address table to this one correct?
Yes, you can also add the read/write syscall to all syscall tables directly in the kernel exploit.

If you're on 5.3.2 :

in loader.h:
#define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown
#define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games
#define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader
#define KERN_SYSCALL_TBL_4 0xFFEA9CE0 // works with home menu
#define KERN_SYSCALL_TBL_5 0xFFEAA0E0 // works with browser (previously KERN_SYSCALL_TBL)

in loader.c:
- replace "copy_payload[0xff8/4] = KERN_SYSCALL_TBL + (0x34 * 4);" by "copy_payload[0xff8/4] = KERN_SYSCALL_TBL_5 + (0x34 * 4);"
- add those lines after the " Map the loader and coreinit as RW before exiting" part :
/* Add read/write syscalls to the other syscall_tables */
kern_write(KERN_SYSCALL_TBL_1 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_1 + (0x35 * 4), KERN_CODE_WRITE);

kern_write(KERN_SYSCALL_TBL_2 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_2 + (0x35 * 4), KERN_CODE_WRITE);

kern_write(KERN_SYSCALL_TBL_3 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_3 + (0x35 * 4), KERN_CODE_WRITE);

kern_write(KERN_SYSCALL_TBL_4 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_4 + (0x35 * 4), KERN_CODE_WRITE);

Then you're free to use the syscalls everywhere :)

edit: sorry I didn't read well the question, I let this here if you are interested
 

Onion_Knight

Well-Known Member
Member
Joined
Feb 6, 2014
Messages
878
Trophies
0
Age
45
XP
997
Country
Yes, you can also add the read/write syscall to all syscall tables directly in the kernel exploit.

If you're on 5.3.2 :

in loader.h:
#define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown
#define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games
#define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader
#define KERN_SYSCALL_TBL_4 0xFFEA9CE0 // works with home menu
#define KERN_SYSCALL_TBL_5 0xFFEAA0E0 // works with browser (previously KERN_SYSCALL_TBL)

in loader.c:
- replace "copy_payload[0xff8/4] = KERN_SYSCALL_TBL + (0x34 * 4);" by "copy_payload[0xff8/4] = KERN_SYSCALL_TBL_5 + (0x34 * 4);"
- add those lines after the " Map the loader and coreinit as RW before exiting" part :
/* Add read/write syscalls to the other syscall_tables */
kern_write(KERN_SYSCALL_TBL_1 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_1 + (0x35 * 4), KERN_CODE_WRITE);

kern_write(KERN_SYSCALL_TBL_2 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_2 + (0x35 * 4), KERN_CODE_WRITE);

kern_write(KERN_SYSCALL_TBL_3 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_3 + (0x35 * 4), KERN_CODE_WRITE);

kern_write(KERN_SYSCALL_TBL_4 + (0x34 * 4), KERN_CODE_READ);
kern_write(KERN_SYSCALL_TBL_4 + (0x35 * 4), KERN_CODE_WRITE);

Then you're free to use the syscalls everywhere :)

edit: sorry I didn't read well the question, I let this here if you are interested

This is even better than the question I asked!

Will my thread migrate than from browser, to system menu and game?

--------------------- MERGED ---------------------------

This is even better than the question I asked!

Will my thread migrate than from browser, to system menu and game?
I'll need to add this to the loader.h for the codehandler as well I assume.
 

golden45

Well-Known Member
Member
Joined
Jun 23, 2015
Messages
108
Trophies
0
Age
124
XP
473
Country
France
I'll need to add this to the loader.h for the codehandler as well I assume.
If you modify the syscall tables in the kernel exploit, you don't need to modify them anymore. You will be able to use kern_read/kern_write of pygecko when in browser/home/games

Will my thread migrate than from browser, to system menu and game?
You mean the pygecko thread?
If yes, the thread (pygecko server) is created when coreinit.rpl starts, which is done at the end of the loader, which is called everytime you switch between applications.
 

Onion_Knight

Well-Known Member
Member
Joined
Feb 6, 2014
Messages
878
Trophies
0
Age
45
XP
997
Country
If you modify the syscall tables in the kernel exploit, you don't need to modify them anymore. You will be able to use kern_read/kern_write of pygecko when in browser/home/games


You mean the pygecko thread?
If yes, the thread (pygecko server) is created when coreinit.rpl starts, which is done at the end of the loader, which is called everytime you switch between applications.
Your my favorite clown right now. Thanks for the quick answers. Finally bothered to fix the pygecko codehandler to keep listening after the socket closes, so now i'm interested in moving around.
 

golden45

Well-Known Member
Member
Joined
Jun 23, 2015
Messages
108
Trophies
0
Age
124
XP
473
Country
France
Finally bothered to fix the pygecko codehandler to keep listening after the socket closes, so now i'm interested in moving around.

Be aware that with pygecko, it will freeze the console if you launch a game, quit it, and then return to the browser.
(well for me it freezes, maybe it's the modifications i made on pygecko so i'm not sure)

To resolve the problem I had to add a "GX2WaitForVsync" in the start function of the pygecko codehandler :

Code:
static void start(int argc, void *argv) {
    int sockfd = -1, clientfd = -1, ret, len;
    struct sockaddr_in addr;
    struct bss_t *bss = argv;

    socket_lib_init();

    while (1) {
        addr.sin_family = AF_INET;
        addr.sin_port = 7331;
        addr.sin_addr.s_addr = 0;

        sockfd = ret = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        CHECK_ERROR(ret == -1);
        ret = bind(sockfd, (void *)&addr, 16);
        CHECK_ERROR(ret < 0);
        ret = listen(sockfd, 1);
        CHECK_ERROR(ret < 0);
        len = 16;
        clientfd = ret = accept(sockfd, (void *)&addr, &len);
        CHECK_ERROR(ret == -1);
        socketclose(sockfd);
        sockfd = -1;
        ret = rungecko(bss, clientfd);
        CHECK_ERROR(ret < 0);
        socketclose(clientfd);
        clientfd = -1;

        GX2WaitForVsync();
        continue;
error:
        if (clientfd != -1)
            socketclose(clientfd);
        if (sockfd != -1)
            socketclose(sockfd);
        bss->error = ret;
        GX2WaitForVsync();
    }
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Xdqwerty @ Xdqwerty: And that game stick i'm tired of mentioning