Legitimizing your counterfeit Zelda save

(Updated )

I’ve been working on filling the gaps in my collection of the Legend of Zelda franchise, and one of the gaps I had was The Legend of Zelda: The Minish Cap for the Game Boy Advance. Since the game came out in 2005, I was stuck with getting a used copy. Unfortunately little did I know, Minish Cap is one of the more frequently counterfeited GBA games. Also unfortunately for me, I didn’t even realize I had purchased a counterfeit until I had gotten around 90% of the way through the game…whoops.

As soon as I realized my mistake, I read up on avoiding fake GBA carts and ordered a new copy. Unfortunately the damage was done. I was already mostly done with the game, and some parts of the game were not completable due to either a bad version of the game or some sort of copy protection.

Photo comparing counterfeit and legitimate Zelda Minish Cap game cartridges side-by-side

It is surprisingly obvious seeing them side-by-side. Especially the quality of the printing on the label. Additionally, the ESRB and Nintendo logos are wrong. It is also missing the imprinted numbers. (In case you aren’t seeing it: The fake is the one on the left.)

I knew when I ordered the new cart that I wanted to try to transfer the save (using homebrew on a Nintendo DS.) The most popular homebrew for doing this is Rudolph’s GBA Backup Tool. It worked great for pulling the ROM images for analysis and the legit cart’s save, but when I pulled the save from the counterfeit cart I got 8 KB of 0xFF. This was disappointing but I wasn’t going to give up there.

Screenshot of Zelda Minish Cap showing a heart piece which is impossible to access

I mean, the counterfeit cart had an inaccessible heart piece in it! You can’t just leave those behind!

Diagnosing the undownloadable save

The truth lies within the cart:

Photo comparing the insides of the two game cartridges

As before, the counterfeit cart is on the left. A battery hints at an SRAM save backup, and this is confirmed by reading the chip model information below. If you look at the real cart, it uses an EEPROM. Unfortunately, the only (reliable) way to detect cart backup media is to look for magic strings placed by Nintendo’s build tools. My guess is Rudolph’s tool uses this technique, and incorrectly identifies the cart as an EEPROM cart.

Counterfeit chip info

Here’s a screenshot of the counterfeit ROM dump with the magic string indicating it should be using an EEPROM:

Screenshot of a hex editor showing the magic string “EEPROM_V124”

Those with sharp eyes will also notice in the above screenshot that the counterfeit cart was identified as GBAZELDA_MC_BZMP, which is the PAL region (European) version of the game. I live in the US though and would expect to have GBAZELDA_MC_BZME (which is what it says on the label.)

After doing some analysis on the ROM dumps, it definitely appears that it the PAL version of the game. Additionally, the entire ROM is doubled for some reason. I imagine this is either an error in Rudolph’s tool or the counterfeit cart’s design (the real cart didn’t do this.) Other than that, there are two other small changes:

Screenshot of a hex diff tool showing the differences between the two ROMs

I didn’t have the patience to disassemble this (don’t blame me, blame THUMB mode), but I imagine these are save file routines. (Patching from EEPROM to SRAM is actually very automated from the little I know. There are tools out there from when the reloadable GBA carts didn’t have EEPROM chips or support emulating it.)

So at this point I am starting to worry. I tried a handful of other save dumpers with similar results. Additionally, even if I got the save down, there’s no telling if it is going to work because of the separate regions. (I could’ve tried loading a counterfeit save from an emulator on the legit cart or with the legit rom in an emulator, but I decided against this since the following was more fun.)

The Solution

So what would any sensible* person do in this situation? Give up. Make their own save file dumper from scratch. (There is actually an open source save downloader on GitHub, but for various reasons I ignored it.)
*For various definitions of sensible.

So with reading my trusty hardware reference and reinstalling the ever-reliable devkitPro I set out on my quest.

I started with a simple Nintendo DS tool that could print out the contents of a GBA save file. Basically, a simple hex viewer. I’m lucky that the counterfeit cart was SDRAM instead of EEPROM rather than the other way around, because reading from SRAM is dead simple while the EEPROM…not so much (from what I’ve gathered.)

All you have to do is clear bit 7 of the EXMEMCNT register to give access to the ARM9 processor to the GBA slot. (The Nintendo DS has two processors, an ARM9 and an ARM7.) Then, the SRAM can be accessed using 8 bit reads in the address range 0x0A000000 - 0x0A010000, which is the “GBA Slot RAM” (previously known as the Game Pak SRAM at 0x0E000000 in the GBA.)

Clearing bit 7 in EXMEMCNT is pretty important, because if you forget you will get all 0x00. Which is not awesome. (This is why the app has the EXMEMCNT displayed and a message stating whether the entire save region is 0x00 or 0xFF…oops.)

Photo of my save dump tool running on a Nintendo DS Lite with the text “ADLEZ” at offset 0

As you can see, the app properly detects the game’s name, and can read its save data. It is backwards, but you can also see that the save data begins with the text ZELDA. I’ll talk a little bit more about this later.

Another photo of the backup tool showing a different offset with the text “htaP”

You can also see my nickname Path in there (also backwards.)

At this point we know we can definitely read the save data, so now we just have to save it to the flash cart. I was actually pretty surprised I didn’t need to mess with waitstates or anything like that.

I did end up copying the data “by hand” 1 byte at a time into a temporary buffer since GBATEK states that the SRAM only has an 8 bit bus, and I figured memcpy and fprintf might not use 8-bit reads in devkitPro.

Shuffled save data

I actually ended up finding this wasn’t completely necessary, but I thought I’d cover it anyway.

For reasons not completely clear to me, the save data in EEPROM games is partially backwards. To be more exact, each chunk of 64 bits is reversed. The 64 bits makes sense since you access the EEPROM 64 bits at a time, but why the reverse? I am thinking it might have to do with how the generic Nintendo EEPROM code works. (It also turns out that Rudolph’s GBA Backup Tool ships with a VBS script to fix it for you.)

If you compare the two raw save files from NO$GBA, you’ll see that the real version (bottom) is linear, but the counterfeit cart is reversed.

Screenshot of a hex editor comparing a save files from both games

I imagine this is because the Nintendo save routine is still writing everything backwards, but NO$GBA isn’t reversing it for the raw save because its SRAM and not EEPROM. Or maybe EEPROM is naturally recorded backwards. Either way, I wanted to be able to test my dump save in an emulator before loading it on the real legitimate cart. So as a part of this project, I also wrote a small C# tool to fix the orderings of the dumped save files.

Small side notes about the saves

This is a bit out of place, but I found it interesting so I wanted to mention it. From a very light look at the dumped saves, it looks like Nintendo/Capcom are storing each save file twice. I imagine this is to ensure one version of the save file is still available if one gets corrupted by the player removing the cart or old hardware. You can corrupt one, but not the other, and still get a proper save in game.

Of course, if you mess with both of them, you get a dreaded error that I imagine most players will never see.

Screenshot of Zelda Minish Cap with a forboding red error box stating “The data in File 1 is corrupted.”

So there’s definitely some CRC validation going on. Also interesting, the game takes a noticeably longer period of time at the start screen when the save file is corrupted. I guess it is either a pretty thorough integrity check, or maybe there’s some error correction going on.

Loading the counterfeit save into a legit game

At this point, if I loaded the counterfeit save into the legit game in an emulator, I only got a blank save screen. (Interestingly, no error on the screen.) So I had to look at what was different between the two games’ saves (and hope it wasn’t everything.)

Screenshot of hex diffing tool showing the difference between both saves

There’s only a few bytes different here and there, and they are all in that little header section. One difference in particular stands out, the difference in the game title string at the start of the save: “ZELDA 3” vs “ZELDA 5”. I imagine this is some sort of internal version number. All I did was change the 3 to a 5, and load it in the English version of the game and…

A screenshot of the repaired save file loaded in-game

We have savefiles! After this, I tried to load it on the real cart. Since I knew it worked with the real cart, I just used Rudolph’s GBA Backup Tool again. Since the save it dumped from my real cart was shuffled, I took this as a hint to give it a shuffled version (but still with the corrected version number.)

A photo of the repaired save file loaded in-game on real hardware

Source code

Even though it isn’t much, I’ve open sourced the code for both my little NDS SRAM save viewer/dumper as well as my little C# tool for un/reshuffling save files. You can find the source code for both on GitHub under PathogenDavid/PathogenBackup. Both projects are contained in a Visual Studio Solution. The NDS project is an NMake project, so if you don’t have Visual Studio you can just run the makefile as you normally would (provided that you have devkitPro installed.) I imagine both projects should build/run fine on Linux and Mac, but I have not tested this.

This is the longest I’ve ever spent on a piece of heart side quest ever.

Post cover is a parody of the Nintendo Anti-Piracy website header.