In this article we will talk about the Old Man glitch and what causes it.
What is it?
The Old Man glitch is a programming error in Pokemon Red and Blue that allows the player to encounter the glitch Pokemon ‘MissingNo.’ (short for Missing Number); as well as a series of other glitch Pokemon dubbed ‘name data Pokemon’. The glitch’s name comes from the first step needed to perform this glitch; in particular, you must first talk to an ‘Old Man’ who teaches you how to catch a Pokemon near the beginning of the game. After talking to the Old Man, it is possible to encounter corrupted Pokemon in the wild.
If performed correctly, you should encounter ‘MissingNo.’, whose sprite looks like the following:
How to Perform the Glitch
The following are the in-game steps you need to perform to trigger the bug.
- Set up the trainer name with particular characters in particular positions.
- Talk to the Old Man in Viridian City, i.e., the man that shows you how to catch Pokemon. Say ‘no’ to his question and watch his demonstration.
- Fly to Cinnabar Island without leaving Viridian City.
- Surf along the shore on the right side of the island and you will encouter MissingNo.
Explanation
To understand the glitch, we first need to discuss how wild Pokemon encounters work.
How Wild Pokemon Encounters Work
Pokemon games have two main types of areas: routes and towns. Towns contain buildings such as gyms, marts, and Pokemon Centers, whereas routes contain trainers you can fight and wild Pokemon you can catch. When you enter a route, the game will load a table that defines the set of wild Pokemon available on that route. The assembly code for loading this data when the player enters Route 1 looks like this:
Route1Mons:
db $19 ; 25% grass encounter rate
db 3,PIDGEY ; level 3 pidgey
db 3,RATTATA
db 3,RATTATA
db 2,RATTATA
db 2,PIDGEY
db 3,PIDGEY
db 3,PIDGEY
db 4,RATTATA
db 4,PIDGEY
db 5,PIDGEY
db $00 ; 0% water encounter rate
; no water Pokémon defined because they aren't needed
There’s not much going on here, but the code can be confusing if you have never
seen GameBoy assembly before. Here db
stands for define byte
. The db
instruction is used to place the operand byte(s) directly in memory. You can
think of Route1Mons
as a reference to an array of bytes starting with hex
value 0x19
(the $
denotes hex notation). Every route has a similar array
defined, and that array is loaded in to the encounters table whenever the
player enters a route.
The first byte in the encounters table denotes the rate of grass encounters
(25% for Route 1). The next 20 bytes denote the different Pokemon that may be
encountered in the Route 1 grass. Specifically, one byte is used to define the
Pokemon’s level and the following byte is used to define the specific Pokemon.
The encounter rate and Pokemon for water tiles is usually defined immediately
following the grass encounter data, but Route 1 does not have any water so the
water encounter rate is set to 0x0
and no water encounter Pokemon are
defined.
When you walk into a new location, the Pokemon data gets loaded via a call to
LoadWildData
. In this function, the engine checks if the NoGrassData
flag
is set. This flag accounts for situations wherein the player is in town. As no
cities or towns have grass Pokemon encounters, the NoGrassData
flag is set
for those locations. If NoGrassData
is set, the game will not load grass
encounter Pokemon data. Importantly, this also means that the previously
loaded grass encounter Pokemon data remains in memory. In other words,
whenever you are in a town, the Pokemon that would appear in grass, if there
were any, would be the Pokemon that were in the last route that you visited.
We can make this behavior more concrete with the following example. As the
player steps onto Route 1 from Pallet Town the Route1Mons
are loaded into
memory starting at address 0xd887
. We refer to this region of memory as the
loaded encounters table. Specifically, the byte at address 0xd887
is
changed from 0x0
(because we were previously in a town) to 0x19
indicating
that the grass encounter rate has changed from 0% to 25% (as hex value 0x19
is decimal value 25). The bytes starting at address 0xd888 will be loaded with
the remaining values of the Route1Mons
table. If you were to walk back into
Palette Town, the grass encounter rate would be set to 0%, i.e., the byte at
address 0xd887
would be set to 0x0; however, the bytes following 0xd887
retain the same values they had when the Route1Mons
were loaded.
Our objective, when exploiting the glitch, is to get values that we control loaded into the encounters table. Suppose we can control the memory of the loaded encounter tables. In that case, we can make MissingNo one of the possible encounters. But first, we need to get the Old Man to teach us how to fight.
Old Man Battle
Near the beginning of the game, when you first come to Viridian City, there is a Non-Player Character (NPC) named ‘Old Man’ who will teach you how to catch a Pokemon. This tutorial is meant for first-timers who don’t know the game’s mechanics, but we are going to use him to make the glitch work. Player’s may talk to him as many times as they would like throughout their adventure. If players let him teach, the game immediately starts a battle between the Old Man and a Weedle, which is a grass-encounter Pokemon.
When the game simulates this battle, it needs to display the name ‘OLD MAN’ instead of displaying your trainer’s name. To achieve this, the game engine first temporarily copies the player’s name to new location in memory. The engine then overwrites the memory previously used for the player’s name with the text ‘OLD MAN’. Once the battle is over, the engine copies the player’s name back to the original location in memory, but the copy of the name remains.
Controlling the Pokemon Encounters
It just so happens that the memory location picked to temporarily store the
player’s name during the Old Man battle is also the location used for the
loaded encounters table, i.e., the memory starting at address 0xd887
.
Consequently, when the Old Man battle finishes, encounter table’s memory is
populated with the player’s name. As we control the player name, we effectively
have control over the bytes written to encounters table during the Old Man’s
fight. By setting the player name appropriately, we can cause MissingNo (and
other Pokemon) to become a possible grass encounter.
Here is a layout of the encounter table after battling the Old Man.
Address | d887 | d888 | d889 | d88a | d88b | d88c | d88d | d88e | d88f |
---|---|---|---|---|---|---|---|---|---|
Purpose | Grass Encounter Rate | Level 1 | Pokemon 1 | Level 2 | Pokemon 2 | Level 3 | Pokemon 3 | Level 4 | Pokemon 4 |
Value | name[0] | name[1] | name[2] | name[3] | name[4] | name[5] | name[6] | 0x80 | 0x00 |
Note, the player’s name can be at most 7 characters so we can directly control only three of the grass encounters.
The Old Man Glitch link in the references section has a table that links
characters to Pokemon and levels, in case you are curious. Not every Pokemon
has a character associated with it, so some Pokemon and levels are impossible
to glitch via this method. For example, if we wanted a Mewtwo, Wartortle, and
Venusaur all at level 127 (the lowest possible controllable glitch level) then
we would name our character A D t (
.
The “backwards L” form of MissingNo, appears if the character in the third, fifth, or seventh slot of the player’s name is G, H, J, M, S, T, :, ], a, b, c, m, o, p, or v.
Looking at the Source Code
Thankfully, a number of people have spent countless hours reverse-engineering Pokemon Red/Blue, so we can look directly at the source code to understand what is happening.
Note: This page will help you understand the gameboy instructions shown below.
Looking at
engine/battle/core.asm:2106
we can see the following code is executed:
ld a, [wBattleType] ; wBattleType is 0 for normal battle, 1 for Old Man Battle
dec a
jp nz, .handleBattleMenuInput
; the following happens for the old man tutorial
ld hl, wPlayerName ; load address of playername into 16-bit register hl
ld de, wGrassRate ; load address of wGrassRate ($d887) into 16-bit register de
ld bc, NAME_LENGTH ; load address of NAME_LENGTH into 16-bit register bc
call CopyData
; copy .oldManName into .wPlayerName
ld hl, .oldManName
ld de, wPlayerName
ld bc, NAME_LENGTH
call CopyData
To understand the flow of data in this section we need to clarify some variable
names. wPlayerName
is the address of the trainer’s name. wGrassRate
is
the address of the encounters table. NAME_LENGTH
is a constant defined to be
equal to 11, although player names are limited to 7 characters.
CopyData will copy bc
number of bytes from hl
to de
one by one. Here
bc
, hl
, and de
are pairs of 8-bit registers combined to form a single
16-bit value.
CopyData:: ; Copy bc bytes from hl to de.
ld a, [hli] ; load value at hl into register a and increment hl
; This will load the current byte of the players
; name into register a
ld [de], a ; Put the byte that is in register a into the address
; referenced to by 16-bit register de
inc de ; increment pointer de to point to the next address
dec bc ; decrement counter bc (counter for data length)
ld a, c ; load bottom 8 bits of counter into a
or b ; or it with b
jr nz, CopyData ; if the counter is not 0, start at the top
ret
As described previously, When the battle is over, the player name is copied
back into wPlayerName
, but a copy remains in the encounters table.
The Last Step: Encountering MissingNo
The final step is to trigger a battle while using our manipulated encounters table. Battles typically only occur on routes, but if we enter a new route, the encounters table will be loaded with the encounter information for that route, overwriting our manipulated encounters table. Thus, we have to figure out how to trigger a wild Pokemon encounter without entering a location that will cause a new encounters table to be loaded.
The solution is to fly to Cinnabar Island without leaving Viridian City. This
will leave the manipulated encounters table intact, with the exception that the
grass encounter rate will be set to 0x0—recall from above that the grass
encounter rate is set to 0x0 when entering towns. At first a zero encounter
rate seems like a showstopper; all of our manipulated encounters are grass
Pokemon and, thus, with an encounter rate of 0 they should never appear.
Fortunately, Pokemon’s developers made a mistake when programming some of the
shore blocks in Cinnabar Island.
Every block the player can walk on is made up of a 2x2 tile grid. The left 2
tiles in the block determine the encounter type, and the right two tiles
determine the encounter rate. Due to a programmer error, the ‘shore’ tiles that
make up the left two tiles along the coast of Cinnabar Island are programmed to
be ‘grass’ type, rather than ‘water’. This causes the wGrassData
Pokemon to
appear at a water encounter rate. In other words, when walking on these tiles,
the game will use our tampered-with grass Pokemon encounters! Success!
Conclusions
Above we described how to control the memory used to determine Pokemon encounters and how to exploit a programming error to get the game to use these manipulated bytes. Finally, by setting these bytes to specially crafted values (via the player name) we can cause MissingNo to appear.
But what does this have to do with security? Well, we wanted to start this class by introducing you to a real-world example of a bug that was found in a program and the resulting exploits that followed. Further, this type of bug is something that you will encounter often in this course. The Old Man Glitch exploits a memory error. Memory errors are a class of bugs that come from mistakes in how a program manages or accesses memory.
As an Aside
It is interesting to see how similar the implementation of CopyData (see above) is to the Stdlib’s memcpy function
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
References
All the source code in this section can be found in the PokeRed repo.
These notes borrow from the writeup found at Glitch City Laboratories.