Dreamcast - Anatomy of an Assembly Hack

ADnova
Way back in 2000 or so I got involved in the video game cheat code hacking scene. There was a vibrant and fun community surrounding the various cheat code devices. Eventually the newer consoles made mass market cheat devices impossible for one reason or another, so I’m not even sure what the state of the community is these days. My level of involvement in the cheat code hacking scene also dropped sharply after I graduated and got a job and moved out of my parents basement.
 
The specific hacks I’m going to be discussing are for the great Dreamcast game Skies of Arcadia. Back when the game was released, the only cheat device available for Dreamcast was the Gameshark. Their codes had an encryption scheme applied, which was something new (?) and unwelcome in the hacking community. After the incredible abilities provided by the Gameshark Pro for the N64, most community members were annoyed at this apparent step back in openness. There was no way for the casual hacker to create Dreamcast codes.
 
Two events soon occurred that allowed Dreamcast hacking.
 
First, a company named Pelican released the Code Breaker device for the Dreamcast. It supported unencrypted codes, which meant that the common hacker could now understand code types. They could then also potentially create codes without having to know the encryption scheme used by the Gameshark (a point rendered moot by awesome hacking community member Parasyte and the release of DCCrypt). The Code Breaker was supported by a favourite community hangout, CMGSCCC (now currently CodeTwink I believe).
 
Second, a Dreamcast emulator called Chankast was released (now supplanted by other more complete emulators). It meant that you could actually play Dreamcast games on your PC. A basic cheat code hacking program was released, allowing you to execute searches on Chankasts memory.
 
Unfortunately for the future of Sega in the console market, the Dreamcast had the ability to load CD-Rs formatted a certain way with a scrambled binary. This was fantastic for Homebrew developers, but also fantastic for pirates. Broadband usage was increasing at a rapid rate around this time as well, which meant that the formerly daunting task of downloading a several hundred megabyte Dreamcast ISO wasn’t such a big deal any more. With the addition of disc ripping programs released making use of the DC Broadband Adapater, or the ‘coders cable’ sold by the sued-out-of-existence Hong Kong based company Lik-Sang, the torrent sites presented nearly the entire DC library on a platter for people. You simply downloaded the image, burned it to CD-R using a common CD burning program, then put it in your unmodded Dreamcast and started playing.
 
If you were interested in creating cheat codes, then you just needed to download the game image, Chankast, and the Chankast cheater standalone program that let you do value searches of memory. If you wanted to get much deeper into how the game worked, you could then extract all of the files out of the image using a program such as ISOBuster.
 
Since this post was supposed to be about explaining an assembly hack, next up would be finding the game binary in the extracted files, usually named 1ST_READ.BIN. If the downloaded image was classed as ‘self-boot’ as most of them were, it meant that the binary file was scrambled. The scrambling process was necessary in order to get the Dreamcast to load it off of a CD-R. If you wanted to get an assembly code actually usable in a real game though, you first had to unscramble the binary, then remake the disc image with the non-scrambled binary.

Now with an unscrambled binary, it was time to run it through a disassembler. This would create a listing of all assembly instructions in the game in human-readable format, such as:
 
H'8c1ecd30: H'1f09  ..  mov.l R0, @(9, R15)
 H'8c1ecd32: H'53f9  .S  mov.l @(9, R15), R3
 H'8c1ecd34: H'd119  ..  mov.l @(H'8c1ecd9c), R1          (H'8c5808ac)
 H'8c1ecd36: H'2132  2!  mov.l R3, @R1
 
What do the different instructions mean? For that you need to grab a programming manual for the Dreamcast processor, the Hitachi SH-4. This was free and publicly available.
 
It would probably be good to mention now what kind of codes I wanted to create. One of the most common gripes people had with this game was the number of random battles. So,  I wanted a code that would shut off random battles. For my own interests, I wanted to create codes that changed how much experience and gold you received after battle.
 
The codes I ended up creating were get 4x gold, experience, and magic experience after battle, and no random battles.
 
I started with the gold, exp, and magic codes. The first step is of course to load the game in Chankast and run the Chankast Cheater program. You then follow the typical cheat code hacking routine of narrowing down values. After a battle you are given a certain amount of gold, experience, and magic experience points. In this case, it was easier to search for the gold or experience values since magic experience gained was usually just 1 or 2, but experience might be 458 (somewhat less likely to occur in memory than 1 or 2).
 
My initial idea was to just change the value at the memory address I found through the search process. That didn’t work, however. It only changed the value displayed in the after-battle UI; it didn’t actually alter the exp/gold you received. This lead me to conclude that the data must be copied from some other place where the true value is calculated.
 
That massive disassembly file we have is where we look to next. I have the memory address I found through the search program that stores the value I care about. Now I look for it in the disassembly. Luckily, the binary file is loaded into memory at the same absolute location, so assuming your disassembler resolves memory references you’re in good shape.
 
You’ll end up finding a routine that works with the values you care about. For me, I think the gold gained value was stored in the address 0x8c56e0bc. I found the routine that handles gold, exp, and magic exp gained after battle all together:
 H'8c1ecd30: H'1f09 .. mov.l R0, @(9, R15)
 H'8c1ecd32: H'53f9 .S mov.l @(9, R15), R3
 H'8c1ecd34: H'd119 .. mov.l @(H'8c1ecd9c), R1 (H'8c5808ac)
 H'8c1ecd36: H'2132 2! mov.l R3, @R1
 H'8c1ecd38: H'6322 "c mov.l @R2, R3
 H'8c1ecd3a: H'8431 1. mov.b @(1, R3), R0
 H'8c1ecd3c: H'd318 .. mov.l @(H'8c1ecda0), R3 (H'8c5808b0)
 H'8c1ecd3e: H'2302 .# mov.l R0, @R3
 H'8c1ecd40: H'6322 "c mov.l @R2, R3
 H'8c1ecd42: H'503d =P mov.l @(13, R3), R0
 H'8c1ecd44: H'1f0c .. mov.l R0, @(12, R15)
 H'8c1ecd46: H'53fc .S mov.l @(12, R15), R3
 H'8c1ecd48: H'd016 .. mov.l @(H'8c1ecda4), R0 (H'8c5808b4)
 H'8c1ecd4a: H'2032 2 mov.l R3, @R0
 H'8c1ecd4c: H'd216 .. mov.l @(H'8c1ecda8), R2 (H'8c56e0bc)
 H'8c1ecd4e: H'53fc .S mov.l @(12, R15), R3
 H'8c1ecd50: H'6122 "a mov.l @R2, R1
 H'8c1ecd52: H'313c <1 add R3, R1
 H'8c1ecd54: H'2212 ." mov.l R1, @R2
 H'8c1ecd56: H'd215 .. mov.l @(H'8c1ecdac), R2 (H'05f5e0ff)
 H'8c1ecd58: H'd013 .. mov.l @(H'8c1ecda8), R0 (H'8c56e0bc)
 H'8c1ecd5a: H'6102 .a mov.l @R0, R1
 H'8c1ecd5c: H'3127 '1 cmp/gt R2, R1
 H'8c1ecd5e: H'8b01 .. bf H'8c1ecd64
 H'8c1ecd60: H'd311 .. mov.l @(H'8c1ecda8), R3 (H'8c56e0bc)
 H'8c1ecd62: H'2322 "# mov.l R2, @R3
 H'8c1ecd64: H'd112 .. mov.l @(H'8c1ecdb0), R1 (H'8c5808b8)
 
All of the instructions are listed, and I have the addresses that store the values for exp, gold, and magic exp gained after battle. The next question is, how am I supposed to modify them? We’re actually going to be replacing assembly code (hence the name assembly hack), so we need to understand what’s going on in the routine.
 
Luckily it’s quite simple; there’s basically a bunch of moves from registers to memory. What we have to find out is what instructions to replace.
 
Consider the following code snippet:
 

8c1ecd30: mov.l R0, @(9, R15)
 8c1ecd32: mov.l @(9, R15), R3
 8c1ecd34: mov.l @(H'8c1ecd9c), R1 (H'8c5808ac)
 8c1ecd36: mov.l R3, @R1
 
From what little I recall of SH4 assembly this code moves a value from register 0 to the stack (I think R15 was the stack pointer register). Then it moves that stack value into R3, moves a value in memory location 8c1ecd9c to R1 (8c5808ac, the experience gained after battle storage location), then moves the value in R3 to that address.
 
So it seemed to me that R0 contained the ‘true’ value that I needed to modify, and that the use of R3 was unnecessary. I replaced the first instruction with a shift left by 2, which means the value is multiplied by 4 (the value of exp gained is small  enough that overflow isn’t a concern). R3 didn’t need to be used, but I still had to copy the value in R0 to the stack, and make sure that R1 got the proper value.
 
So 3 instructions were replaced for this code, ‘Get 4x experience after battle’:
 8c1ecd30: shll2 R0
 8c1ecd32: mov.l R0, @(9, R15)
 8c1ecd36: mov.l R0, @R1 

Okay, most of the hard work is done. Now we just need to make a code for a cheat device using this information. First we need to consult the SH4 programming manual and find what values we should write to the memory locations to replace the existing instructions with the ones we want. Fortunately it has a table with the instruction codes.
 

shll2 R0            => 4008
 mov.l R0, @(9, R15) => 1f09
 mov.l R0, @R1       => 2102
 

I mentioned earlier the binary is always loaded into the same location in memory. Well, luckily for us the cheat devices allow us to write to that location. What we now need to determine are what code types we need to use. We only care about 2 code types for this code, “01″ which is 2 byte write, and “02″ which is 4 byte write. Following the code type is an address to write to. In this case, the “8C” part of the address is always assumed, so isn’t necessary to write in the code. 

The first two address are consecutive, so it’s simpler to use a 4 byte write which gives us the code 021ECD30 1F094008.
 The second part of the code only needs to modify 2 bytes, so we use 011ECD36 00002102.