Hardware Crackmes: 100 GameBoy Advance Games

A Game Boy Advance cartridge is a frozen binary. There are no patches, no server-side validation and no telemetry. Whatever cheat codes the developer intentionally (or unintentionally) wrote in 2003 is still the exact code running today. That makes an in-game cheat code about as close to a real-world crackme as you can get: there is a validator, there is an input surface on dedicated homogenous hardware, and somewhere in the ROM is the set of inputs it accepts.
Under the hood, it’s useful to read the hardware architecture and the wonderful GBATek to understand what’s going on. At a high level: every game ROM runs on identical hardware, and every input comes through a specific subset of addressable memory. This means that if you have a game and a lot of patience, you can enumerate the full scope of every valid input. It just takes some guidance and effort, not dissimilar to how one might leverage AI agents to reverse engineer a binary for vulnerability discovery.
What makes it particularly annoying to do by hand is that GameBoy Advance ROMs are a custom format and also mix together both ARM and Thumb CPU instructions. Constantly swapping back and forth between static and dynamic analysis is necessary, and learning to play the game in such a way that you don’t taint the result is implied. At its core, a particularly annoying benchmark to meet.
So I pointed AI agents at 100 GBA ROMs and gave each one the same brief.
- Search the internet for the game’s known cheat codes.
- Find the cheat, password or debug logic in the ROM, whether intended or not.
- Reverse the validator.
- Enumerate the whole accepted space: confirm every published code, prove where the published lists are wrong, and mint codes nobody has published, then enter each one on the game’s own screen in mGBA emulator and watch it work.
The agents wrote a report per ROM: address maps, pseudocode, tables, rejection tests proving the bounds, and a section on what they couldn’t prove. Then I went back through all 100 and searched the web myself to see whether the “novel” findings really were novel.
Some held up. Some didn’t. Some probably aren’t new, but just seem that way because of the current state of search engine rot and AI slopification. Both lists are below, to at least ensure they’re written about here. Later, I will probably have the AI agents analyze every published GBA game title in existence, but for now I’m out of tokens. One agent in particular spent several billion tokens working through a Yu-Gi-Oh game and while that type of unecessary token burn is easily addressed, I truthfully just let it keep going because it was entertaining to watch. The session devolved from english into pure symbology, and yet it continued anyways.
Following the celebration of the novelties, we’ll do a quick study of the design of hardware specific cheat codes through the lens of a “crackme”.
Novelties
Each entry below was searched against GameFAQs mirrors, SuperCheats, Cheat Happens, Cyberly, CheatCC, Almar’s Guides, VGChartz, TCRF, etc… “Not found” means I couldn’t find it mentioned anywhere. It doesn’t mean it’s never been found before. That would be pretty cool to be able to say, but is also an insanely high bar to meet, especially across 100+ GBA games.
Unless a caption says otherwise, each screenshot is the game’s own UI in mGBA, typed on the game’s own keyboard, with no GameShark, CodeBreaker or memory edit involved.
Barnyard - a single literal behind a feature the manual advertises
The GBA Barnyard has an OPTIONS → Enter Code: screen, and the manual says “You are also able to enter your secret code here to unlock new characters!”. It never prints the code. The only public cheats for the GBA version are CodeBreaker memory writes. Cheat Happens lists none, and the codes on GamesRadar are for the Wii and GameCube.
The validator turns out to be one strcmp against one literal at 0x0809A46C:
0T1S
The entry widget is a four-slot wheel that skips every byte outside 0-9A-Z, so the input space is 36⁴ = 1,679,616 and exactly one value is accepted. Entering it writes a u32 flag at 0x02033D6C, shows “Congratulations! You have unlocked four new colored cows!”, and the character creator’s color list grows from 3 to 4. It’s saved to the cartridge. I couldn’t find 0T1S published anywhere.


Its nearest neighbour, 0T1T, is rejected.
Army Men: Operation Green - a leetspeak table that runs before the real decoder
Operation Green has a proper algorithmic password: 8 symbols over a 32-symbol alphabet, 7 data symbols plus one symbol that is both the checksum and the XOR key. There are 3,898,605,568 valid codes, and the published list of 22 level codes is a tiny slice of that. Two of the published cheat codes are OCR errors (FFOOWP36 is really FF00WP36). Classic.
Before that decoder runs, though, the password screen checks a hard-coded 7-entry table of developer strings:
| Code | Effect |
|---|---|
CR3D1TZZ | credits |
H4X0RD1Z | a “1337” screen |
T4K34W4Y | a photo from the studio |
D3BVGPLZ, H34LTHY*, W34P0NZZ, M3H34LTH | set RAM flags only |
None of these show up on any cheat site I checked, and an exact-string search for them turns up nothing game-related.

The T4K34W4Y “photo” is a face built out of plastic bags(?) with two clear plastic cups for eyes.

Batman: Vengeance - the password table is hidden from strings
The published Batman: Vengeance list (20 story levels, 16 Advance Mode levels, plus NORA, LSMRTG and CREDITS) is complete and correct. But grep the ROM for GRAYSON, ALFRED or BATARANG and you get nothing, which makes them look fake.
They aren’t fake. The 53-record table at 0x08069614 stores every character as ASCII + K[pos], using the per-position bias 21 14 09 0B 17 45 3C 0A. Undo the bias and you get the full table, including records no list has ever printed:
| Code | Effect |
|---|---|
HOWDEYDO | hidden developer-photo slideshow |
QPMTRL | hidden team photo |
PSCLCTT | freezes the Advance Mode timer at 9:99 |
MRCLVLRL | sets all four cheat bits at once |
GLMTKVN | third ammo counter → 255 |
LHSBST, JQSLGS | same cheat bit, two spellings |
There is also a typeable FLYMODE record that the dispatcher deliberately routes to the invalid path. Six other records contain the digit 1, which the A–Z keyboard can’t produce.


Antz Extreme Racing - a two-stage developer handshake
The Antz password is the most over-engineered in the set. 9 symbols (45 bits) go through a fixed invertible affine transform over GF(2) into a 48-bit buffer, then a 4-bit fold checksum, a mixed-radix payload with radices 2,5,7,12,7,50,2, a non-decreasing “opened items” list, and cross-field range checks. That gives 1,655,267,328 accepted strings.
Before the generic validator, though, there’s a little state machine:
- Type
*CL3M3NT(8 symbols). The entry buffer silently clears and stage 1 is armed. Nothing on screen says anything happened. - Then type
*M4M1K0(7 symbols). The screen fades to a developer photo.
Both literals are stored XORed with a running key (0x55+i and 0x42+i), so they don’t show up in a string dump either. The second code does nothing on its own. Published Antz lists only have the 12 level codes, and one of those, “Level 13”, actually decodes to Level 1 with 12 levels opened.

Power Rangers: Ninja Storm - the publisher’s initials
Ninja Storm’s 3-character password packs 11 data bits and a 4-bit checksum into 15 bits. The encoder reproduces 23 of the 24 published codes. The 24th, GLW (Thunder Rangers, level 5), is a typo that’s published online today. The real code is GLG.
The submit handler then makes one extra call. 0x0804955C returns success if and only if the buffer holds symbol indices (15,5,12):
THQ
That plays the credits. The only “THQ credits” code I could find published is for the GameCube Dino Thunder, a different game from the same publisher. It looks like a house habit that went unnoticed on the GBA.

Back Track - two console commands nobody listed
Back Track hides a fake DOS prompt (Welcome to BSBODSOM / DOS Version 0.9Beta) behind Select, L, Right, B, L, R, Left on the pause menu. The published lists have nine commands (GOD, WEAP, AMMO, HEA, KEY, FRE, ARM, MON, COOR). The table has eleven in that context. TI turns on a hidden numeric debug readout in the HUD, and FAIL writes 0x1FFF to the level’s failsafe word. A second, mutually exclusive context (the in-level computer terminals) has PASSWORD and JV alongside the published JAG and VINCE.

FAIL doesn’t change anything visible, so it isn’t pictured. The picker also caps input at 17 characters, and the screenshots show that too.
Backyard Baseball 2006 - the unlock conditions had coach-name shortcuts
Published GBA lists give two coach names (BABYBEAR for Sammy Sosa, BIGFISH for Dontrelle Willis). They list every other unlock as a gameplay task: “earn 20 skill certificates” for Abner, “complete the fielders challenge” for Barry Dejay, and so on. The 9-entry table in the ROM has a coach name for each of them:

| Code | Unlock |
|---|---|
NACHOS | Abner Dubbleplay |
HOOPS | Barry Dejay |
LIBERTY | Jim Thome |
ANCHOVY | Mike Piazza |
SPACEMAN | Quantum Field |
SHOWTIME | Humongous Memorial Stadium |
ATLANTIS | Aquadome |
HOOPS has a known ancestor: it’s the Barry Dejay coach name in the PC Backyard Baseball 2005. The other six I couldn’t find for any version. The ROM also contains a complete Cheat Manager v1.0, gated on a held-input value of 0x3080. No controller can produce that, because bits 12–13 aren’t buttons. The 2007 sequel ships the same table minus ATLANTIS, with the player rewards swapped for 2007 rosters.
Big Mutha Truckers - a second code in a two-entry table
The one published GBA code (Up L Right Right A B Down Down R at the title screen → Evil Bob’s truck) lives in a two-record button table at 0x082812AC. The second record, Up Down Left R B A Right L, is accepted by the same validator with the same flash and sound. It sets bit 1 of the cheat bitmap at 0x02000145. Nothing in the ROM reads bit 1, so it’s a working cheat code with no cheat attached.

Both codes get the same white-flash acknowledgement. Only one of them changes anything.
Kelly Slater’s Pro Surfer - four toggles behind a 12-press shoulder code
Every published Kelly Slater code is for the console versions’ in-game cell phone. The GBA cart has its own system:
L R L L R R L L L R R R (main menu)
That sets bit 0 of 0x020041E4, and the Extras screen switches to an 11-item template with four new toggles: (Cheat) Beach (13/13 beaches), (Cheat) Boards (13/13 boards), (Cheat) Clips (all 13 Clip Book photos) and (Cheat) Champ (forces your heat score to a perfect 10.0). None of it is saved, so the code has to be re-entered every session.

Dragon Ball GT: Transformation - the unlock-all code
GT’s title menu has a 9-entry button table. Five codes unlocking one character each are on every cheat site. The other four aren’t: an unlock-all-five code, a +20,000 Zeni code, and two flag-setters whose visible effect wasn’t pinned down. The first two were confirmed in mGBA. I found character-by-character codes and CodeBreaker Zeni codes published, but no button-entry versions of either.
Both are 17 presses long (L/R are the shoulder buttons):
Unlock all five: Down Up Left Left Down Up Left Left Down Up Left Left Up Up Down Up B
+20,000 Zeni: Up Down B Left Right B L R B Up Left Down L R L R B

These are two separate sessions. Neither effect survives a trip into Story Mode, which reloads the profile from SRAM.
Smaller confirmed finds
Board Game Classics. The six-digit password screen compares against exactly three strings. 192845 and 446218 are known. The ROM’s level-1 entry, 000413 (Fantasy set), isn’t on Cyberly or anywhere else I looked.

Golden Nugget Casino. The 13-character bankroll password packs a 24-bit money field. Minting the maximum, !!!!v#dbbbxb= ($16,777,215), triggers a “You’re a Multi-Millionaire — Time to retire!” ending I couldn’t find described anywhere. One caveat: the keypad cursor is so timing-sensitive that the agent placed this code in the game’s own password buffer from a savestate and submitted it through the normal OK handler. The ending is real. The keystrokes weren’t typed. The lower novel code, BPRDv#dbbbxb3 ($9,100,000), was typed normally.

Barbie as the Princess and the Pauper. The portrait password table has 46 accepted entries, and only about half are published. 6,6,6,6 (four Julians) jumps straight to the end credits.

Bomberman Tournament. TCRF documents a ROM patch that boots the TEST SELECT menu. The report goes on to enumerate all 16 entries, including FLAG SET, a 16×16 editor for the game’s 256 runtime flags at 0x02035274. This one isn’t reachable on a retail cart: it needs the one-byte patch (movs r0,#0x3C → #0x5A at 0x08000CBA).

Battle B-Daman. Every list I found prints the first Zero Code as B-DAMAN. The validator rejects it. The ROM stores GO B-DAMAN (1,000 B-Dabucks). There’s no screenshot: the Zero Code screen sits behind a story-gated shop, so this result comes from calling the game’s own validator through the GDB stub, not from the retail UI.
Minor novelties
These were flagged as “unpublished” in the agent reports. A web search said otherwise:
Crash Bandicoot Purple from the 2-in-1 cart:
SW1NGS3T(the hidden Spyro Party USA minigame) is on CheatCC and Cyberly. So are the staff-name codes (ST4CY,J0NNY,TR4V1S,C0L1N,BR3NT…) What does look new is a UI defect: the keypad caps input at 10 characters, and the ACCEPT cell stops responding once all 10 are filled. The widely publishedSTR4WB3RRYandWVMP4FR00Tare exactly 10 characters, so they’re valid table entries that can’t be submitted on the shipped game.
The keypad has no vowels, so the fourth glyph really is a
4. Three more presses of A after this frame left the screen unchanged.Beyblade VForce: three of the “novel” title-screen sequences (
Right, Down, R, L,L, Left, R, Right,L, R, R, L, B) are published. The report’s real contribution is what they do: memory diffs show two of them write flags no code appears to read. Raising some interesting questions about how that cheat code came to be published in the first place.Legacy of Goku I: The debug menu has five rows where published lists name four. TCRF already describes all five functions. The second entry point (Options from the in-game pause menu) is the only new-ish part.

Ninja Storm Hard mode:
BKB, given as a novel “Green Ranger, level 1, Hard” code, is on SuperCheats as “gives you the Green Ranger”. The Hard-difficulty bit is the new detail, not the string.
Cheat input architectures
Once you have 100 of these side by side, they sort into a small number of designs. Each design has its own failure modes, and the gaps are where the interesting findings come from.
flowchart TD
IN[Player input] --> T{Input surface}
T -->|text / symbol grid| P[Password screen]
T -->|controller edges| B[Button-sequence matcher]
T -->|held chord| C[Chord / mask gate]
T -->|name field| N[Name-as-code]
P --> L[Literal table<br/>strcmp / memcmp]
P --> O[Obfuscated table<br/>bias / XOR / custom charset]
P --> A[Algorithmic codec<br/>state + checksum]
P --> H[Hybrid<br/>special cases before decoder]
B --> S1[Strict state machine]
B --> S2[Subsequence / suffix / substring]
C --> M1[Exact equality]
C --> M2[AND mask]1. Literal tables: the honest crackme
Most of the time a cheat is a fixed table compared with strcmp. A Sound of Thunder walks an 11-record {char *code; void (*apply)();} table. Ballistic: Ecks vs. Sever has two closed tables (9 cheats and 20 levels) behind one screen. Alex Rider: Stormbreaker binds each of its 10 strings to a slot, so a correct code typed under the wrong cheat name is rejected. Blades of Thunder doesn’t even store strings: it converts four digits to an integer and runs a 30-constant comparison tree.
The portrait passwords in licensed kids’ games work the same way. Atomic Betty packs four portrait choices as a base-8 number and searches a 21-entry u32 table, and three valid slots (including the screen’s default Betty×4) were missing from published lists. Barbie in the 12 Dancing Princesses has a 416-record table (13 levels × 32 variants). 232 of those records contain a symbol the 8-icon ring can’t produce, leaving 184 enterable codes, of which 13 are published.
The gap with literal tables is completeness. The developer often tested more codes than were ever announced. Running the game’s own validator over the entire input space, as was done for Blades of Thunder’s 10,000 inputs and Pegasus’s 1,296, turns “I found N codes” into “exactly N exist” and shakes out the leftovers.
2. Obfuscated tables: hiding from strings
The step up from a literal table is a literal table that doesn’t look like one. In this set:
- Per-position bias: Batman: Vengeance (
byte = ASCII + K[pos]). - Running XOR: the Antz developer codes (
0x55+i). - Custom glyph encodings: Castlevania: Harmony of Dissonance and Aria of Sorrow store
HARDGAME,NO MAGIC,JULIUSand the rest asASCII − 0x3F. A grep forHARDGAMEfinds nothing and the system looks absent. Battle B-Daman runs input through a 34-entry control-code expansion table before itsstrcmp.
None of this is security. It’s a speed bump against a hex editor. The main effect, twenty years on, is that it makes valid published codes look fake. An analyst who greps for ALFRED, finds nothing and calls the published code wrong has been fooled by a one-byte add.
3. Algorithmic codecs: the password is a save file
Games without battery saves serialize their state into a password, and these are the true crackmes. The game ships both an encoder (the screen that shows you your password) and a decoder, so once you’ve reversed the pair you can mint a password for any state the format can represent.
The checksums vary a lot more than “sum the characters”:
| Game | Integrity check |
|---|---|
| American Idol | 8-bit sum of nibbles + 13 |
| ATV: Thunder Ridge Riders | 10-bit sum split across two symbols |
| Fievel’s Gold Rush | 5-bit checksum, exactly one valid string per payload |
| Army Men: Operation Green | the checksum symbol is the XOR key |
| Scooby-Doo Cyber Chase | six even-parity bits over sliding windows, per-column Caesar key |
| Power Rangers Time Force | per-field parity plus a parity-of-parities |
| Boktai 2 | inverted CRC-16/CCITT + LCG descrambler over a 192-bit stream |
| Velocity X | base-9 → 40-round permute/rotate/toggle network → popcount checksum |
| Antz Extreme Racing | affine GF(2) transform + 4-bit fold |
| Ace Combat Advance | none, only marker bits identify each symbol’s field |
| Hot Wheels World Race | none, 20 bits must be zero, the other 20 are payload |
| SpongeBob: Revenge of the Flying Dutchman | none, validity is that three 5-bit groups are unary |
The most interesting one is BattleBots: Design & Destroy, where codes are coupled. The 22-character bot password carries a 6-bit checksum that has to equal a per-class seed stored in the separate 15-character team password. Published bot codes fail on a fresh game because the lists never included the team code that goes with them. Seven of the ten published bot codes turned out to be genuine. They just needed a minted companion team password.
The gaps in algorithmic codecs are the most consistent across the whole set:
- Unchecked fields. American Idol never validates the top payload byte, so 256 different strings decode to every state. Horse Adventures masks its check field to 8 bits and ignores two bits of the last symbol, giving four spellings per state. In Army Men Advance, 5 of the 8 symbols are free filler, which gives each real level between 13 and 30 million valid spellings.
- Checksum valid, range unchecked. Fievel accepts world 0 and world 7 and then hangs on a white screen. Alienators accepts level 16 and crashes at
0xFFFFFFFE. Army Men Advance accepts level 13 and loads a briefing from the German text bank. A checksum only proves the string is well formed. It doesn’t prove the game has content for it. - The game’s own encoder emits bad codes. The password Alienators displays for a fresh Normal game has stale check characters, so the game rejects it. Two characters have to be repaired by hand.
- Formats bigger than the content. Ace Combat accepts arbitrary per-mission S-rank subsets. Time Force accepts a final-chapter, mode-2 state (
W3DB) that no published code uses, and the game’s own pause screen printsW3DBback. That round trip proves the generator would have produced it.
4. Hybrids: special cases before the decoder
Several games run an algorithmic codec but check a few magic strings before the decoder: Ninja Storm’s THQ, Operation Green’s leet table, the Antz handshake, Rise of Sin Tzu’s _NDTH_ and _FLYM_, Scooby-Doo’s 15 literal special codes sharing a screen with its 40-bit progress passwords. This is where developer Easter eggs live, because it’s the cheapest place to add one. The decoder can’t see these strings, so minting codes from the format will never find them. You have to read the submit handler.
5. Button-sequence matchers: the semantics are the attack surface
Button codes look trivial: compare presses against a list of masks. But the matching semantics decide which input language is actually accepted, and they differ widely:
- Strict state machine with a fail latch. Advance Guardian Heroes accepts exactly one 7-press string out of 10⁷. Any wrong non-zero press sets a fail bit that sticks for the rest of the logo screen. Zero-key frames are ignored, so holding a button between presses is fine.
- Subsequence, never reset. Animal Snap’s progress index isn’t reset by a wrong press. Any stream containing the 8 correct D-pad edges in order, with L held, is accepted, decoys included.
- Suffix match on a ring buffer. Batman Begins maps presses to characters, appends them to a 10-byte ring, and compares the last 8 against each code. A match XOR-toggles a flag, so entering a code twice turns it off. Four of its eight slots hold
xxxxxxxx, and no button maps tox, so those four flags (one is the debug HUD) can only be set with a memory editor. - Latest substring wins. The Backyard Basketball engine runs
strstrfor all 17 entries over a 29-byte press buffer and keeps the match that occurs latest. That’s howB Select Select B B B B A(not in the table at all) resolves to the 10-second-quarters cheat. In Basketball 2007, 14 of the 20 entries turn out to be power-up selectors that no published list mentions. - Per-key timeout windows. Beyblade VForce gives each press a 60-frame window. Aggressive Inline has a timeout path that clears the 8-press counters but forgets the 4-press ones, so
L, B, R, Bstill completes after a five-second pause while the 8-press codes fail. - Prefix plus dispatch. 007: Nightfire matches a fixed 6-button prefix and then dispatches the seventh press against four masks: god mode, 500 ammo, all missions, high-pitched voices. Enumerating every branch of the dispatcher is how you prove there isn’t a fifth.
6. Chord gates: equality vs. mask
Boot-time chords are a single comparison, and that one comparison decides how many inputs pass. Advance Wars uses exact equality against 0x214 (L + Right + Select): one state out of 1,024, plus an explicit guard that refuses the soft-reset chord. Banjo-Kazooie: Grunty’s Revenge tests (~KEYINPUT & 0x214) == 0x214, an AND mask, so every superset passes: 128 of 1,024 combinations erase your save, Select + L + Right + Up included.
7. Dead, stubbed and impossible: the developer did lock the door
The last category isn’t a way to enter cheats, it’s a way to remove them. It’s the most common finding in the set, and each one needs different proof:
- Stubbed gate. Spider-Man: The Movie’s pause-menu
Cheatlevel/Cheat Zaphandlers both call0x0900074C, whose entire body ismovs r0,#0; bx lr. Banjo-Kazooie’s fullVER 0.42.75debug menu (CHEATS, GOD MODE, six warp pages) is wired to a frame hook initialized to a no-op. - Impossible value. The Backyard 2006 and 2007 Cheat Managers compare held input against
0x3080. Batman Begins’xslots need a button that doesn’t exist. Batman: Vengeance has records containing a digit on an A–Z keyboard. - Bounds-checked menu. Backyard Skateboarding’s credits proudly print two button codes. The title handler only reads A and Start. The “unlocked mode” really exists, as case 4 of the main-menu dispatcher, but the menu has four items and the selected index is bounds-checked, so index 4 can never happen. The credits advertise a cheat the game can’t accept.
- Cut feature. Bionicle: Matoran Adventures has one
ENTER PASSCODEstring in English. In all seven other languages that slot holds the literal placeholderTEMP. - UI defect. Crash Purple’s 10-character ACCEPT bug: the table is fine, the code is fine, the keypad is broken.
What 100 crackmes teach
Most of what the agents got wrong was process, not reverse engineering. They were very good at turning a validator into pseudocode and a working Python codec. They were bad at saying “this is new/novel” with confidence, and occasionally bad at noticing that the harness, not the game, was eating input. A key repeat double-stepping cursors, a cracktro that broke the joypad reader, a single-client GDB stub silently shared by two agents, etc…
The other lesson is about published cheat lists. Across 100 games they contained OCR O/0 swaps, truncated codes, wrong difficulty labels, codes from other platforms and editions, and SEO-generated fakes. Meanwhile the ROMs, which never got a patch, still held codes that never made it into any list.
If you want ground truth for a 2003 cartridge, it’s in the ROM. If you want accuracy, you validate through process.