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
(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:int x = ISFS_Open("/title/.../boot.bin") ISFS_Read(x, boot_base, boot_size); boot_base();
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.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