Mushihimesama Futari Reverse Engineering Notes
The game is composed of multiple XEX files. default.xex contains the main menu and I/O logic (rendering, sound, gamepads...), while the individual game modes are contained in the xex files inside the media/Module directory. In particular, reco_abnormal.xex contains the 1.5 Xbox 360 mode, while reco_normal.xex contains the 1.5 Arcade mode.
This article mostly focuses on the 1.5 Xbox 360 mode (reco_abnormal.xex).
Here are some of the memory regions I could identify:
0x41030000~0x431bffff: Stack memory
0x82000000~0x8205ffff: default.xex - header
0x82060000~0x821dffff: default.xex - code
0x821e0000~0x821fffff: default.xex - data (static memory)
0x82200000~0x822affff: default.xex - resources
0x88000000~0x8806ffff: reco_abnormal.xex - header
0x88070000~0x8824ffff: reco_abnormal.xex - code
0x88250000~0x887affff: reco_abnormal.xex - data (static memory)
0xf67bb000~0xf68dcfff: Heap memory (allocated by FUN_880836d0)
If you are running the game in the Xenia emulator, the Xbox360 memory will be mapped at offset 0x100000000 of the Xenia process.
Reverse Engineering Mushihimesama Futari for Xbox 360
The simplest method to open an Xbox 360 game in Ghidra / IDA Pro is to dump the decrypted executable out of a xex file using xextool, and then opening the resulting file. However, this only gives you access to the code and constant resources of the game, but not to the entire memory map.
My preferred method is to run the game in the xenia emulator, get to a place in the game where something interesting is happening, and then use a debugger (like Cheat Engine) to dump the memory of the xenia process from 0x100000000 to 0x200000000 and open that in Ghidra / IDA. This gives you the full state of the game, including all the variables captured at the moment of the dump.
The maximum score reachable in Mushihimesama Futari 1.5 is 3999999999. This is due to the code in the function player_add_score(player_t *player, uint32_t score) at 0x88134250 which clamps any score above 4 billions.
Removing the counter stop code would only increase the maximum reachable score to 4294967295 (and cause an overflow back to 0 after reaching it) because the score is stored in a 32-bit unsigned integer (at 0x884d6d60, or player_offset + 0x18). Moreover, it is impossible to simply increase the storage type for the player score because the memory areas immediately before and after the player score are used by other player variables.
Fixing the counterstop requires two modifications to the game:
- The overflowing score must be saved somewhere else.
- The code that renders the player score must be modified to take into account the saved overflowed score.
Counter Stop Patch
I developed a patch which removes the counterstop in Mushihimesama Futari for the Xbox 360: Counterstopless Futari Patch.
My patch removes the original score clamping code and replaces it with a function which decrements the player score by 1 billion. The number of times that this decrement happens is saved at 0x887afffc. Once per frame, when the score for player1 is rendered, the patch adds the number of times the decrement happened to the billions digit of P1 score.
This patch only works correctly for player 1, and the score shown in the high-score and in the replay list will be wrong, so I only recommend using it for viewing counterstopped replays.
To compile the patch, you will need xextool (to decrypt the original xex file), cygwin (to run the Makefile) and powerpc-eabi-gcc (to compile the code).
First, create a backup copy of reco_abnormal.xex, then edit the Makefile and change the variable UNPACHED_XEX (point it to the backup you just created), then compile the patch with make. If the compilation is successful, the patched reco_abnormal.xex will appear in the build directory.
Extended training mode patch
This patch adds some extra features to the training mode in both Mushihimesama Futari 1.5 and 1.01, as well as fixing the counter stop: Futari Training Mode Patch. Compiling it requires the same prerequirites as the basic counter stop patch (cygwin, xextool, powerpc-eabi-gcc).
Once the patch is installed, hold Back+LT to prevent enemies from spawning, Back+LB to enable invincibility and/or Back+RB to disable enemy bullets and enable fast-forward mode. It works on the Xbox 360 modes of both 1.5 and 1.01, but not for the Arcade, Black Label and Novice versions.
Slowdown in the Xbox 360 version
The slowdown in the xbox 360 version of Mushihimesama Futari is emulated by rendering the same frame multiple times. The function at 0x88168fa0~0x88169757 of reco_abnormal.xex returns how many times the current frame needs to be rendered.
792 constant float coefficients stored at 0x88008870~0x880094cf are multiplied by different variables (such as number of bullets on screen or number of pixels blitted this frame) to compute the number of times the current frame is going to be rendered. These coefficients are grouped in 36 structures of 22 coefficient each, and a different group is used during different stages and bosses for different game modes.
Each structure of 22 slowdown coefficients starts at 0x88008870 + 88 * (12*game_mode_index + 2*stage_index + currently_fighting_boss).
- game_mode_index is the byte at 0x887ad5ad and goes from 0 (original) to 2 (ultra);
- stage_index is the byte at 0x887ad5ab and goes from 0 (stage 1) to 4 (stage 5);
- currently_fighting_boss is the byte at 0x887ad5ac and goes from 0 (not fighting a boss) to 1 (fighting a boss), except for the TLB which makes this byte take values 2 (first phase) and 3 (second phase).
While I didn't reverse engineer how each coefficient influences the slowdown, here are some examples of what these coefficients do:
- slowdown_coeffs weight for the slowdown caused by the number of player bullets (at 0x887ad1cc). The bigger this coefficient is, the more slowdown will be introduced.
- slowdown_coeffs weight for the slowdown caused by the number of enemy bullets (at 0x887ad1a4). The bigger this coefficient is, the more slowdown will be introduced.
- slowdown_coeffs[8,9,10] thresholds that are compared with several values and, if exceeded, introduce slowdown. The smaller these coefficients are, the more slowdown will be introduced.