NokiDoki

Shine Spawn Cutscene Underflow ACE

May 19th, 2020 (edited)
1,780
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.26 KB | None | 0 0
  1. By starting a Shine Get cutscene while another cutscene is playing, the game will terminate more cutscenes than it started, resulting in previous cutscenes (or garbage data) being played before the savebox. I call this glitch Cutscene Underflow. More info (read the description): https://www.youtube.com/watch?v=xhUd0e0Sgwo
  2.  
  3. What if you replay a cutscene in a different area than it was originally played? For most cutscenes, nothing interesting happens: either they play normally, or they end instantly, depending on whether the associated camera movement filename was overwritten in the transition or not. But some cutscenes retain a callback to execute before and after the cutscene (even if the camera movement couldn’t be found), and a pointer to a relevant object to be passed to the callback. Most notably, Shine spawns keep a pointer to the Shine being spawned.
  4.  
  5. There are limitations to cross-area cutscene underflow: FMVs and episode selections will overwrite all cutscene slots with data from the disc, which has a very low chance of leading to anything but a crash. That means the plaza is basically the only usable target for this. Additionally, since the cutscene count will reset to 0 on any area transition, and it takes at least 2 cutscenes to trigger cutscene underflow, the Shine needs to be spawned after at least 2 other cutscenes, and Shine spawns that can't fit this criterion (e.g. Pinna 1 as it spawns too fast after you enter the area) cannot be used.
  6.  
  7. At the beginning of a Shine spawn cutscene, its callback will lead to one of the Shine’s virtual functions, TMapObjBase::makeObjAppeared, being called. When replaying the cutscene with cross-area cutscene underflow, its Shine pointer will be stale and the virtual call can be redirected to arbitrary code. Let S be the Shine pointer; *S will be read as a pointer to the Shine’s virtual table, and *(*S + 0x100) will be set as the instruction pointer. The conditions to make this ACE happen in the game are yet to be determined, with 426 different Shine addresses being identified as usable for this, but some things can already be said about the payload.
  8.  
  9. Context:
  10. - r0 contains the return address of TMapObjGeneral::appear (read-only; PAL:801b5004)
  11. - r3, r30 and r31 contain the Shine pointer;
  12. - r4 contains the word at offset 0x18c from the Shine pointer;
  13. - r5, r6, r7, r27, r28 and r29 contain 0xFFFFFFFF;
  14. - r8, r19, r23 contain 4;
  15. - r9 contains the horizontal camera angle;
  16. - r12 contains the address of the payload;
  17. - r14, r15, r16, r17, r18, r21, r24 and r25 contain 0;
  18. - r20 contains gpApplication + 0x2c (very useful for setting the next area or FMV);
  19. - r26 contains gpMarDirector.
  20.  
  21. Preventing a crash in the rest of the callback: the Shine spawn callback does a couple more things after the payload runs, still assuming that it’s dealing with a TShine instance.
  22. - `blr`: unsafe, requires other fields to be valid pointers
  23. - branch to the end of TMapObjGeneral::appear (PAL:801abfb8): safer, might only require certain floats to not be NaN or infinite?
  24. - `addi sp,sp,0x28` then branch to the end of TShine::appearWithTime (PAL:801b51d4): very safe, barely any side effects
  25.  
  26. Preventing a crash if not all cutscene slots are filled: `stb r14, 0x24d(r26)` will reset the cutscenes ended index to 0, skipping the later slots.
Add Comment
Please, Sign In to add comment