A few years ago, I encountered Marcus Huderle’s Reverse Engineering Carrot Crazy - Part 1 - Passwords blog post, in which he attempts to pry out the passwords of the Game Boy Color game Looney Tunes: Carrot Crazy. I loved Marcus’s attention to detail and figured I could try out his method myself on other Game Boy stuff I had lying around. The problem with old Game Boy (Color) games is that most of them didn’t even come with a RAM chip—you were lucky if a password system was implemented.
My first thought was one of the Bugs Bunny Crazy Castle games, but since I played through Sylvester & Tweety: Breakfast on the Run (Looney Tunes: Twouble! in USA) recently, I took a shot at that one. As you can see, thanks to the Retronauts podcast, I’m into Looney Tunes games lately! Most of them suck though, so unless you loved these as a kid, don’t bother attempting to play them. Breakfast on the Run–a black Game Boy Color cartridge that is still compatible with the original GB—is perhaps an exception: it’s an isometric puzzle/adventure game reminiscent of Monster Max with jump-and-run sections in-between.
Problem 1: Getting the ROM. Compared to expert hardware hackers that extract their Game Boy cart using an Arduino, I instead resorted to a much simpler solution: I have a GBxCart. Plug in the cart, run cmdline, done.
Problem 2: Figuring out where the entered password is saved in the WRAM. The Game Boy Memory Map is of use here:
$8000 is ROM, which obviously won’t change as we fiddle with the password in the game. The WRAM is located in-between
$DFFF. The BGB Emulator is essential as its debugging tools are superior compared to mGBA’s. Sadly, it’s a Windows-only program, so I had to take out an old work laptop for this little project. If you scroll through the memory locations while playing the game, you can eyeball where the “changes” occur. Rapidly changing values usually indicate music playing or sprite swapping.
After a bit of trail and error, I found the last 8 bytes of the password being stored in
$DC00—these values change as I change one of the five faces in the password screen. You have to get five Looney Tunes characters in the correct order to jump to a certain level. We can also see which values are which character:
02- Hector (the dog)
Problem 3: if we know where the password we entered is stored, can we also figure out the passwords the game will compare it with? That’s where GDB’s memory access breakpoints come in. Set it to
$DC00 in read-only mode and voila: after pressing start in the password select screen, the debugger breaks at
$7456 in ROM bank 2 with instruction:
ld a, (de). Register
de contains our password pointer.
After breaking my head on the cryptic routines there, I realized I had to scroll up a bit to
$7444 where this specific routine actually starts. You can see that it loads both
$DBFC (just before where we enter the password in) into
hl. Curious! After a lot of
ldi instructions (these increase both pointers, meaning byte per bytes gets read, see the Game Boy Opcode summary), we encounter a couple of
jr nz, x instructions that form a loop (the check itself). Debugging is annoying because the breakpoint is hit four times per drawn frame.
Problem 4: How do we translate internal pointers to raw ROM addresses to find the passwords for each level? This is a bit of a hassle on the Game Boy systems as they are very limited 8-bit devices. In order to squeeze more out of a GB cart, most games come equipped with a concept called ROM banking: every
0x4000 bytes is one “bank” that is mapped to the memory-mapped model of the GB. We’re in bank 2. I usually resort to the Game Boy hardware database to find out technical ROM information, but Sylvester & Tweety isn’t there! Luckily, a hex editor allows us to find header information that says how many banks the game has:
$0134contains the title in uppercase:
$0147contains the cart type:
19h, which is MBC5 (no RAM)—5 banks;
$0148contains the ROM size:
05h, which is one meg.
More detailed information on how to translate base addresses to relative pointers in the correct bank can be found in Giulio Pierantoni’s excellent article on GB pointers. To be honest, I got kind of lost here, and after hours of trying, I resorted to another technique. Since the passwords are known anyway—I finished the game and the cheatcodes are online—I decided to open up an hex editor and look for those instead.
Remember, password “Taz, Sylvester, Tweety, Hector, Granny” (Level one, Granny’s Cellar) translates to
04 00 01 02 03 00. I found an entry at Hex location
0x000077ED! Which memory bank is that? Divide by
0x4000—bank 2. Sure enough, in the vicinity, other
03 symbols appeared, and after a bit of puzzling, I uncovered every password.
Problem 5: Can we cheat and create our own password? Yes we can! Simply change the desired values and dump a new ROM file. The CnC check will fail unless you also fix that in the header information, but mGBA or another emulator doesn’t really care. I wanted an all-Sylvester password:
00 00 00 00 00. The trouble is—which level to load? Four bytes after each password seemed to indicate the associated level. For example,
01 31 is The Outer Streets (the second to last level), and
00 11 is Granny’s Cellar. That gives us enough information to cook up something ourselves:
Yay, it works! Marcus went much further in his Carrot Crazy disassembly by injecting a custom password table and changing the pointer to his new one at the end of a random memory bank. Most of them aren’t completely filled and you’ll notice a lot of
00s—for example, right before
0x8000, the second bank. But my work is done here, I’ve had a blast this afternoon doing something I probably shouldn’t be doing.
If you plan to do this yourself, a bit of Game Boy internal knowledge and instruction assembly goes a long way: the Game Boy Development Pandocs will be indispensable. Good luck, that’s all folks!