Announcement

Collapse
No announcement yet.

Misc. Wii code snippets by tueidj

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Misc. Wii code snippets by tueidj

    Over the past few years I've written a lot of wii code that has been kept private for various reasons. I think it might be time to show some of it off and give somebody else the chance to do something useful with it. Having said that, all code posted here falls under the following licence:


    Code:
    Code:
    /* Copyright 2013 tueidj All Rights Reserved
     * This code may not be used in any project
     * without explicit permission from the author.
     */
    	
    		
    
    
    Lesson 1: Loading your own IOS module into the currently running IOS
    Most people know IOS runs on its own dedicated CPU - an ARM926EJ-S commonly known as Starlet. For the majority of the time, Starlet sits in an idle loop waiting for interrupts - why not give it some real work to do by making IOS run some custom code?
    First you need to be able to modify the existing IOS code. This requires the MEM2 protection to be disabled, which needs AHBPROT disabled. HBC can take of AHBPROT and the rest is fairly trivial.
    Since the ES module is the only part of IOS that is "allowed" to load a new module, we're going to modify one of its ioctls. Choosing which one is pretty simple; it should be one that isn't used under normal conditions, it should have uniquely identifiable code (so we can find where it is in memory) and there should be plenty of space for us to overwrite with our own code. ES_ImportBoot2 fits these requirements - it's used to upgrade boot2 which no regular application will want to do.
    After deciding which ioctl to overwrite all we need to do is write our custom IOS module to the wii's NAND (the /tmp directory is a good choice) and use the following function:
    		
    	
    Code:
    #define ES_MODULE_START     ((u8*)0x939F0000)
    #define ES_MODULE_SIZE      0x20000
    static int load_module_file(s32 es_fd, const char *filename)
    {
       // this is the original code for the ES_ImportBoot2 ioctl
       const u8 old_es_code[24] = {
          0x68, 0x4B, 0x2B, 0x06, 0xD1, 0x0C, 0x68, 0x8B, 0x2B, 0x00,
          0xD1, 0x09, 0x68, 0xC8, 0x68, 0x42, 0x23, 0xA9, 0x00, 0x9B,
          0x42, 0x9A, 0xD1, 0x03};
    
       // this is the code that will overwrite it
       const u16 load_module[12] =
       {
          0x68CE, // ldr r6, [r1, #0x0c]   ; ipcmessage.vec
          0x6830, // ldr r0, [r6]         ; vec[0].data (filename of module)
          0x4778, // thumb->arm (BX PC)
          0x46C0, // nop (for alignment, assumes this block starts 4-byte aligned)
          0xE600,   0x0B50, // syscall_5a (load_ios_module)
          0xE28D,   0xD020, // ADD SP, SP, #0x20
          0xE8BD,   0x4070, // LDMFD SP!,{R4-R6,LR}
          0xE12F,   0xFF1E, // BX LR
       };
    
       u8 *addr;
       s32 ret=1;
       ioctlv vec;
    
       for (addr=ES_MODULE_START;addr < ES_MODULE_START+ES_MODULE_SIZE-sizeof(old_es_code);addr++) {
          if (!memcmp(addr, old_es_code, sizeof(old_es_code))) {
             memcpy(addr, load_module, sizeof(load_module));
             DCFlushRange((void*)((u32)addr&~0x1F), 32);
             vec.data = (void*)filename;
             vec.len = strlen(filename)+1;
             // call ES_ImportBoot2 with the module filename as a parameter
             ret = IOS_Ioctlv(es_fd, 0x1F, 1, 0, &vec);
    
             // restore the old code and flush
             memcpy(addr, old_es_code, sizeof(load_module));
             DCFlushRange((void*)((u32)addr&~0x1F), 32);
             break;
          }
       }
    
       return !ret;
    }


    If the function returns 1 it succeeded, you should be able to communicate with your IOS module using regular IPC calls - you did make it register a device name, right?
    Last edited by 47iscool; 07-01-2013, 01:24:41 AM.
Working...
X