custom game boy password hacking

This commit is contained in:
Wouter Groeneveld 2022-04-13 18:18:02 +02:00
parent ff198db286
commit c5f73fba5c
4 changed files with 51 additions and 0 deletions

View File

@ -0,0 +1,51 @@
---
title: "Password Hacking Sylvester & Tweety: Breakfast on the Run"
date: 2022-04-13T17:31:00+02:00
categories:
- retro
tags:
- games
- hacking
---
A few years ago, I encountered Marcus Huderle's [Reverse Engineering Carrot Crazy - Part 1 - Passwords](https://www.huderlem.com/blog/posts/carrot-crazy-1/) 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 in the first place.
My first thought was one of the _Bugs Bunny's Crazy Castle_ games, but since I played through _Sylvester & Tweety: Breakfast on the Run_ recently, I took a shot at that one. As you can see, thanks to the [Retronauts podcast](https://retronauts.com), 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](https://cronop-io.github.io/posts/retrocomputing,%20binary%20analysis,%20hardware/2020-11-25-GameBoyPart1/), I instead resorted to a much simpler solution: I have a [GBxCart](https://www.gbxcart.com/). 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](http://bgb.bircd.org/pandocs.htm#memorymap) is of use here: `$0000` to `$8000` is ROM, which obviously won't change as we fiddle with the password in the game. The WRAM is located in-between `$C000` and `$DFFF`. The [BGB Emulator](https://bgb.bircd.org/) 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:
- `00` = Sylvester
- `01` = Tweety
- `02` - Hector (the dog)
- `03` = Granny
- `04` = Taz
**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.
![](../bgb.png "The password check routine found using the BGB debugger.")
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 `de` and `498A5` into `hl`. Curious! After a lot of `inc` and `ldi` instructions (these increase both pointers, meaning byte per bytes gets read, see the [Game Boy Opcode summary](http://www.devrs.com/gb/files/opcodes.html)), 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](https://gbhwdb.gekkio.fi/cartridges/) 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:
- `$0134` contains the title in uppercase: `SYLVESTER`;
- `$0147` contains the cart type: `19h`, which is MBC5 (no RAM)---5 banks;
- `$0148` contains 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](https://offsecdeer.gitlab.io/post/gb-pointers/) 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](https://www.neoseeker.com/looneytwouble/cheats/gbc/) 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 `04` and `01` and `03` symbols appeared, and after a bit of puzzling, I uncovered every password.
![](../hexedit.jpg "Changing ROM values in a Hex editor.")
**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 final level), and `00 11` is Granny's Cellar. That gives us enough information to cook up something ourselves:
![](../sylvester-password.jpg "A custom password hack with all Sylvesters that takes us to the last level.")
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 `00`s---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](https://gbdev.io/pandocs/) will be indispensable. Good luck, that's all folks!

BIN
static/post/2022/04/bgb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB