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:
- It looks like the bytes 0x2b5..0x2b8 are what end up in the program counter after the overflow, making the start of the exploit code be at address 0x80451ca0
- It looks like the instruction starting at 0x2c0 is part of the exploit code, although the code as far back as 0x1d0 looks like it might be safe to execute. In any case, modifying the bytes at 0x2c0 to 'lwz r1,0(0)' cause the game to crash instead of starting the twilight hack.
- The exploit code is after the end of the NUL-terminated string, so there's no apparent need for the zero-avoidance tricks that are the focus of many ppc-exploit documents.
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
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