Note that this exploit was never finished, but I'm releasing my notes on it in case anyone might find it useful.
Writing this article has been rolling around in my head for almost six months now. Since Wii homebrew currently lacks an exploit which works on every system menu version without the need for a game it is absolutely necessary to have as many options available to users in order to eliminate the stress and pain of hunting for a specific game. I've learned a great deal about the process of writing a savegame exploit for Wii by talking with svpe, AerialX, megazig, Treeki, and many others and in the past made a bit of progress poking around with their assistance. I've really, really wanted to go through and do a completely original new savegame exploit for quite some time now meanwhile being able to share my knowledge and insight I've gained on the process. So I finally decided to drop DOP-Mii, DeSmuME, and my other projects for awhile to follow through on this idea. Enter: This article. Along with trying to make this as insightful and useful as possible, I really hope that everyone enjoys reading it as much as I did writing it.
Picking a Target Game
The easiest way to exploit a savegame is to do so by creating a buffer overflow. This is done by taking a string stored in the file and giving it more characters than it's maximum allowed amount. So when picking a game to create an exploit for you should choose one that you know stores strings in order to minimize your risk of wasting your time for nothing. My target game is going to be Silent Hill: Shattered Memories not only because it's a cool and fairly popular game, but because I know the savefile stores at least one string which the game will not let me increase the length of infinitely (the player's name).
Obtaining an ISO
The easiest way to obtain an ISO of your target game is to run emukidid's CleanRip which will rip an ISO from your disc right to your attached USB Hard Drive.
Obtaining the main.dol
After getting the ISO we need to get the main.dol, the main executable, from it. To do this open the ISO with WiiScrubber and extract it.
Obtaining an Unencrypted Savegame
The first step to getting a savegame is to, well, play the game. I recommend you put at least several hours of play time in so you fill up your savefile with lots of interesting content.
Unfortunately, you can't just drop a savegame onto your SD Card and then presume to play with it. The savefile is encrypted when it is moved to the SD Card so any changes you make to it will cause it to not be recognized by the Wii. Luckily, savegames are stored unencrypted on the Wii's NAND.You can use my Savegame Manager MOD tool to copy an unencrypted savegame from the Wii's NAND to your SD Card. You can put it back onto your Wii by using Savegame Manager MOD to transfer it back.
There is a ton of readable plaintext including literally about a hundred strings in the Silent Hill Shattered Memories save file. I could read the names of the players I entered and I could see names of pictures and other items I had acquired as well as the names of events I had chosen and places I had been. I tried editing the strings and using the edited savefile. Silent Hill spewed out an error that the data was corrupt and could not be read. This meant that there was a checksum present in the savefile. A checksum is a value calculated by running data present in the savefile through an algorithm. When Silent Hill loads a savefile it runs the checksum algorithm and then looks at the checksum in the savefile and sees if the checksums match eachother. If they match, Silent Hill runs the savefile; If not, it spits out an error about the data being corrupt. Despite needing to figure out how the checksum is calculated, this is a very encouraging sign. If you're familiar with hashing, you can think of a checksum has the hash produced by hashing a certain section (or all) of the data.
Reversing the main.dol in IDA Pro into PPC Assembly
To uncover how checksums are calculated in Silent Hill we'll use IDA Pro to reverse the main.dol into PPC assembly and study the assembly to uncover the checksum algorithm. In order to use IDA Pro to reverse the main.dol you're going to need the DOL Loader and Gekko CPU extension installed. There are copies of them here but if those aren't correct for your version of IDA or you can't compile with the IDA SDK then come on over to #wiidev on EFNET and someone should be able to help you out. If necessary, you should be able to use versions of them lower than your version of IDA Pro and they will work. Place the DOL Loader in IDA/loaders and place the Gekko CPU extension in IDA/plugins .
Now once everything is setup properly it's time to reverse the main.dol into PPC assembly with IDA. Start IDA Pro and select to disassemble a new file. Goto the file dropdown menu and select to load a file. Load the main.dol and make sure it is recognized as Gamecube DOL and finally select Ok to the prompts to load it as one. Once it is loaded successfully by IDA, you should see something like this:
Now that the main.dol has been reversed into PPC assembly there are a number of techniques we can use to locate where the checksum is calculated. One such method would be searching for text with Read, or Write in it. Personally, I think the most accurate and easiest way is to use Megazig's Wii Tools.
Using Megazig's Wii Tools
In order to use them you first have to compile them. If you're on Linux and you have GCC installed then just use make. If you're on Windows you can compile them under cygwin. I don't use Mac operating systems so you're on your own if you do. But it shouldn't be even remotely difficult.
Once compiled we'll run these two commands and examine their output:
./mega_info_creator --dol nand.mega main.dol
./mega_info_creator --dol nand2.mega main.dol
This is the output I received:
Using this output we can now see where Write and Read calls are made to the NAND. Since the checksum algorithm will have to be used just before and just after these calls are made respectively we can go back to the disassembly in IDA with a pretty clear place of where to look for the checksum.
Back to IDA Pro
The first thing I do with my dissassembly after getting info from Megazig's Wii Tools is to rename functions to give me a better sense of what's going on. For example, I jump to address 80244280 click sub_80244820, press I on my keyboard, and then rename it to NANDRead. IDA will rename every call to this subroutine NANDRead making it easy for me to remember what to search for to find each call. To make things easier on me, I ran mega_info_creator with many more .mega files and I renamed a lot of subroutines.
The savefile format used for Silent Hill is extremely confusing; There are a ton of plaintext strings embedded with lots of garbage looking data. Presumably this garbage data is somehow encrypted to further prevent modification. I'm not particularly interested in it though, all I'm really interested in is being able to edit strings. I'm still relatively new to reverse engineering Wii software so eventually I called upon the help of veteran reverse engineer Treeki.
Treeki noticed a handful of interesting pieces of data starting at address 803E0320:
.data6:803E0320 .long aEcmd_idle # "eCmd_Idle"
.data6:803E0324 .long aEcmd_checkcard # "eCmd_CheckCard"
.data6:803E0328 .long aEcmd_openfile # "eCmd_OpenFile"
.data6:803E032C .long aEcmd_closefile # "eCmd_CloseFile"
.data6:803E0330 .long aEcmd_readfile # "eCmd_ReadFile"
.data6:803E0334 .long aEcmd_createfil # "eCmd_CreateFile"
.data6:803E0338 .long aEcmd_writefile # "eCmd_WriteFile"
.data6:803E033C .long aEcmd_seekfile # "eCmd_SeekFile"
.data6:803E0340 .long aEcmd_deletefil # "eCmd_DeleteFile"
.data6:803E0344 .long aEcmd_checkcrc # "eCmd_CheckCRC"
.data6:803E0348 .long aEcmd_checkspac # "eCmd_CheckSpace"
.data6:803E034C .long aEcmd_createdir # "eCmd_CreateDir"
.data6:803E0350 .long aEcmd_deletedir # "eCmd_DeleteDir"
.data6:803E0354 .long aEcmd_msgbox # "eCmd_MsgBox"
.data6:803E0358 .long aEcmd_confirmsa # "eCmd_ConfirmSave"
.data6:803E035C .long aEcmd_complete # "eCmd_Complete"
.data6:803E0360 .long aEcmd_completes # "eCmd_CompleteSuccess"
Of particularly interesting note to Treeki was eCmd_CheckCRC. The Wii has a 32-Bit processor and CRC32 is a widely documented generic checksum algorithm. After doing a lot of cross referencing and tracing we found sub_801B570C. sub_801B570C calculates a CRC block of data we were able to figure out what the size of the first CRC block would be in bytes and where in the block the checksum would be placed. We quickly tried this command in Python:
It returned: 0xd14d6ff8 as correctly being the checksum being generated in that CRC block which was correctly verified with a hex editor. We also were able to correctly calculate the checksum in the PDSS CRC block (where a lot of strings are stored). So with two checksum algorithms uncovered which were used over a lot of strings it was finally time to move on from IDA Pro.
Using the Checksum
Once you have the checksum algorithm and the range of data it's used for, the basic idea is to edit your savedata and then recalculate and change the checksum. Prior to this project I was under the misconception that once you had a checksum algorithm all you needed was to mess around inside a hex editor with it. This is actually impossible to do in most cases and instead you'll need to write your own code to use the checksum. Due to it's simplicity, portability, and powerful nature I decided to write my code in Python. I drafted this up:
#Silent Hill: Shattered Memories (Wii) Savefile Checksum Calculator and Editor
#Written by Arikado and Treeki
#Get the checksum for the first CRC block of data
checksum = zlib.crc32(open('Store.000','rb').read()[0x10:0x760])
#Modify the savefile with the calculated checksum
f = open('Store.000','ab')
#Get the checksum for the second CRC block of data (PDSS section)
checksum = zlib.crc32(open('Store.000','rb').read()[0x770:0x770+0x4C10])
#Modify the savefile with the calculated checksum
f = open('Store.000','ab')
I tested this on my savefile and it was successful. Then I changed the name of my player to a name with an equal number of characters (for testing purposes), ran the program and tested the new savefile ... and ... it failed miserably. What I mean by "failed miserably" is that Silent Hill detected that the save file was modified and refused to load it. My guess was that there is yet another checksum that is calculated based on the content of the entire savefile or at least a large portion of it. This is exactly why reverse engineering is so frustrating, so much fun, and why so few people do it.
Using the Dolphin Emulator
With enough time and patience you can essentially figure out any file format or any other interesting information from a program through reverse engineering it. In IDA I graphed out every place that calls the CRC block producing function and proceeded to reverse engineer each one to figure out how it worked. It was obvious that even more backtracing would have to be done of the functions that called the CRC block producing function. tl;dr I had about at least week worth of work ahead of me before I would really get anywhere. I don't really have that kind of time or patience and probably neither does Treeki.
When I develop Wii homebrew I use my USB Gecko to log debug output onto a terminal in my PC. Wii developers do the same thing with their development units using a function of the SDK called OS_Report. The Dolphin emulator is able to log these messages sent via OS_Report. Treeki came up with the brilliant idea to add OS_Report logging to the main.dol so we could see where every CRC block is made and where every checksum is written in it. Going on my hypothesis, this would reveal what checksums are protecting the checksums we already reversed. If not, then it was back to IDA for probably at least another week of reverse engineering to find out what was making those checksums.
Treeki also found that there was a function used to send debug messages by the developers to OS_Report. This function was empty though so it was gutted out for retail compilation. The debug messages were still there, they just weren't being sent to OS_Report by the function. Because this might help us reverse the savefile and because Treeki and I are both interested in how developers think, we filled the function back in.
Identifying and Exploiting a Vulnerability
blah blah blah
Testing the Vulnerability
This section may be a bit redundant but I wanted to throw it in just to ensure absolute clarity among all readers. Testing the vulnerability is a trivial exercise done to determine if it's possible to turn the hacked savegame into a complete exploit. To test it, simply reinstall the modified savegame back into the Wii with Savegame Manager MOD. Next run the game you're working with and see if the savegame crashes the Wii. If it does, you've successfully discovered a vulnerability which can be used to create a savegame exploit. If not, you'll have to either work with the savedata a little more or give up and try a different game.
Adding a DOL Loader
blah blah blah
Modifying the Exploit to Work for Other Regions
blah blah blah
Thinking Outside the Box
There are a number of ways this article can help out fellow hackers that I want to bring to attention before closing off.
Silent Hill: Shattered Memories was also released on the PSP and PS2. I know the PSP in particular is always looking for new savegames to exploit. Perhaps some of the information in this article can be useful to PSP hackers; I certainly think it's at least worth a look. Pushing this train of thought even further, there are also other Silent Hill games on the PSP, PS2, PS3, and XBOX 360 that may be worth looking into.
Konami and developer [NAME] have released other games for the Wii. What are the chances that they use the same generic CRC32 checksum algorithm for those games too? What if there are even more striking similarities in the savefiles of other games they have released? In order to further increase the number of savegame exploits available for Wii, it should definitely be considered being investigated.
Download and Source Code: http://code.google.com/p/INEEDANAME
IRC: #arikadosblog on EFNET
- Team Twiizers (particularly svpe and bushing for always answering my questions)
- Treeki (probably couldn't have done it without you)