- Joined
- Jul 7, 2010
- Messages
- 4,057
- Trophies
- 2
- Location
- /dev/random
- Website
- www.gudenau.net
- XP
- 6,305
- Country
Check over here. https://github.com/shinyquagsire23/bootstrap
what version is your 3ds?
Your code contains global non-constant variables and as far as I know those are not permitted with spider3DSTools
Does pie break that then? Or i is it the linker?
I think it has more to do with the address where the code is copied to be executed (But I don't really know). You'll have to ask yifan_lu.
A solution is using known free heap space memory or just stack memory and pass down pointers.
#define START_SECTION __attribute__ ((section (".text.start"), naked))
// make sure code is PIE
#ifndef __PIE__
#error "Must compile with -fPIE"
#endif
#define FILE_R 0x1
typedef struct file_s {
int s;
int pos;
int size;
} FILE;
int(*IFile_Open)(FILE *this, const short *path, int flags) = (void *)0x0022FE08;
int(*IFile_Read)(FILE *this, unsigned int *read, void *buffer, unsigned int size) = (void *)0x001686DC;
int(*svcSleepThread)(unsigned long long nanoseconds) = ((void *)0x0023FFE8);
int(*GX_SetTextureCopy)(void *input_buffer, void *output_buffer, unsigned int size, int in_x, int in_y, int out_x, int out_y, int flags) = ((void *)0x0011DD48);
int(*GSPGPU_FlushDataCache)(void *addr, unsigned int len) = ((void *)0x00191504);
//int(*svcControlMemory)(void **outaddr, unsigned int addr0, unsigned int addr1, unsigned int size, int operation, int permissions) = ((void *)0x001431A0);
int svcControlMemory(unsigned int* addr_out, unsigned int addr0, unsigned int addr1, unsigned int size, int op, int perm);
// Release the gpu handle that spider has
void releaseGpu(unsigned int address);
// Get version specific data
int getVersionData(unsigned int *kernelPatchAddress, unsigned int *svcPatchAddress, unsigned int *rebootAddress);
// Set-up the kernel mode environment
int setupKernelMode(void);
// Execute the function in kernel mode
int __attribute__((naked)) executeKernelMode(int (*function)(void));
// Gets called in kernel mode
int __attribute__((naked)) kernelModeStub(void);
// Gets called in kernel mode
// Put code in here
void kernelMode(void);
void gspwnCopy(void *dest, void *source, unsigned int size, unsigned int checkValue, unsigned int checkOffset);
int __attribute__((naked)) svcControlMemory(unsigned int* addr_out, unsigned int addr0, unsigned int addr1, unsigned int size, int op, int perm){
__asm__ __volatile__(
"push {r0, r4}\t\n"
"ldr r0, [sp, #0x8]\t\n"
"ldr r4, [sp, #0x8+0x4]\t\n"
"svc 0x01\t\n"
"ldr r2, [sp], #4\t\n"
"str r1, [r2]\t\n"
"ldr r4, [sp], #4\t\n"
"bx lr"
);
}
int main(void){
setupKernelMode();
executeKernelMode(kernelModeStub);
return 0;
}
int __attribute__((naked)) executeKernelMode(int (*function)(void)){
__asm__ (
"svc 8\t\n"
"bx lr\t\n"
);
}
void kernelMode(void){
unsigned int kernelPatchAddress = 0;
unsigned int svcPatchAddress = 0;
unsigned int rebootAddress = 0;
getVersionData(&kernelPatchAddress, &svcPatchAddress, &rebootAddress);
int (*reboot)(int, int, int, int) = (void *)rebootAddress;
reboot(0, 0, 2, 0);
}
int __attribute__((naked)) kernelModeStub(void){
__asm__(
"add sp, sp, #8"
);
kernelMode();
__asm__(
"movs r0, #0\t\n"
"ldr pc, [sp], #4"
);
}
int setupKernelMode(void){
unsigned int kernelPatchAddress = 0;
unsigned int svcPatchAddress = 0;
unsigned int rebootAddress = 0;
if(getVersionData(&kernelPatchAddress, &svcPatchAddress, &rebootAddress) == -1){
return -1;
}
int i;
unsigned int tempAddress;
unsigned int *buffer = (unsigned int *)0x18410000;
unsigned int memory;
svcControlMemory(&memory, 0, 0, 0x2000, 0x10003, 0x3);
unsigned int freeMemory = memory + 0x1000;
int (*nopFunction)(void);
svcControlMemory(&tempAddress, freeMemory, 0, 0x1000, 1, 0);
buffer[0] = 1;
buffer[1] = kernelPatchAddress;
buffer[2] = 0;
buffer[3] = 0;
gspwnCopy((void *)freeMemory, (void *)buffer, 0x10, kernelPatchAddress, 4);
svcControlMemory(&tempAddress, memory, 0, 0x1000, 1, 0);
for(i = 0; i < 0x1000; i++){
buffer[i] = 0xE1A00000; // nop
}
buffer[i - 1] = 0xE12FFF1E; // arm bx lr
nopFunction = (void *)0x08F02894 - 0x10000;
gspwnCopy((void *)buffer, (void *)nopFunction, 0x10000, 0xE1A00000, 0);
nopFunction();
}
int getVersionData(unsigned int *kernelPatchAddress, unsigned int *svcPatchAddress, unsigned int *rebootAddress){
// Get kernel version
unsigned int kernelVersion = *(unsigned int *) 0x1FF80000;
if(kernelVersion == 0x02220000){
*kernelPatchAddress = 0xEFF83C97;
*svcPatchAddress = 0xEFF827CC;
*rebootAddress = 0xFFF748C4;
return 0;
}else if(kernelVersion == 0x02230600){
*kernelPatchAddress = 0xEFF8372F;
*svcPatchAddress = 0xEFF822A8;
*rebootAddress = 0xFFF64B94;
return 0;
}else if(kernelVersion == 0x02240000){
*kernelPatchAddress = 0xEFF8372B;
*svcPatchAddress = 0xEFF822A4;
*rebootAddress = 0xFFF64B90;
return 0;
}else if(kernelVersion == 0x02250000){
*kernelPatchAddress = 0xEFF8372B;
*svcPatchAddress = 0xEFF822A4;
*rebootAddress = 0xFFF64A78;
}else if(kernelVersion == 0x02260000){
*kernelPatchAddress = 0xEFF8372B;
*svcPatchAddress = 0xEFF822A4;
*rebootAddress = 0xFFF64A78;
return 0;
}else if(kernelVersion == 0x02270400){
*kernelPatchAddress = 0xEFF8372F;
*svcPatchAddress = 0xEFF822A8;
*rebootAddress = 0xFFF64AB0;
return 0;
}else if(kernelVersion == 0x02280000){
*kernelPatchAddress = 0xEFF8372B;
*svcPatchAddress = 0xEFF822A4;
*rebootAddress = 0xFFF64AAC;
return 0;
}else if(kernelVersion == 0x022C0600){
*kernelPatchAddress = 0xDFF83767;
*svcPatchAddress = 0xDFF82294;
*rebootAddress = 0xFFF54BAC;
return 0;
}else if(kernelVersion == 0x022E0000){
*kernelPatchAddress = 0xDFF83837;
*svcPatchAddress = 0xDFF82290;
*rebootAddress = 0xFFF151C0;
return 0;
}
return -1;
}
// 0x003DA72C
// Thanks smealum!
void releaseGpu(unsigned int address){
__asm__ __volatile__ (
"mrc p15, 0, r8, c13, c0, 3\n"
"add r8, #0x80\n"
"ldr r0, =0x00170000\n"
"str r0, [r8], #4\n"
"ldr r0, =0x003DA72C\n"
"ldr r0, [r0]\n"
".word 0xEF000032\n"
);
}
void gspwnCopy(void *dest, void *source, unsigned int size, unsigned int checkValue, unsigned int checkOffset){
unsigned int result;
do{
GSPGPU_FlushDataCache(source, size);
GX_SetTextureCopy(source, dest, size, 0, 0, 0, 0, 8);
GSPGPU_FlushDataCache(dest, size);
GX_SetTextureCopy(dest, source, size, 0, 0, 0, 0, 8);
result = *(unsigned int *)(source + checkOffset);
}while(result != checkValue);
}
int START_SECTION entryPoint(){
__asm__ volatile(".word 0xE1A00000");
main();
__asm__ volatile("bx lr");
}
This is where I got most of the stuff for bootstrap from:
https://github.com/yifanlu/Spider3DSTools/tree/arm11-kernel-research
I just ported it to ninjhax really, which took a tiny bit of work but was fairly easy. ARM9 kernel though, that one took forever since I did that using a lot of disassembly and trial+error.
/*
Thanks a bunch for most of this yifanlu!
https://github.com/yifanlu/Spider3DSTools/blob/arm11-kernel-research/code.c
*/
#define START_SECTION __attribute__ ((section (".text.start"), naked))
// make sure code is PIE
#ifndef __PIE__
#error "Must compile with -fPIE"
#endif
int (*IFile_Open)
(void *this, const short *path, int flags)
= (void *)0x0022FE08;
int (*IFile_Write)
(void *this, unsigned int *written, void *src, unsigned int len)
= (void *)0x00168764;
int (*memcpy)
(void *dst, const void *src, unsigned int len)
= (void *)0x0023FF9C;
int (*GX_SetTextureCopy)
(void *input_buffer, void *output_buffer, unsigned int size, int in_x, int in_y, int out_x, int out_y, int flags)
= (void *)0x0011DD48;
int (*GSPGPU_FlushDataCache)
(void *addr, unsigned int len)
= (void *)0x00191504;
int (*svcSleepThread)
(unsigned long long nanoseconds)
= (void *)0x0023FFE8;
int (*svcControlMemory)
(void **outaddr, unsigned int addr0, unsigned int addr1, unsigned int size, int operation, int permissions)
= (void *)0x001431A0;
int main();
unsigned int getKernelVersion(void);
int getArm11KernelPatchAddress(void);
int getArm11RebootAddress(void);
void fillScreens(char red, char green, char blue);
int START_SECTION entryPoint() {
__asm__ volatile(
".word 0xE1A00000"
);
main();
__asm__ volatile(
"bx lr"
);
}
int gspwnCopy(void *dst, void *src, unsigned int len, unsigned int check_val, int check_off){
unsigned int result;
do{
memcpy((void *)0x18401000, (void *)0x18401000, 0x10000);
GSPGPU_FlushDataCache(src, len);
GX_SetTextureCopy(src, dst, len, 0, 0, 0, 0, 8);
GSPGPU_FlushDataCache((void *)0x18401000, 16);
GX_SetTextureCopy(dst, (void *)0x18401000, 0x40, 0, 0, 0, 0, 8);
memcpy((void *)0x18401000, (void *)0x18401000, 0x10000);
result = *(unsigned int *)(0x18401000 + check_off);
}while(result != check_val);
return 0;
}
int arm11KernelSetup(void){
unsigned int patchAddress;
unsigned int *buffer;
int i;
int (*nopFunction)(void);
// part 1: corrupt kernel memory
buffer = (int *)0x18402000;
// 0xFFFFFE0 is just stack memory for scratch space
svcControlMemory((void *)0xFFFFFE0, 0x18451000, 0, 0x1000, 1, 0); // free page
patchAddress = 0xDFF83837;//TODO getArm11KernelPatchAddress();
if(patchAddress == 0){
return 1;
}
buffer[0] = 1;
buffer[1] = patchAddress;
buffer[2] = 0;
buffer[3] = 0;
// overwrite free pointer
gspwnCopy((void *)0x18451000, buffer, 0x10u, patchAddress, 4);
// trigger write to kernel
svcControlMemory((void *)0xFFFFFE0, 0x18450000, 0, 0x1000, 1, 0);
// part 2: obfuscation or trick to clear code cache
for(i = 0; i < 0x1000; i++){
buffer[i] = 0xE1A00000; // ARM NOP instruction
}
buffer[i-1] = 0xE12FFF1E; // ARM BX LR instruction
nopFunction = (void *)(0x009D2000 - 0x10000); // 0x10000 below current code
gspwnCopy((void *)(0x19592000 - 0x10000), buffer, 0x10000, 0xE1A00000, 0);
nopFunction();
return 0;
}
// after running setup, run this to execute func in ARM11 kernel mode
int __attribute__((naked)) arm11KernelExecute(int (*func)(void)){
__asm__(
"svc 8\t\n" // CreateThread syscall, corrupted, args not needed
"bx lr\t\n"
);
}
void invalidateInstructionCache(void){
__asm__(
"mcr p15,0,%0,c7,c5,0\t\n"
"mcr p15,0,%0,c7,c5,4\t\n"
"mcr p15,0,%0,c7,c5,6\t\n"
"mcr p15,0,%0,c7,c10,4\t\n"
:: "r" (0)
);
}
void invalidateDataCache(void) {
__asm__(
"mcr p15,0,%0,c7,c14,0\t\n"
"mcr p15,0,%0,c7,c10,4\t\n"
:: "r" (0)
);
}
void invalidateCache(void) {
__asm__(
"mcr p15,0,%0,c8,c5,0\t\n"
"mcr p15,0,%0,c8,c6,0\t\n"
"mcr p15,0,%0,c8,c7,0\t\n"
"mcr p15,0,%0,c7,c10,4\t\n"
:: "r" (0)
);
}
int __attribute__((noinline)) arm11Kernel(void){
int i;
__asm__ volatile(
"clrex"
);
// fix up memory
*(int *)0xDFF8383F = 0x8DD00CE5;
invalidateInstructionCache();
invalidateCache();
fillScreens(0xFF, 0x00, 0x00);
//memcpy((void *)0xD848F000, (void *)0xFFF00000, 0x00038400);
//memcpy((void *)0xD84C7800, (void *)0xFFF00000, 0x00038400);
//memcpy((void *)0xE4410000, (void *)0xFFFF0000, 0x1000);
invalidateDataCache();
int (*reboot)(int, int, int, int);
// If we are this far, we do not need to check this!
reboot = 0xFFF151C0;//TODO (void *)getArm11RebootAddress();
fillScreens(0x00, 0x00, 0xFF);
// Time to reboot!
reboot(0, 0, 2, 0);
fillScreens(0x00, 0xFF, 0x00);
return 0;
}
int __attribute__((naked)) arm11KernelStub(void){
__asm__(
"add sp, sp, #8\t\n"
);
arm11Kernel();
__asm__(
"movs r0, #0\t\n"
"ldr pc, [sp], #4\t\n"
);
}
int main(){
if(arm11KernelSetup() != 0){
return 1;
}
arm11KernelExecute(arm11KernelStub);
return 0;
}
void fillScreens(char red, char blue, char green){
int i;
for(i = 0; i < 320*240*3; i += 3){
((char *)0xD848F000)[i] = green;
((char *)0xD848F000)[i+1] = blue;
((char *)0xD848F000)[i+2] = red;
((char *)0xD84C7800)[i] = green;
((char *)0xD84C7800)[i+1] = blue;
((char *)0xD84C7800)[i+2] = red;
}
}
// Version stuff
unsigned int getKernelVersion(void){
return *(unsigned int *) 0x1FF80000;
}
int getArm11KernelPatchAddress(void){
unsigned int kernelVersion;
kernelVersion = getKernelVersion();
switch(kernelVersion){
case 0x02220000:
return 0xEFF83C97;
case 0x02230600:
return 0xEFF8372F;
case 0x02240000:
case 0x02250000:
case 0x02260000:
case 0x02280000:
return 0xEFF8372B;
case 0x02270400:
return 0xEFF8372F;
case 0x022C0600:
return 0xDFF83767;
case 0x022E0000:
return 0xDFF83837;
default:
return 0;
}
}
int getArm11RebootAddress(void){
unsigned int kernelVersion;
kernelVersion = getKernelVersion();
switch(kernelVersion){
case 0x02220000:
return 0xFFF748C4;
case 0x02230600:
return 0xFFF64B94;
case 0x02240000:
return 0xFFF64B90;
case 0x02250000:
case 0x02260000:
return 0xFFF64A78;
case 0x02270400:
return 0xFFF64AB0;
case 0x02280000:
return 0xFFF64AAC;
case 0x022C0600:
return 0xFFF54BAC;
case 0x022E0000:
return 0xFFF151C0;
default:
return 0;
}
}
Is 0xFFF151C0 the reboot address for 9.2? It gets to that then crashes...
It won't reboot unless a particular offset is patched. And also the reboot offset is different from yifanlu's writeup.
Oh, interesting...
I am using the 9.2 one, the 4.1 is 0xFFF748C4, correct?
Your offset is right, yes. That function alone though will just crash your 3DS, one of the patches in firmlaunch hax actually allows it to reboot, and the other hooks the point where ARM9 finishes checking the offset to boot into.