Introduction
Here is a claim that should feel slightly wrong the first time you read it: on an original Game Boy, the list of items in your Pokémon Red bag can be executed as code. Not “interpreted”, not “simulated”. The actual CPU fetches your Potions and Poké Balls, decodes them as instructions, and runs them.
By the end of this article you will understand exactly why that is possible, and you will have walked through the smallest interesting version of it: getting the Game Boy’s CPU to execute one instruction that you chose, planted by hand inside the item bag. We stop the moment that instruction runs. Chaining instructions into a full payload is a separate (large) topic, and the conclusion says a word about where that road leads.
This is, in miniature, a real exploit primitive: a buffer you control, plus a jump into that buffer, equals code execution. The same shape shows up in memory-corruption bugs on modern software. The Game Boy just lets us see it naked, with none of the defenses a 2020s machine would put in the way.
I am assuming you write C, that pointers and memory addresses hold no fear, and that you have met the idea that code and data share the same memory on a von Neumann machine. That last point is the only prerequisite that really carries weight here, because the interesting part is not the fact itself but its consequence, which the next paragraph spells out. Everything else is fair to not know: the Game Boy’s internals, this particular glitch, how exploitation works in general. That is what the article is for.
One practical note before we start. If you only want to read, you need nothing. If you want to reproduce the two demonstrations, and you should, because they are the fun part, you will want a Game Boy emulator with a debugger. The appendix names one, and it takes about a minute to set up.
The one idea to keep in mind
You already know code and data share memory. The consequence we usually forget
is this: the CPU never checks which is which. It has a program counter, the
program counter holds an address, and the CPU fetches the byte at that address
and executes it as an instruction. That is the whole decision procedure. The
byte 0x3E is “the number 62” or “the start of a ld a, n instruction”
depending on one thing only, and it is not a property of the byte. It is whether
the program counter happens to point at it during a fetch.
So the boundary between code and data is not physical. It is drawn entirely by the control flow (where the program counter goes) and by whatever memory protection the hardware enforces. Modern CPUs enforce a lot. The Game Boy enforces none. That gap is the vulnerability this whole article lives inside.
The stage: just enough Game Boy
We need three facts about the machine. No more.
The CPU. The Game Boy runs a Sharp LR35902, an 8-bit processor whose
instruction set is close to the Z80. For our purposes it has an accumulator
A, some general registers (B, C, D, E, H, L), a 16-bit stack
pointer SP, and a 16-bit program counter PC. “Accumulator” is the
historical name for the register the CPU privileges above the others: most
arithmetic and load instructions read and write A implicitly, so it is where
the value being worked on tends to sit. That is why our demonstration
instruction targets A, and why inspecting A afterwards is proof enough that
it ran.
The program counter. PC holds the address of the next instruction. The CPU
fetches the byte there, decodes it, executes it, and advances PC past the
bytes it consumed. Jumps, calls, and returns are nothing more than writes to
PC. There is no separate notion of “this region is code, that region is data”.
PC can hold any 16-bit value, and the CPU will fetch from wherever it points.
The memory map. The Game Boy has a single flat 16-bit address space,
0x0000 to 0xFFFF, carved into regions:
0000 - 3FFF ROM bank 0 (the cartridge program, fixed)
4000 - 7FFF ROM bank N (switchable)
8000 - 9FFF Video RAM
A000 - BFFF Cartridge RAM (save data, if present)
C000 - DFFF Work RAM (WRAM) <-- your game state lives here
E000 - FDFF Echo RAM (a mirror of C000-DDFF)
FE00 - FFFF OAM, I/O, High RAM, interrupt enable
Note: why does Echo RAM exist? It is not extra memory, and nobody designed it as a feature. The console decodes addresses with fewer lines than the full 16 bits, so the
E000-FDFFrange physically selects the same WRAM cells asC000-DDFF. Write a byte to0xD31Eand the same byte reads back at0xF31E: one chip, one byte, two windows onto it. The duplication was an accidental consequence of the hardware design, not an intended programming feature, and Nintendo’s documentation advised developers not to use it.
The part that matters: your Pokémon game state, including the item bag, sits in
Work RAM, and Work RAM is readable, writable, and, crucially, executable.
There is no memory management unit, no privilege level, no per-page “no execute”
bit. Nothing anywhere on this machine says “the program counter is not allowed
to point here.” If PC lands at 0xD31E, the CPU fetches from 0xD31E and
runs it, exactly as it would from ROM.
Note: why “no execute” is even a thing. On a modern OS, writable pages are marked non-executable (this is DEP / NX, a form of W^X: write XOR execute). Jump into a buffer you just wrote and the CPU faults. The Game Boy predates all of that by decades, so a byte you can write is a byte you can run. Hold onto this contrast; it comes back in the conclusion.
That is the entire stage. Three facts: the CPU blindly follows PC, WRAM holds
our data, WRAM is executable. Now we go get a buffer we control.
Step 1: the item bag is writable memory
The Pokémon Red item bag is not a special structure. It is a small, well-known stretch of Work RAM. From the pokered disassembly we know its layout exactly:
| Address | Meaning |
|---|---|
0xD31D |
item count |
0xD31E |
item 1 - ID |
0xD31F |
item 1 - quantity |
0xD320 |
item 2 - ID |
0xD321 |
item 2 - quantity |
0xD322 |
item 3 - ID |
0xD323 |
item 3 - quantity |
| … | … |
0xD344 |
item 20 - ID |
0xD345 |
item 20 - quantity |
0xD346 |
0xFF end-of-list marker |
So the bag is a count byte followed by twenty slots, and one slot is one
item: two consecutive bytes, an ID byte and then a quantity byte. Slot 1 is the
pair 0xD31E-0xD31F, slot 2 is 0xD320-0xD321, slot 3 is
0xD322-0xD323, and so on until the 0xFF that closes the list. Forty bytes
of ID-and-quantity in total, all of it in executable WRAM. Fix that “one slot,
two bytes” convention in your head now, because Step 2 plants an instruction
across exactly one such pair.
You can verify this yourself in about a minute. Load a save in an emulator with
a debugger, open a memory view, and jump to 0xD31E. Now, in the game, look at
your first item. Say slot 1 holds Potion x5. The byte at 0xD31E is the
Potion’s item ID, and the byte at 0xD31F is 0x05. Toss one Potion so you
have four, and watch: 0xD31F changes from 0x05 to 0x04. Buy a fifth, and
it goes back to 0x05.
That is the whole point of Step 1. The quantity shown in the menu and the byte in RAM are the same thing. Every time you use, buy, toss, or reorder an item, you are editing bytes at known addresses. The bag is a memory editor with a friendly UI. It is a buffer, and you control its contents.
Note: quantities go further than the menu admits. Normally a quantity is 1 to 99. Through the item-underflow glitch (see the appendix), quantities can be forced to any value from
0x00to0xFF. That matters, because it means the quantity bytes can hold any byte we want, which is exactly what we need in the next step. For now, just note it is possible; the mechanism is a rabbit hole of its own.
Step 2: planting your bytes
We have a buffer in executable memory whose contents we can set. Now we decide what to write.
Remember the one idea: those forty bytes are only “item data” because nothing
has pointed the program counter at them. If we can get PC to arrive there, the
CPU will read the same bytes as an instruction stream, walking straight across
the (ID, quantity) pairs without any idea that a boundary was ever supposed to
exist. The “item ID / quantity” structure is a fiction maintained by the item
menu code, and the CPU is about to ignore it completely.
So let us choose an instruction. Something small, unambiguous, and easy to see land. I will use:
3E 2A ld a, $2A ; load the value 0x2A into register A
0x3E is the opcode for “load an 8-bit immediate into A”, and the next byte
is that immediate. Two bytes, one instruction, one visible effect: after it
runs, register A holds 0x2A. If we see A become 0x2A, we know our
instruction ran and nobody else’s did.
Now encode it as items. One fact has to be borrowed from Step 3 to do that:
8F is a glitch item, and using it makes the CPU jump into the item bag. Where
it lands is not our choice. The address falls out of the glitch itself, and with
the standard setup it is 0xD322, the ID byte of slot 3. So that is where the
instruction has to go, whether we like it or not:
| Address | Byte | As an item | As code |
|---|---|---|---|
0xD322 |
0x3E |
item 3 - ID | ld a, $2A (op) |
0xD323 |
0x2A |
item 3 - quantity (= 42) | ld a, $2A (imm) |
0xD324 |
0xC9 |
item 4 - ID | ret |
Concretely: give item slot 3 an ID byte of 0x3E and a quantity of 42, and give
slot 4 an ID byte of 0xC9. That is it. You have hand-assembled
ld a, $2A ; ret out of nothing but a shopping list.
Which answers the obvious question about the first two slots: we do not use them
for anything, and we could not have started the instruction earlier even if we
wanted to. Execution begins at 0xD322 and moves forward, so the four bytes of
slots 1 and 2 sit behind the program counter and are never fetched. Slot 1 is
where 8F itself normally sits, and slot 2 can hold any ordinary item you like.
They are not part of the payload; they are just below the landing site.
Note: how you actually pick the items. You do not memorize opcodes as item names. The community keeps tables mapping every byte value to the item it represents, and quantities (0 to 255, thanks to the previous note) give you free bytes directly. In practice you look up which item has ID
0x3E, put it in slot 3 with quantity 42, and give slot 4 the item whose ID is0xC9. The lesson underneath the bookkeeping: an opcode and an item ID are the same byte wearing different labels.
The ret on the end is housekeeping. Once our chosen instruction has run, we
want the CPU to return cleanly to normal game code instead of stumbling forward
into whatever bytes come next and crashing. It is not part of “the instruction
we chose”; it is the safety net that lets us stop on our terms.
Step 3: the jump
We have a controlled buffer with our bytes in it. The last piece is getting the
program counter to point at 0xD322. This is the jump, and it is where the
8F item earns its reputation.
Note: what is
8F, exactly? An item that was never supposed to exist. Item IDs in Red and Blue are a single byte, so there are 256 possible values and far fewer real items;0x5Dis one of the unused ones. Ask the game to display it and it reads character tiles from past the end of the item-name table, which on the English releases renders as the garbled string “8F” (other localisations show something else entirely, which is why you will see this item under different names depending on the region). It cannot be obtained in normal play; the appendix covers where it comes from, and how to skip that entirely by placing it in your bag with an emulator.
When you select a normal item and choose “use”, the game looks up a function
pointer for that item’s field effect and calls it. 8F has none, so the lookup
runs off the end of the intended table and produces a garbage pointer. That
pointer
resolves into Work RAM, and the CPU jumps there. In other words, using 8F
sets PC to an address inside the RAM block that holds your Pokémon and item
data. With the standard setup, execution slides down through some harmless
leading bytes and arrives at the start of your item list, right at slot 3, where
we planted ld a, $2A.
Read that again, because it is the entire exploit in one sentence: selecting an item causes the program counter to jump into a buffer whose contents you wrote. Controlled data plus a controlled jump into it equals controlled execution.
Let us watch it happen rather than take it on faith. In an emulator debugger:
- Set the item slots as in Step 2 (slot 3 =
0x3E/ qty 42, slot 4 = ID0xC9), and have8Fin your bag. - Put an execution breakpoint at
0xD322, the address of our first planted byte. - Note the current value of register
A. It will be some ordinary game value, definitely not0x2A. - Open the bag and use
8F. The breakpoint trips. The debugger stops withPC = 0xD322, sitting on the byte0x3E, about to fetch it as an instruction. This is the moment the fiction collapses: the program counter is now pointing at what the menu still calls “item 3”, and it is going to run it.
Single-step once. The CPU fetches 3E 2A, executes ld a, $2A, and advances
PC to 0xD324. Check register A.
It reads 0x2A.
That value is there because the CPU executed an instruction we authored, byte
for byte, from inside a Pokémon save file. We chose the instruction, we chose
where it lived, and we chose the moment it ran. Step forward once more and the
ret at 0xD324 returns control to normal game code, and the game keeps
running as if nothing happened. Mission accomplished: one chosen instruction,
executed and verified.
Conclusion
Everything above rests on the single idea from the introduction. Code and data
are the same bytes, and on this machine nothing stops the program counter from
treating one as the other. We turned that gap into a concrete capability in
three moves: we found a buffer we control (the item bag, Step 1), we filled it
with a chosen instruction (Step 2), and we redirected the program counter into
it (Step 3, courtesy of 8F). The item menu insisted we were editing an
inventory. The CPU disagreed.
We deliberately stopped at one instruction. The natural next question is how you
get from ld a, $2A to something that does real work, and the answer is that
you keep going: place more instructions after the first, and since the CPU just
walks forward through memory, it executes them in sequence. The bag is small, so
serious payloads use the early bytes as a bootstrap, a short loader that
pulls a larger program in from somewhere roomier (text input, box data, even the
link cable) and jumps to it. That is how people beat the game from the item
menu, or repaint the screen, or run whole new programs. Same primitive, more of
it.
Note: what this looks like on a machine that fights back. Our whole approach was code injection: write new bytes, jump to them, run them. It works only because the Game Boy has no memory protection. On a modern system, DEP / NX marks writable memory non-executable, so the jump-into-your-buffer trick faults instantly. Attackers adapted with return-oriented programming (ROP): instead of injecting new code, they chain together fragments of existing executable code (short sequences ending in
ret, called gadgets) to assemble the behavior they want, one return at a time. ROP is more work precisely because injection is off the table. The Game Boy exploit and a modern ROP chain are answers to the same question, “how do I make the CPU run my logic”, separated by thirty years of defenses. Seeing the undefended version first makes the defended one much easier to understand.
If the naked version stuck with you, the appendix is where you go deeper.
Appendix and references
Follow along. BGB is a Game Boy emulator with a solid built-in debugger (memory viewer, breakpoints, single-step, register display). Everything in Steps 1 and 3 is meant to be reproduced there.
Ground truth for addresses and routines. The pokered disassembly
(pret’s reverse-engineered Pokémon Red/Blue source) is where the 0xD31D
item-bag layout and the item-use code come from. If you want to know why a byte
is where it is, it is in there.
The glitch, documented. Bulbapedia’s Arbitrary code execution article
and the Glitch City Wiki cover 8F (ID 0x5D), the item-underflow
glitch used to obtain it and to force 0x00-to-0xFF quantities, and the exact
bootstrap offsets that Step 3 kept at arm’s length. Treat these as recipes; this
article was the “why the recipe works” that they mostly skip.
How to obtain 8F. The standard route is the
item-underflow glitch: underflow the bag’s item counter to 0xFF,
exposing slots that overlay unrelated memory (the “expanded item pack”), then
maneuver until one of them reads as item 0x5D and pull it into a real slot. It
is fiddly, save-corrupting and version-specific, so if you only want the
mechanism above, skip it: in an emulator’s memory editor, write 0x5D into an
item-ID byte (say 0xD320, slot 2) with a sane quantity, and 8F is in
your bag.
Going further on defenses. For the conclusion’s ROP detour, three next steps, in increasing order of effort. Wikipedia’s return-oriented programming page is the fastest overview of gadgets and chaining. ROP Emporium is the practical route: a series of challenges built to teach ROP in isolation, with a beginners’ guide, so you assemble chains yourself instead of reading about someone else’s. And Hovav Shacham’s 2007 paper The Geometry of Innocent Flesh on the Bone is the original systematic treatment, the one that showed gadget chaining is Turing-complete on x86. The primitive is identical to ours; only the obstacle course changes.