zeldaTp.dat exploit analysis (part 1 of ?)

Since a source release for either of the major hombrew methods does not seem to be forthcoming from the original creators, I've started reverse engineering the zelda exploit. My ultimate goal is to create a hombrew method which anyone is free to build from source code. I will be concentrating on the 'rzde2' version of the Twilight Hack, since that's the disc version I own.

wiifuse_server+net has been a valuable ally so far, and I also have to thank Segher for releasing zelda-cksum in his git tree.

I've found a few things so far:

Before I looked at the disassembly, I had in mind what the exploit might look like; from a glance at this code, it seems that the twiizers team has done something rather more complicated. Basically, I had imagined that the exploit would amount to code implementing

int x = ISFS_Open("/title/.../boot.bin")
ISFS_Read(x, boot_base, boot_size);
boot_base();
(assuming something like ISFS is in Zelda as a recognizable API). This might assemble to as few as a dozen instructions. However, there are quite a few more instructions there -- over 500 bytes worth of stuff that is superficially valid code. I've taken a look at the disassembly and written some notes:
     2b4:       33 80 45 1c     addic   r28,r0,17692
     2b8:       a0 53 53 53     lhz     r2,21331(r19)
     2bc:       53 53 53 53     rlwimi. r19,r26,10,13,9
     2c0:       3c 20 80 80     lis     r1,-32640
     2c4:       38 00 00 00     li      r0,0
     2c8:       94 01 ff c0     stwu    r0,-64(r1)
                                                            (0x807fffc0) = 0
     2cc:       7c 68 02 a6     mflr    r3
                                                            r3 <= lr
     2d0:       48 00 00 40     b       _t1

video_clear: // sets the i2cReg and then sets 640*576*2 bytes of memory to in R3

     2d4:       3d 20 cd 80     lis     r9,-12928
     2d8:       61 29 00 c0     ori     r9,r9,192
                                                            r9 <= 0xcd8000c0            // i2cReg + 48 -- SCL
     2dc:       80 09 00 00     lwz     r0,0(r9)
                                                            r0 <= *r9
     2e0:       7c 00 04 ac     sync    
     2e4:       68 00 00 20     xori    r0,r0,32            r0 <= r0 ^ 32
     2e8:       90 09 00 00     stw     r0,0(r9)
                                                            *r9 <= r0                   // toggle SCL?
     2ec:       7c 00 06 ac     eieio
     2f0:       3c 00 00 02     lis     r0,2
     2f4:       3d 20 c0 f0     lis     r9,-16144           r9 <= 0xc0f00000
     2f8:       60 00 d0 00     ori     r0,r0,53248         r0 <= 0x2d000

video_loop:
     2fc:       34 00 ff ff     addic.  r0,r0,-1            r0 <= r0 - 1
     300:       90 69 00 00     stw     r3,0(r9)            *r9 <= r3
     304:       39 29 00 04     addi    r9,r9,4             r9 <= r9+4
     308:       40 a2 ff f4     bne-    0x2fc               if(r0) goto loop
     30c:       4e 80 00 20     blr

_t1:                                                        sploit(r3 = void *lr) {
     310:       7c 08 02 a6     mflr    r0
                                                            r0 <= lr
     314:       94 21 ff e0     stwu    r1,-32(r1)
                                                            (0x87fffa0) = 0x87fffc0
     318:       3d 20 80 00     lis     r9,-32768
                                                            r9 = 0x80000000
     31c:       bf 41 00 08     stmw    r26,8(r1)
                                                            store regs r26..r31 starting at 0x87fffc8
     320:       61 29 00 03     ori     r9,r9,3
                                                            r9 = 0x80000003
     324:       90 01 00 24     stw     r0,36(r1)
                                                            (0x87fffc4) = lr
     328:       88 09 00 00     lbz     r0,0(r9)
                                                            r0 = (0x80000003) -- region code of game ID?
     32c:       2f 80 00 45     cmpwi   cr7,r0,69       
     330:       41 9e 00 10     beq-    cr7,0x340           region 'E'
     334:       2f 80 00 50     cmpwi   cr7,r0,80
     338:       41 9e 00 40     beq-    cr7,0x378           region 'P'
     33c:       48 00 00 38     b       0x374               unknown region

region_e:
     340:       6c 60 80 45     xoris   r0,r3,32837
     344:       2f 80 19 e0     cmpwi   cr7,r0,6624         r3 (old lr) == 0x804519e0
     348:       40 9e 00 18     bne-    cr7,0x360           flavor 1
flavor_2:
     34c:       3d 20 80 36     lis     r9,-32714
     350:       3b 49 c1 48     addi    r26,r9,-16056       r26 = 0x8036c148
     354:       3d 20 80 36     lis     r9,-32714
     358:       3b 89 c9 88     addi    r28,r9,-13944       r28 = 0x8036c988
     35c:       48 00 00 2c     b       0x388               goto common
flavor_1:
     360:       3d 20 80 37     lis     r9,-32713
     364:       3b 49 17 10     addi    r26,r9,5904         r26 = 0x80371710
     368:       3d 20 80 37     lis     r9,-32713
     36c:       3b 89 1f 50     addi    r28,r9,8016         r28 = 0x80371f50
     370:       48 00 00 18     b       0x388               goto common
die:
     374:       48 00 00 00     b       0x374               loop forever
region_p:
     378:       3d 20 80 36     lis     r9,-32714    
     37c:       3b 49 c5 78     addi    r26,r9,-14984       r26 = 0x8036c578
     380:       3d 20 80 36     lis     r9,-32714
     384:       3b 89 cd b8     addi    r28,r9,-12872       r28 = 0x8036cdb8


common:
     388:       3c 60 26 6a     lis     r3,9834
     38c:       3f a0 80 45     lis     r29,-32699
     390:       60 63 26 c0     ori     r3,r3,9920          r3 =  0x266a26c0
     394:       3b bd 1e c0     addi    r29,r29,7872        r29 = 0x80451ec0
     398:       4b ff ff 3d     bl      0x2d4
                                                            call video_clear -- clear to maroon
     39c:       3c 60 80 45     lis     r3,-32699
     3a0:       7f 89 03 a6     mtctr   r28                 ctr <= r28 (second region/flavor dependent function)
     3a4:       7f a4 eb 78     mr      r4,r29              r4 <= r29
     3a8:       38 a0 00 01     li      r5,1                r5 <= 1
     3ac:       38 63 1f c0     addi    r3,r3,8128          r3 <= 0x80451fc0        // filename pointer
     3b0:       3f c0 40 80     lis     r30,16512
     3b4:       3f e0 90 00     lis     r31,-28672
     3b8:       3f 60 c0 80     lis     r27,-16256
     3bc:       63 de 40 80     ori     r30,r30,16512       r30 <= 0x3f184080
     3c0:       63 ff 00 20     ori     r31,r31,32          r31 <= 0x90000020
     3c4:       63 7b c0 80     ori     r27,r27,49280       r27 <= COLOR_SILVER
     3c8:       4e 80 04 21     bctrl                       call  df1 // open loader.bin?
                                                                        df1(r3="loader.bin",
                                                                            r4=handle? (after code, 256 bytes before loader.bin), 
                                                                            r5=1 (read in ISFS_Open))
     3cc:       3c 60 71 40     lis     r3,28992
     3d0:       60 63 71 8a     ori     r3,r3,29066         r3 <= 0x7140718a
     3d4:       3b 80 00 00     li      r28,0               r28 <= 0
     3d8:       4b ff fe fd     bl      0x2d4               call video_clear        // clear to OLIVE

read_loop:
     3dc:       7f c3 f3 78     mr      r3,r30              r3 <= r30
     3e0:       4b ff fe f5     bl      0x2d4               call video_clear        // clear to ????

// Cache buster -- clear cache for physical range about to be read
     3e4:       39 3f 10 1f     addi    r9,r31,4127         r9 <= 0x4000101f
     3e8:       55 29 00 34     rlwinm  r9,r9,0,0,26        r9 <= r9 & ~0x1f
     3ec:       57 e0 00 34     rlwinm  r0,r31,0,0,26       r0 <= r31 & ~0x1f
     3f0:       7d 20 48 50     subf    r9,r0,r9            r9 <= byte count r9 .. r31
     3f4:       55 29 d9 7e     rlwinm  r9,r9,27,5,31       r9 <= r9 >> 5
     3f8:       39 29 00 01     addi    r9,r9,1             r9 <= r9 + 1  // size in 0x20 blocks, rounded up
     3fc:       7d 29 03 a6     mtctr   r9                  and move to counter register
     400:       7f e9 fb 78     mr      r9,r31              r9 <= 0x40000020
     404:       48 00 00 0c     b       0x410               
loop2:
     408:       7c 00 48 ac     dcbf    r0,r9
     40c:       39 29 00 20     addi    r9,r9,32
     410:       42 00 ff f8     bdnz+   0x408

     414:       7c 00 04 ac     sync    

     418:       38 a0 10 00     li      r5,4096             
     41c:       7f e4 fb 78     mr      r4,r31
     420:       7f 49 03 a6     mtctr   r26
     424:       7f a3 eb 78     mr      r3,r29          
     428:       3b ff 10 00     addi    r31,r31,4096
     42c:       4e 80 04 21     bctrl                       r3 <= read(handle?, 0x50000020, 4096) // read block?
     430:       3d 3e 14 ab     addis   r9,r30,5291         r9 = r30 + (5291<<16) /* 0x14ab0000 */
     434:       7f 9c 1a 14     add     r28,r28,r3          r28 += r3
     438:       38 69 14 95     addi    r3,r9,5269          r3 = r9 + 5269
     43c:       4b ff fe 99     bl      0x2d4               clear to a color dependant on return value?
     440:       3d 3e 02 00     addis   r9,r30,512          r9 = r30 + 0x2000200
     444:       3b c9 02 00     addi    r30,r9,512          r30 = r9 + 0x2000200
     448:       7f 9e d8 00     cmpw    cr7,r30,r27         
                                                           // did the compiler come up with this f***ed up loop termination
                                                            // or is there a human to blame?
     44c:       40 9e ff 90     bne+    cr7,0x3dc           if(r27 != r30) goto read_loop  // 64 loops?

     450:       3c 60 c3 99     lis     r3,-15463
     454:       60 63 c3 6a     ori     r3,r3,50026
     458:       4b ff fe 7d     bl      0x2d4               clear to SKYBLUE
     45c:       3d 3c 90 00     addis   r9,r28,-28672       .. and at this point boredom set in
     460:       39 29 00 3f     addi    r9,r9,63            .. because it looks like we're home free
     464:       3d 60 90 00     lis     r11,-28672
     468:       55 29 00 34     rlwinm  r9,r9,0,0,26
     46c:       61 6b 00 20     ori     r11,r11,32          r11 = 0x90000020
     470:       3d 29 70 00     addis   r9,r9,28672
     474:       39 29 ff e0     addi    r9,r9,-32
     478:       55 29 d9 7e     rlwinm  r9,r9,27,5,31
     47c:       39 29 00 01     addi    r9,r9,1
     480:       7d 29 03 a6     mtctr   r9                  r9 = how much to clear, in cache lines
     484:       48 00 00 10     b       0x494

loop3:                                                      // flush data cache
     488:       7c 00 58 6c     dcbst   r0,r11
     48c:       7c 00 5f ac     icbi    r0,r11
     490:       39 6b 00 20     addi    r11,r11,32
     494:       42 00 ff f4     bdnz+   0x488

     498:       7c 00 04 ac     sync    
     49c:       4c 00 01 2c     isync
     4a0:       3c 00 90 00     lis     r0,-28672
     4a4:       39 20 01 23     li      r9,291
     4a8:       60 00 00 20     ori     r0,r0,32
     4ac:       7d 23 4b 78     mr      r3,r9
     4b0:       7c 09 03 a6     mtctr   r0
     4b4:       4e 80 04 21     bctrl                       call 0x90000020 (r3=291) -- loader.bin?
     4b8:       3c 60 4c 54     lis     r3,19540            returned from loader.bin?  unpossible!
     4bc:       60 63 4c ff     ori     r3,r3,19711         
     4c0:       4b ff fe 15     bl      0x2d4               clear to RED
     4c4:       48 00 00 00     b       0x4c4               ... and die
OK, a bit more than a dozen instructions, but not far off from what I thought. There's code to set the screen color and some kind of I/O as each step of the load occurs. There's code to switch between the different code versions supported (E0, E2, P). And there's a lot of cache-related code that I would never have figured out on my own.




Entry first conceived on 9 June 2008, 22:29 UTC, last modified on 15 January 2012, 3:46 UTC
Website Copyright © 2004-2024 Jeff Epler