Animal Crossing is a social simulation video game series developed and published by Nintendo. It has many iterations including GameCube, Wii and Switch versions. The focus of this article is on the GameCube version of the game.
While exploring Animal Crossing in on the Dolphin emulator, the author wanted to know how the NES emulator in the game works. From a tiny bit of reversing, the game has small NES ROM image within the game. This means that the game itself contains a custom NES emulator. But, how does the emulator load the game and how does it know which game to load?
The author used the Dolphin GameCube emulator to force jump to the section that would load the ROM. The game itself it stored on a memory card when it tries to load the ROM, which can be seen in the crash logs. Now, we know that the game itself it stored on a memory card when it tries to load the ROM.
After some more reversing, the author found the location where the game was being loaded from the memory card: offset 0x642. After adding a ROM to this memory card location with the proper magic file headers, most NES games booted up. At this point, the author has a Save Game attack vector: what can we do with this?
The author was interesting in spotting a Save Game exploit that would cause enough memory corruption to take over the GameCube. From messing around with special tag functionality, the author noticed complex memory manipulation for loading metadata with dubious calls to memcpy. Because of this, they started bug hunting in this area.
The NES is a 16-bit system. So, most of the offsets for values were only 16 bits long away. However, the QDS parsing area loads a 24-bit offset. One issue has a maximum value of 0xFFFFFF, which is much larger than the boundary of the ROM. But, because this write zeros everything out first then later does the write, this did not look like a good option to pursue. There were many other deadends that would simply cause crashes but nothing exploitable.
Eventually the author found the PAT tag, which was by far the most complicated of all of the tags. A PAT tag has a 8-bit type, 8-bit patch size and a 16-bit offset value, followed by the patch data. Using this patch code, it would be possible to edit the NES game being loaded on the current platform.
The patch address validation is flawed! Because of the poor validation, it allows us to overwrite arbitrary data on the heap from 0x80000000 - 0x807FFFFF with the format described above. Because Animal Crossing loads in this space, we can use the patching functionality to overwrite arbitrary locations inside of Animal Crossings game on the GameCube. This is a complete emulator escape!
Patching data is trivial. But, what if we want to patch the game? Because of the Instruction Cache on the CPU, overwriting the instructions does not do anything to start with. To get around this issue, the author overwrite a function pointer within malloc to divert the flow of execution. Because the pointer was now changed, we could point it to our own code to do whatever we wanted within Animal Crossing.
To wrap this up, there are few interesting reversing tips that should be pointed out:
- Error messages go a long ways when debugging.
- Files and parsers LOVE magic values, such as AA55 for bootloaders.
- Dynamic debugging is the way to go in order to hit normally unreachable code paths. This will help you see if something is worth your time or not.
This is an awesome post on a 20 year old game console that I grew up on as well. Emulation is tricky to do, which is why this exploit works in the first place.