0x1500 control code arbitrary code execution
0x1500 control code arbitrary code execution (Crystal) | Cart-swap arbitrary code execution | Generation I custom map script pointer | Generation I invalid meta-map scripts | Generation I item ("8F", "ws m", "-g m", "5かい", "てへ" etc.) | Generation I move ("-", "TM42") | Generation I Trainer escape glitch text boxes | Generation II bad clone | Generation II Burned Tower Silver | Japanese Crystal Pokémon Communication Center SRAM glitches | Coin Case glitch | Generation II glitch Pokédex sortings | Pikachu off-screen glitch ACE | OAM DMA hijacking | Pikachu glitch emote | Generation III glitch Pokémon summary | Generation III glitch move animation) | Remote code execution | TM/HMs outside of the TM/HM pocket | ZZAZZ glitch Trainer FC
(view, talk, edit)
List of arbitrary code execution programs
|This article is incomplete. Please feel free to add any missing information about the subject. It is missing: Original speedrunning method needed. Cover starting menu ACE research as well..|
This article is outdated
Feel free to update it.
Reason given: Add Tetsuji's findings
0x1500 control code arbitrary code execution is an arbitrary code execution method found in Pokémon Crystal. It does not occur in Pokémon Gold and Silver.
A specific variation of this glitch involving an unterminated name glitch Pokémon is also known as unterminated name Pokémon arbitrary code execution.
Both of these exploits were discovered by luckytyphlosion. The original method used for speedrunning purposes is not yet covered in this article.
This glitch involves the combination of the byte 0x15 ("Mobile" control character) followed by 0x00 in a text string, and will lead to arbitrary code execution at memory address $CD52. Once the code is terminated with a ret, the program counter by default will be at the location following where the 0x1500 sequence was in the RAM.
Effects of the 0x15 control character
The 0x15 control character signifies a "mobile script" in Crystal. When the text engine reads the byte 0x15, it uses the following bytes as jump table indices to a list of specific functions ("mobile functions"). The valid jump table indices are 0x01 to 0x0f (i.e. 1 to 15), and an index >= 0x10 would end the mobile script interpretation procedure instead of being used as a jump table index. Notice that some mobile functions may "take parameters" by consuming them from the text stream.
However, the byte 0x00 is not excluded by the above check. It would be interpreted as jump table index 256, and the jump target is $CD52, which is a WRAM address used in some mobile functions. Therefore, when the text engine sees the byte combination "0x15 0x00", it will jump there, leading to ACE exploits.
Usually, there are three components to the setup for exploiting this glitch:
- "0x1500" setup: Have a string that, when displayed, cause the text engine read the byte sequence "0x15 0x00". This can be achieved by either putting the sequence in the string itself, or by trying to display an unterminated string, and putting the sequence somewhere after the text buffer.
- Bootstrap: Put some assembly instruction at or shortly after memory address $CD52, in order to jump to some more easily manipulated memory area, usually the box names.
- Payload: The actual arbitrary code to be executed.
These steps are not necessarily done in the above order. For example, the player may first set up the payload in the form of box names, as that is the most robust part of the setup. Then the player may use some specific movements to set up the BG map buffer for a multi-level bootstrap. Finally, the player may use an incomplete toss to set up 0x1500, and view the name of an unterminated name glitch Pokémon to do the exploit.
This article will focus on the "0x1500" setup and the bootstrap. For some examples of payloads, see Crystal box name codes.
Setup and bootstrap methods
Unterminated name glitch Pokémon method w/ traded Lapras and box names
For this method, an unterminated name glitch Pokémon is required. A convenient way of getting one is through a box name corruption glitch in Pokémon Red, Blue, and Yellow, such as through the 9F (0x5E) glitch item in Pokémon Red and Blue.
1) A Lapras with Perish Song (level 29 in Generation II), Bide (TM34 in Generation I) and Safeguard (level 50 in Generation II) which will have its name corrupted. The Lapras should be able to gain experience with an Exp. Share or Rare Candies (in this video Rare Candies are used from outside of the items pack, which allows them to be used effectively infinitely).
2) The 9F glitch item in Pokémon Red/Blue if you want to corrupt Lapras' name without getting a bad clone in Generation II. When the 9F glitch item is used many times with Lapras in the box, its name will corrupt.
You can then save and reset the game to withdraw it and its moves shouldn't be corrupted if you didn't use 9F too much. We can get the 9F glitch item with dry underflow glitch (https://www.youtube.com/watch?v=ZyppA...) with the Celadon looping map trick (http://glitchcity.info/wiki/Celadon_l...).
3) Two Generation II core games; one a that just got the ability to trade (this was a measure due to the glitch not working on a later save file) with Crystal and another (with access to the Time Capsule after meeting Bill in Ecruteak City and waiting a day) to raise Lapras to level 50.
4) Specific box names for storage box 1
1) Teach level 28 Lapras on Generation I Bide via TM34; move 2.
2) Deposit in the PC, corrupt nickname with 9F. Try about 15 9F uses each iteration.
3) Save and reset after nickname is corrupted, view a Pokémon summary that can withdraw unterminated name Pokémon and withdraw the Pokémon.
4) Trade to a Generation II game (Time Capsule must be enabled - meet Bill in Ecruteak and wait one day).
5) Raise it to level 29 (e.g. with Rare Candy) to learn Perish Song; move 1. Raise it to level 50 to learn Safeguard; move 3.
6) Trade to a new Generation II Crystal that just got to the Pokémon Center with Antidote x21 purchased
7) Do box name cheats and save every iteration. There are various examples below. Before doing a box name cheat (box name cheats can be set via a PC by altering PC names), save and reset the game and then perform the following; In order to perform the box names cheats, have Antidote x21 at the bottom of the inventory, try to toss all x21 (move toss counter down to show all x21) but Cancel with B, scroll down and exit by pressing A on Cancel (not with B), and then view the Lapras summary to execute arbitrary code.
Stored unterminated name Pokémon/bad clone method w/ stored PC items
(From Crystal_'s video)
1. Items in the PC item storage ended with a ret command, with register de set to a specific value (e.g. 0134)
2. A bad clone in the current PC box
3. Max Elixer or TM21 (Frustration) in the bag
4. Quagsire in party slot 1, with Return as move 1, with a move with less than 10 characters in it, in slot 4
5. Spearow holding TM50 (Nightmare) in party slot 2. TM49 may also work and depends on the number of items in the PC item storage.
1. Save and reset the game just outside of a regular Pokémon Center
2. Press up on the d-pad only, until the player character is one tile below the Pokémon Center desk
3. Move right only, until facing the wall/edge of map
4. Move up only until facing the PC. Do not use the PC yet.
5. Press Start and open the player's bag
6. Have the cursor point to Max Elixer or TM21, then exit the bag without pressing A on the item
7. Go to deposit a Pokémon and view your Quagsire's summary.
8. Exit and scroll down to Spearow, then exit Deposit
9. Choose withdraw and have the cursor on the bad clone/unterminated name Pokémon, which will force its name and the 0x1500 sequence that follows, and cause arbitrary code execution.
Self-contained setup and bootstrap
If the player has the ability to put arbitrary data in a string, then both the setup and the bootstrap, and even potentially the entire payload, can actually be done from within the string itself:
- Instead of setting up "0x15 0x00" after the string buffer, 0x15 followed by 0x00 in the string itself could be used to trigger this glitch.
- By putting carefully constructed byte sequences between 0x15 and 0x00, valid mobile functions can be triggered and modify the value at $CD52.
- Due to how mobile functions use the stack, if the game encounters a
retinstruction when executing code from $CD52, without other stack manipulation, the game will continue to run arbitrary code from the location following the 0x00 byte, which in this case would also be in the string itself.
This principle can be used after the player has already achieved ACE, to make subsequent execution of arbitrary code easier. Alternatively, they might be used to setup ACE by trading with another game, or with a game-altering device.
The following self-contained setups are designed by pfero:
4F 15 08 05 C9 00 [code] 37 C9
This works in any unverified string, notably including Pokémon nickname and mail messages. This means that it can be transferred from any Generation I game (with just enough space to jump to a more convenient location) or Generation II game (with more space to possibly write a "built-in" payload).
and 0xC5 ; E6 C5 dec b ; 05 ret ; C9
15 0A C0 00 [code] E1 C9 15 0B C0 00 [code] E1 C9
The first setup is specifically designed for mail messages, the second one might be useful elsewhere. The first one depends on the value of
hl (the location where the current character in the string is being printed to) translating to valid instructions to slide for two bytes; the second one depends on
hl+3 in the same way. The first setup might not work on Japanese versions, due to the behavior of mobile function 0x0A being different.
Luckytyphlosion offers the following explanation on the forums:
"Basically, it's the cause of poor error checking by GameFreak. When the game has to print the Fake Bad Clone's name through the PlaceString function, it encounters 0x00 characters which aren't supposed to be printed.
In Gold/Silver, encountering a 0x00 character would cause the game to stop processing the string (and also terminate a call from the text processing engine, although that's irrelevant in this case). However, in Crystal, for whatever reason GameFreak replaced this error checking so encountering a 0x00 character would print a ? instead. This can lead to PlaceString writing past the tilemap in WRAM and into other RAM (as seen in Crystal_'s Bad Clone/Kingdra video).
This new error checking has another consequence; being able to read invalid characters. Normally this would not be too destructive; the only thing you could do at best (worst?) is overflowing text into other portions of RAM, as seen above. However, due to another instance of bad error checking, the <DAY> control code (0x15) can jump to a fairly exploitable portion of RAM, 0xcd52.
The code for control code 0x15 jumps to a mobile function, Function17f036, which then calls Function17f036 leading to a jumptable, which reads the next byte from the source as the jumptable index. While there's error checking implemented, GameFreak missed one invalid index, 0x00. The maximum index check checks if the index is greater than the upper bound, but then decrements the a register after the error check. This can allow a 0x00 index to pass through the error check, but then underflow to 0xFF, thereby reading an invalid address from ROM, which conveniently points to WRAM, and a fairly manipulable portion. This is why you need the byte combination 0x15 0x00 to jump to 0xcd52.
From there, you can do whatever setup you want to achieve ACE. Conveniently, Gamefreak pushed the source address onto the stack before jumping to the specified address, so the return address will point to whatever was after the 0x15 0x00. In the Crystal Any% speedrun case, this is an immense help as the memory after is a temporary buffer for storing a Pokemon struct (which stores the Pokémon with the corrupted nickname), allowing us to use the moves and trainer ID as a bootstrap to reach box names.
It might be possible to find other locations for a bootstrap. The address where the game jumps is similar to the address where Coin Case jumps in Gold/Silver, so you could potentially manipulate the BG Map buffers to jump to a more suitable place. (The jump to the middle of party data would not work, as the address of party data had shifted in Crystal).
Interestingly, I found this ACE exploit a while ago when attempting to do regular cloning, but I dismissed it as the result of a crash. (When I was doing some testing regarding cloning, I encountered this glitch again and actually decided to look into it)."
- Much of the text in this article (specifically for the Lapras method) is courtesy of ChickasaurusGL's video description, with permission.
- Luckytyplosion offered an in-depth explanation on the forums.
- Pfero introduced the idea of a self-contained setup, and did some preliminary research on the effects of valid mobile functions.
- TimoVM reverse engineered some of Pfero's setups, giving explanations on the purpose of each byte.