SETTINGS
Appearance
Language
About

Settings

Select a category to the left.

Appearance

Theme

Light or dark? Choose how the site looks to you by clicking an image below.

Light Dark AMOLED

Language

Preferred Language

All content on blog.claranguyen.me is originally in UK English. However, if content exists in your preferred language, it will display as that instead. Feel free to choose that below. This will require a page refresh to take effect.

About

"blog.claranguyen.me" details

Domain Name: claranguyen.me
Site Version: 1.0.0
Last Updated: 2020/12/29
Action Replay DS (Part 1): White Screen Brick Recovery
Monday, June 20, 2022

Introduction

In 2007, I got a hold of an Action Replay DS cartridge. As a kid, I used it not only to cheat, but to experiment and play around with games I had physical copies of. Don't worry. I didn't cheat online. Aside from them wiping out my saves, it was a pretty fun time. The way the cartridge worked was cool. It had an additional NDS cartridge slot on top. You would put your game in there. Apply the cheats in the interface that boots up, and then boot the game. The cheats will be applied and you can play the game normally.

Unfortunately, a few years after owning one, I managed to make that cartridge unusable. I have no idea how it actually happened. When I boot it, I am presented with a white screen and nothing else. On top of that, I don't have the cable that would let me connect the cartridge to my PC. So I am kind of out of luck, right? Well, not really. Let's look into it.

Just a disclaimer, this blog post was typed progressively. I type as I figure out more things. So it won't just be a "this is this" and "that is that". So it might come across as disorganised. My apologies. But I do think it might be useful to some people to see how I come to some of the conclusions I do. And you see the journey I went across. It's a fun challenge to me. So know what you're getting into by reading this. My goals are to figure out how to salvage whatever data I could off the cartridge, and then figure out why the Action Replay DS froze in the first place.

Getting information off of the cartridge

I do not have the USB cable that came with the Action Replay DS set. So I can't just connect the cartridge to a PC and try to figure out what's going on. However, I doubt it's going to work even if I did have the cable. Instead, I'll just force it to work. Conveniently, we have a modern solution, a DSi with CFW. I also have a New 3DS LL with CFW, but the cartridge will not fit. Oh well. While the Action Replay DS doesn't officially work with the DSi, the CFW on it will force it to work.

In either case, we can use CFW to run GodMode9i to dump the contents of the cartridge, as well as the "save". From there, we can potentially recover the data from the cartridge.

GodMode9i in action. Contents of the ARDS cartridge are dumped.

The ROM is 16 MB. The save is 256 KB. The metadata is stored in a txt file. This is that text file:

Text file (DAR4NDS v150_DSAR52_00.txt)
Title String : DAR4NDS v150
Product Code : DSAR52
Revision     : 0
Cart ID      : 00000FC2
Platform     : DS
Save Type    : SPI
Save chip ID : 0x010101
Timestamp    : 2022-06-20 14:28:34
GM9i Version : v3.2.1

Whenever I bought this, it was version 1.0. I did update it a few times. I guess that the update will overwrite the contents of the cart directly. We still have no idea how exactly the data is stored on the cart. My initial assumption was that the codes would be stored in the save file, while the cartridge and firmware would be dumped and present in the ROM. That would make sense, right?

A look at the save file

Well, this is underwhelming. The DAR4NDS v150_DSAR52_00.sav file contains a bunch of 01s. Seriously. It's just 262,144 of them. Gee, that would compress really well with bz2. 😏

First 256 bytes of the save file.

I was hoping the save would contain the codes. Though 256 KB doesn't seem like a lot, now that I think about it more. I remember the cart coming with codes for a lot of games. And I'm sure it would have exceeded 256 KB. But whatever. It must be stored in the ROM dump, somehow.

A look at the NDS file

And now we look at the actual NDS file. At first, it looks like a pretty normal NDS file. But after scrolling down, it's pretty obvious that the code data is present in this dump, somehow. Check this out:

Text from codes for Super Mario 64 DS. Text only, it seems.

So, the code names are present there, as well as a game name. It seems like the data is stored in the NDS file after all. Not too sure why. But whatever. This means that, if we can reverse-engineer and figure out how the codes are stored on this dump, we can make a full backup of the codes that were on there. We can also use this to try to figure out what the hell happened to make the cartridge soft-brick.

Regarding those names up above, they resemble C-Strings. In other words, it's bytes that resemble each character, followed by a 00, which is the null terminator. This is how strings of text are stored usually in C. You can clearly see it up above. The strings go on until a 00 is hit. Some seem to have two. My guess at this moment is that they are string pairs. The first is the code name. The second is like a code note, which may be blank. I may be misremembering and it might just allow for 2 lines of text per code. But it doesn't really matter. Either way, it's 2 strings per code.

Before I actually proceed to figuring out where everything is, I need to make it clear, all memory addresses and codes found are for my own copy of Action Replay DS. Since the codes are stored on the actual NDS file itself, this means every cart has a unique dump, with codes located in unique spots. A specific memory address for me definitely won't be the same for you.

Finding the actual codes

I have a hunch that codes are not stored as strings, but actual bytes for compact measure. We have names up above, as well as this magical thing called "The Internet". So we can just grab the codes online and search them in the hex dump.

Some googling led me to this ancient post from 2008 (Archive). How convenient. It happens to have a lot of the codes for the strings above. Thanks mariobowser64! You probably have no idea your post would be useful 14 years later.

Action Replay Code
Have 240 Stars
Load the file and you will have the stars
02094BB4 FFFFFFFF 02094BB8 FFFFFFFF 02094BBC FFFFFFFF 12094BC0 FFFFFFFF 22094BC1 FFFFFFFF
22094BC2 FFFFFFFF 22094BC3 FFFFFFFF 22094BC4 FFFFFFFF 22094BC5 FFFFFFFF 22094BC6 FFFFFFFF
22094BC7 FFFFFFFF 22094BC8 FFFFFFFF 22094BC9 FFFFFFFF 22094BCA FFFFFFFF 22094BCB FFFFFFFF
22094BCC FFFFFFFF 22094BCD FFFFFFFF 22094BCE FFFFFFFF 22094BCF FFFFFFFF 22094BD0 FFFFFFFF
22094BD1 FFFFFFFF 22094BD2 FFFFFFFF 22094BD3 FFFFFFFF 22094BD4 FFFFFFFF 22094BD5 FFFFFFFF
22094BD6 FFFFFFFF 22094BD7 FFFFFFFF 22094BD8 FFFFFFFF 22094BD9 FFFFFFFF 22094BDA FFFFFFFF
22094BDB FFFFFFFF 22094BDC FFFFFFFF 22094BDD FFFFFFFF 22094BDE FFFFFFFF 22094BDF FFFFFFFF
22094BE2 FFFFFFFF

I guess I'll keep it compact like that for site readability. Anyways, let's look for that code in memory. It's stored from 0x00054EF4 until 0x00055013.

"Have 240 Stars" AR Code encoded in binary

Score. If you don't see it, reverse the code values. The Nintendo DS is a Little Endian system. It makes sense that they are reversed. So the first part of the first code, 02094BB4 shows up at the top left of the highlighted region as B4 4B 09 02.

It also looks like the surrounding binary is other codes. The 50 35 09 62 at the bottom is the start of "Skip Text" code from that website above. So we know how the codes are stored.

Surrounding Data: Code Header

There's a few other bytes in that diagram above that have some significance. For one, there is a sequence of 4 bytes that comes before the beginning of "Skip Text", which I just talked about. We don't really know what those bytes are for, other than that they are not part of the actual Action Replay code. So they must be a header of some kind.

Go back up to 0x00054EF0. There's 4 bytes there too. Specifically, 01 00 24 00. My hunch is that this is a pair of two 16-bit integers. I'd say the first 2 bytes are some kind of flag. I would say the second 2 bytes is the length of the code. So let's make some sense of it.

A single line of an Action Replay code is in the format XXXXXXXX YYYYYYYY. If you count the number of "lines" in the "Have 240 Stars", you'll come up with 36 lines. In hex, this is 24. Hmm. Convenient. So I propose the following C-like structs:

C Code
typedef struct AR_LINE {
	uint32_t memory_location; // Left side of AR code
	uint32_t value;           // Right side of AR code
} ar_line_t;

typedef struct AR_CODE_T {
	uint16_t   flag;
	uint16_t   num_lines;     // A line is 8 bytes, or "XXXXXXXX YYYYYYYY"
	ar_line_t *line;
} ar_code_t;

Scared of C or programming in general? Here's a fancy diagram to show what I mean.

"Have 240 Stars" and surrounding codes colour-coded based on struct

If my hunch is correct, and the 01 00 is a flag, then it would mean that the numerical value 1 will represent a Cheat Code. The Action Replay DS lets people organise codes with folders as well. So I will guess that there is a flag for a folder as well. It can't be complicated.

Deconstructing Folders

Wonderful. So we have codes working. That Super Mario 64 cheats listing also features folders. Scrolling just a little bit down in the hex dump will reveal a mysterious new flag. What could it be?

Such mysterious...

If it wasn't clear, the arrow is pointing to address 0x000550B8, being 02 00 03 00. If we treat this as an ar_code_t as defined in our structs earlier, this means the flag is 2. If 1 is a Cheat Code, what is 2? My hunch is obviously Folders.

I want the name of that entity. Fortunately, we have all codes (and supposedly folders) text all available to us. So jumping back to that,

Text from codes for Super Mario 64 DS. Text only, it seems.

There's a lot of bookkeeping to do here. So we will construct a table.

Code Name AR_CODE_T Location Name Location
240 Stars 0x00054EF0 0x00055D33
Skip Text 0x00055014 0x00055D6C
Character/Arrow Replacement 0x00055038 0x00055D97
Multiple Jumping 0x0005505C 0x00055DD7
Wireframe Character 0x00055080 0x00055DF9
No Music 0x000550A4 0x00055E0E
Item Quantity Mods 0x000550B8 0x00055E2B

We got what we wanted. It's "Item Quantity Mods". And it has no note. So, if we assume that it's a folder, then we can assume that second bit means it has 3 codes inside? Recall. 02 00 03 00. If my assumption is correct, this is a folder that has 3 items in it.

Our random Internet friend mariobowser64 comes to the rescue again.

Action Replay Codes
Item Quantity Mods
-
Control Coin Amount
Hold X and press up or down
520973EC FFFFFFFF 02097454 FFFFFFFF D0000000 FFFFFFFF 42097454 FFFFFFFF 02097454 00000000
D0000000 00000000 927FFFA8 FBFF0000 923FDF08 FF0F00F0 A4000130 FF0F00F0 D9000000 02097454
94000130 FFEF0000 D4000000 00000001 D0000000 00000000 94000130 FFDF0000 D4000000 FFFFFFFF
D0000000 00000000 D6000000 02097454 D2000000 00000000 D3000000 04000130 F23FDF08 00000002
D2000000 00000000

-
Control Red Coin Amount
Hold X and press up or down
520973EC FFFFFFFF 02097408 FFFFFFFF D0000000 FFFFFFFF 42097408 FFFFFFFF 02097408 00000000
D0000000 00000000 927FFFA8 FBFF0000 923FDF08 FF0F00F0 A4000130 FF0F00F0 D9000000 02097408
94000130 FFEF0000 D4000000 00000001 D0000000 00000000 94000130 FFDF0000 D4000000 FFFFFFFF
D0000000 00000000 D6000000 02097408 D2000000 00000000 D3000000 04000130 F23FDF08 00000002
D2000000 00000000

-
Control Silver/Multi Star Amount
Hold X and press up or down
520973EC FFFFFFFF 0209740C FFFFFFFF D0000000 FFFFFFFF 4209740C FFFFFFFF 0209740C 00000000
D0000000 00000000 927FFFA8 FBFF0000 923FDF08 FF0F00F0 A4000130 FF0F00F0 D9000000 0209740C
94000130 FFEF0000 D4000000 00000001 D0000000 00000000 94000130 FFDF0000 D4000000 FFFFFFFF
D0000000 00000000 D6000000 0209740C D2000000 00000000 D3000000 04000130 F23FDF08 00000002
D2000000 00000000

If you look at the name of the very next code in the hex dump above, it will be "Control Silver/Multi Star Amount". And if you look at the values after 02 00 03 00, which is 01 00 15 00, it reveals a code of 21 lines (0x15 is 21). Those codes posted above match up, and match the hex dump. We have folders figured out.

With all of this in mind, we can now start to construct an enum for the flag. This is just so things will be more readable whenever I turn all of this information into code. I propose the following enum:

C Code
typedef enum AR_FLAG_T {
	AR_FLAG_TERMINATE = 0,
	AR_FLAG_CODE      = 1,
	AR_FLAG_FOLDER1   = 2,
	AR_FLAG_FOLDER2   = 6
} ar_flag_t;

Later on in the digging up of codes, I also discovered that 6 is a folder. Considering I am not able to test this on my bricked cartridge, I have no way of telling if there is some special condition for it yet. My hunch is that the Action Replay DS keeps track of what folder is open and closed. This conclusion is only because I saw some videos on YouTube of other people demonstrating their Action Replay DS's and booting them up. Some folders were open, and some weren't. But I can be wrong. We'll see. I also have no idea if folders can be nested or not. But whenever I implement a code extractor later on in this post, it won't really matter whether they can be extracted or not.

Furthermore, I discovered that we should stop reading data for a game if an ar_code_t flag of 0 is hit. It indicates we hit the end of a game's code list. Hence AR_FLAG_TERMINATE.

Reverse-Engineering Game Code Structure

With code and folder structure figured out. We can broaded the scope a bit. So what about how things are stored per game?

From above, the codes are stored as bytes. Then the text for the codes is stored after it. This is done on a per-game basis. We have only looked into some codes for Super Mario 64 DS. But what about what shows up before the codes? Well, it's game information. And this starts at 0x00054000. Here's a hex dump of that:

Header. Above code information.

So the first 32 bytes from 0x00054000 are not bytes for a code. Instead, they are for game information. A header. From the plaintext view, we can see that 41 53 4D 45 is ASME. Hmm, doesn't that look familiar?

The front of my Super Mario 64 DS cartridge. NTR-ASME-USA is shown.

Yes. It's part of the code on the actual cartridge. Specifically, it's the Game Code. There are a few other parts that I can recognise. 49 37 A6 AE at 0x0005401C is a checksum. This one is the result of a CRC32 run on the first 512 bytes of the NDS ROM, then run through a bitwise NOT operator. For you C programmers, that's ~. When you find Game IDs online, this is where the final 8 digits come from. Hence ASME-AEA63749 for version 1, or ASME-F486F859 for version 2 of SM64DS.

Also, looking a bit up at 0x00054000, this looks like a length of some kind. 0x18CA is 6346. And ends up being the number of bytes from the header up until the text. The next 4 bytes is an integer 0x1730, which is 5936. Seeing as the size of the text chunk is 0x835 (2101 bytes), it can't be that. Instead, it is the number of bytes from the header until the end of the code binary. There are bytes between the binary code and the text. This can also serve as an "offset" to jump to that segment.

The 5th and 6th byte look like a 16-bit integer that is simply the number of codes present.

I also speculate one of these has to be a time field. A weird hunch that has quite a coincidence behind it. The 4 bytes prior to ASME, when reinterpretted into a DOS date, gives us 2007/11/07 @ 18:44:00. This "coincidence" is consistent among a lot of games. Now, this isn't a release date. This is more like a date that the code list was generated on. I'm skeptical, because why a DOS timestamp? I was expecting a UNIX timestamp. Well, the software is for Windows.

Anyways, let's assume this is true for now. Thus, Microsoft has documentation on this. So we can use that to decipher things without libraries or an actual Action Replay DS. Another supporting factor is that the timestamps I have sampled from my dump is that the "seconds" field is always 00, which is how Action Replay DS XML files have their <date> tags organised. They do not specify a "seconds". There are only two exceptions. If there is no date specified, which I tended to leave out as a kid, these 4 bytes will be 00 00 00 00. The other exception is where it shows SCRO, which is 53 43 52 4F. I have no idea what that is. But it decodes to 2013/10/19 @ 9:58:36. That doesn't sound quite right... But remember, I can't test this.

As for the other fields, I can do a proof by exhaustion on some of them. For the first 4 bytes, it is always 01 00 1C 00. So I will treat it as a Magic Number. I want to say it's 2 uint16_ts and each have their own meaning. Maybe 01 is a "game" identifier, and 1C (which is 28) could be something else. But it's consistent enough for me to not care. Another is bytes 6 and 7. They will always be 20 00 (which is 32). Again, it's consistent enough for me to not care about it.

With all of this in mind, I propose the following struct:

C Code
typedef struct AR_GAME_INFO_T {
	                          // Bytes    Description
	uint32_t magic;           // 00 - 03. Always "01 00 1C 00".
	uint16_t num_codes;       // 04 - 05. Number of codes present
	uint16_t nx20;            // 06 - 07. Always "20 00".
	uint32_t offset_text;     // 08 - 11. Bytes from game_info_t to text - 1
	uint32_t offset_strlen;   // 12 - 15. Bytes from game_info_t to strlen
	uint16_t wDosDate;        // 16 - 17. DOS date (?)
	uint16_t wDosTime;        // 18 - 19. DOS time (?)
	char     ID[4];           // 20 - 23. 4 characters that appear on cartridge
	uint32_t idk;             // 24 - 27
	uint32_t N_CRC32;         // 28 - 31. ~CRC32(first 512 bytes of ROM)
} ar_game_info_t;

Writing Code: A game-to-codelist "decompiler"

ards_game_to_xml - A code "decompiler" into XML format

We now know enough to write up some code to "decompile" segments of the ROM dump into a code list. I'll stay classy. So we'll do this in C. The goal is to start small. We'll write something that will take a memory address and try to dump a single game with the information that was figured out above. This is why I was creating structs. Because then we can just chuck it at C and it will just work... I hope.

So, with this, I present to you ards_game_to_xml. Mouthful. It takes the Action Replay DS rom dump, as well as a hex address that points to the top of the header up above. In other words, look for a 01 00 1C 00. That's the address you put in. It will spit out a valid XML file with the codes from the game straight from the ROM dump.

It has a syntax like this:

UNIX Command
UNIX> ./ards_game_to_xml "ACTION_REPLAY_DS.NDS" HEX_ADDRESS > file.xml

And if we adjust that to where Super Mario 64 DS's header is, at 0x00054000, we get...

UNIX Command
UNIX> ./ards_game_to_xml "DAR4NDS v150_DSAR52_00.nds" 54000 > sm64ds.xml

Which results in the following file: sm64ds.xml. I would embed it here, but it's quite big.

Sweet! It works. And I have successfully recovered codes for that one game. By searching in a hex editor for the magic number 01 00 1C 00, I consistently get results that let me extract more codes from more games. So the code works consistently. I'm satisfied. In an effort to make it a little more user friendly, I let it take more than one address. And it will export the Action Replay codes of multiple games to the same XML file.

UNIX Command
UNIX> ./ards_game_to_xml "DAR4NDS v150_DSAR52_00.nds" 54000 5A900 5BF00 5C500 5C800 5DE00 62C00 > codelist.xml

ards_game_ls - A listing utility for game addresses

To aid in extracting addresses, another utility was written. This one is for getting addresses where games are stored, and listing their names, if possible. With this, I present to you ards_game_ls. A bit less of a mouthful. It will take an Action Replay DS rom dump and scan it from 0x00054000 throughout 0x000FFFFF for the magic number discussed earlier. To prevent stumbling upon finding that magic number by coincidence in an Action Replay code, it will skip over ones it finds in games.

Since we are going for data recovery and salvaging whatever we need to, I will throw out my theory that there is a "game list" somewhere, probably at 0x00044000. The program's point is to go through every single byte and get whatever it can. Brute force. Thus, the syntax is as follows:

UNIX Command
UNIX> ./ards_game_ls [-dehnw] "ACTION_REPLAY_DS.NDS"

There's some optional flags:

This program will help out with figuring out what's going on, and what went wrong with the Action Replay DS.

"Just give me something that dumps all codes into an XML file..."

Ok. This.

UNIX Command
UNIX> ./ards_game_ls "ARDS.nds" | sed 's/^0x[0]\+\([0-9a-f]\+\) - .*/\1/' | xargs ./ards_game_to_xml "ARDS.nds" > "codelist.xml"

So, what caused the white screen brick?

At the current moment, trying to figure out the issue is not really feasible. Maybe once I reverse-engineer the firmware in the next part of this blog series, I'll be able to figure out what the culprit is. I was hoping to use ards_game_ls to do error-checking. It went like this:

Left = Working copy. Right = Non-working copy.

While it would make sense to take these error messages seriously, it's also random-access where a lookup table is located somewhere to jump to the correct spot. So if you delete a game from the Action Replay DS cartridge, the memory isn't erased. Yet it can be overwritten. So these errors mean nothing.

In short, I have no idea what broke just yet. For now, we got the codes recovered. The next blog post will be about firmware reverse-engineering as well as flashing to permanently fix the cartridge. So that will be the time to figure out what went wrong.

So, what's next?

Mission accomplished. I recovered my cheats from my bricked Action Replay cartridge and figured out, to some degree, what was wrong with it. So, what's next?

From here on, I will try to get my own cartridge to boot by flashing a working firmware onto it. Whether that requires more hardware or I just write some homebrew to do it will be discussed later on. That will have to make for a second part. Until then, I hope you enjoyed the read. It was a fun and simple challenge.

The programs I showed off earlier can be downloaded at its GitHub repo. You can find that here: ards_tools.




Clara Nguyễn
Hi! I am a Vietnamese/Italian mix with a Master's Degree in Computer Science from UTK. I have been programming since I was 6 and love to write apps and tools to make people's lives easier. I also love to do photography and media production. Nice to meet you!


Blog Links
Post Archive
Affiliates/Cool People
Nigoli's Blog
Raas's Blog