view org/total-control.org @ 620:1b52b14868d3 tip

merge.
author rlm <rlm@aurellem.org>
date Sun, 07 Feb 2016 23:16:04 -0800
parents 90575d3a64d1 a79e5a852347
children
line wrap: on
line source
1 #+title: Pokemon Yellow Total Control Hack
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description: Taking over Pokemon Yellow from the inside.
5 #+keywords: pokemon, pokemon yellow, rom, gameboy, assembly, hex, pointers, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
8 #+BABEL: :exports both :noweb yes :cache no :mkdirp yes
9 #+OPTIONS: num:2
12 Full Source : http://hg.bortreb.com/vba-clojure
15 #+BEGIN_HTML html
16 <div class="figure">
17 <p>
18 <iframe width="420" height="315"
19 src="https://www.youtube.com/embed/p5T81yHkHtI"
20 frameborder="0" allowfullscreen></iframe>
21 <p>
22 #+END_HTML
23 Youtube Video w/ Visual Keypresses: http://www.youtube.com/watch?v=p5T81yHkHtI
24 #+BEGIN_HTML
25 </div>
26 #+END_HTML
28 Special Thanks to:
30 - http://tasvideos.org/2913S.html for the save corruption hack which
31 is used at the start of this run.
32 - http://www.everyponysings.com/ for providing the midi file I used
33 to create the song at the end.
34 - http://www.zophar.net/ for the terminal font.
37 * Introduction
39 Think of pokemon yellow as creating a little universe with certain
40 rules. Inside that universe, you can buy items, defeat rival trainers,
41 and raise your pokemon. But within that universe, you are bound by the
42 rules of pokemon. You can't build new buildings, or change the music,
43 or change your clothes.. There are some games (like chess), where it
44 is not possible to alter the rules of the game from within the
45 game. No matter what moves you make in chess, you can never change the
46 rules of the game so that it becomes checkers or basketball. The point
47 of this run is to show that you CAN change the rules in pokemon
48 yellow. There is a certain sequence of valid actions (like walking
49 from one place to another or buying items) that will allow you to
50 transform pokemon yellow into Pacman, or Tetris, or Pong, or a MIDI
51 player, or anything else you can imagine.
53 * Background
55 [[http://tasvideos.org/2913S.html][This speedrun]] by Felipe Lopes de Freitas (p4wn3r), beats pokemon
56 yellow in only 1 minute and 36 seconds. It does it by corrupting the
57 in-game item list so that he can advance the list past its normal
58 limit of 20 items. The memory immediately after the item list includes
59 the warp points for the current map, and by treating that data as
60 items and switching and dropping them, he can make the door from his
61 house take him directly to the end of the game.
63 When I first saw that speedrun, I was amazed at how fast pokemon
64 yellow could be beaten, and that it was possible to manipulate the
65 game from the inside, using only the item list. I wondered how far I
66 could extend the techniques found in p4wn3r's run.
68 The gameboy is an 8 bit computer. That means that ultimately, anything
69 that happens in pokemon is a result of the gameboy's CPU reading a
70 stream of 8 bit numbers and doing whatever those numbers mean. For
71 example, in the gameboy, the numbers:
73 [62 16 37 224 47 240 37 230 15 55]
75 mean to check which buttons are currently pressed and copy that result
76 into the "A" register. With enough numbers, you can spell out an
77 interactive program that reads input from the buttons and allows you
78 to write any program you want to the gameboy. Once you have assembled
79 such a program and forced the game to run it, you have won, since you
80 can use that program to write any other program (like Tetris or
81 Pacman) over pokemon yellow's code. I call a program that allows you
82 to write any other program a "bootstrapping program". So, the goal is
83 to somehow get a bootstrapping program into pokemon yellow and then
84 force yellow to run that program instead of its own.
86 How can we spell out such a program? Everything in the game is
87 ultimately numbers, including all items, pokemon, levels, etc. In
88 particular, the item list looks like:
90 #+begin_example
91 item-one-id (0-255)
92 item-one-quantity (0-255)
93 item-two-id (0-255)
94 item-two-quantity (0-255)
95 .
96 .
97 .
98 #+end_example
100 Let's consider the button measuring program [37 62 16 37 224 37 240
101 37 230 15 55] from before. Interpreted as items and item quantities, it is
103 #+begin_example
104 lemonade x16
105 guard spec. x224
106 leaf stone x240
107 guard spec. x230
108 parlyz heal x55
109 #+end_example
111 So, if we can get the right items in the right quantities, we can
112 spell out a bootstrapping program. Likewise, when writing the
113 bootstrapping program, we must be careful to only use numbers that are
114 also valid items and quantities. This is hard because there aren't
115 many different items to work with, and many machine instructions
116 actually take 2 or even 3 numbers in a row, which severely restricts
117 the types of items you can use. I ended up needing about 92 numbers to
118 implement a bootstrap program. Half of those numbers were elaborate
119 ways of doing nothing and were just there so that the entire program
120 was also a valid item list.
122 The final part of the hack is getting pokemon yellow to execute the
123 new program after it has been assembled with items. Fortunately,
124 pokemon keeps a number called a function pointer within easy reach of
125 the corrupted item list. This function pointer is the starting point
126 (address) of a program which the game runs every so often to check for
127 poison and do general maintenance. By shifting an item over this
128 function pointer, I can rewrite that address to point to the
129 bootstrapping program, and make the game execute it. Without this
130 function pointer, it would not be possible to take over the game.
132 * The Run
134 I start off and name my rival Lp/k. These characters will eventually be
135 treated as items and shifted over the function pointer, causing it to
136 execute the bootstrapping program that will soon be constructed. I
137 start the run the same as p4wn3r's and restart the game while saving,
138 so that the pokemon list is corrupted. By switching the 8th and 10th
139 pokemon, I corrupt the item list and can now scroll down past the 20th
140 item. I shift items around to increase the text speed to maximum and
141 rewrite the warp point of my house to Celadon Dept. Store. (p4wn3r
142 used this to go directly to the hall of fame and win the game in his
143 run.) I deposit many 0x00 glitch items into the PC from my corrupted
144 inventory for later use. Then, I withdraw the potion from the
145 PC. This repairs my item list by overflowing the item counter from
146 0xFF back to 0x00, though the potion is obliterated in the process. I
147 then take 255 glitch items with ID 0x00 from the computer into my
148 personal items.
150 Leaving my house takes me directly to Celadon Dept. store, where I
151 sell two 0x00 items for 414925 each, giving myself essentially max
152 money. I hit every floor of the department store, gathering the
153 following items:
155 #+begin_example
156 +-------------------+----------+
157 |##| Item | Quantity |
158 +--+----------------+----------+
159 |1 | TM02 | 98 |
160 |2 | TM37 | 71 |
161 |3 | TM05 | 1 |
162 |4 | TM09 | 1 |
163 |5 | burn-heal | 12 |
164 |6 | ice-heal | 55 |
165 |7 | parlyz-heal | 99 |
166 |8 | parlyz-heal | 55 |
167 |9 | TM18 | 1 |
168 |10| fire-stone | 23 |
169 |11| water-stone | 29 |
170 |12| x-accuracy | 58 |
171 |13| guard-spec | 99 |
172 |14| guard-spec | 24 |
173 |15| lemonade | 16 |
174 |16| TM13 | 1 |
175 +--+----------------+----------+
176 #+end_example
178 After gathering these items, I deposit them in the appropriate order
179 into the item PC to spell out my bootstrapping program. Writing a full
180 bootstrap program in one go using only items turned out to be too
181 hard, so I split the process up into three parts. The program that I
182 actually construct using items is very limited. It reads only from the
183 A, B, start, and select buttons, and writes 4 bits each frame starting
184 at a fixed point in memory. After it writes 200 or so bytes, it jumps
185 directly to what it just wrote. In my run, I use this program to write
186 another bootstrapping program that can write any number of bytes to
187 any location in memory, and then jump to any location in memory. This
188 new program also can write 8 bits per frame by using all the
189 buttons. Using this new bootstrap program, I write a final
190 bootstrapping program that does everything the previous bootstrapping
191 program does except it also displays the bytes it is writing to memory
192 on the screen.
194 After completing this bootstrapping program, I go to the Celadon
195 mansion, because I find the metaness of that building to be
196 sufficiently high to serve as an exit point for the pokemon
197 universe. I corrupt my item list again by switching corrupted pokemon,
198 scroll down to my rival's name and discard until it is equal to the
199 address of my bootstrapping program, and then swap it with the
200 function pointer. Once the menu is closed, the bootstrapping program
201 takes over, and I write the payload....
203 * Infrastructure
205 The entire video was completely produced by bots --- I didn't manually
206 play the game at all to produce this speedrun. Here is a brief account
207 of the infrastructure I built to make the video. The entire source of
208 the project is available at http://hg.bortreb.com/vba-clojure
210 The first step was to build a programmatic interface to pokemon
211 yellow. So, I downloaded vba-rerecording from
212 http://code.google.com/p/vba-rerecording/. After repairing their
213 broken auto-tools scripts so that it would compile on GNU/Linux, I
214 added a low level C interface that I could call from Java via
215 JNI. This C interface gives me basic control over the emulator: I can
216 step the emulator either one clock cycle or one frame, and I can get
217 the contents of any memory location or register. The interface also
218 allows me to freeze the state of the emulator, save it to a Java
219 object, and reload that state again at any time.
221 I built a layer of [[http://clojure.org/][clojure]] code on top of the JNI bindings to get an
222 entirely functional interface to vba-rerecording. This interface
223 treats state of the emulator as an immutable object, and allows me to
224 do everything I could do with the lower level C interface in a
225 functional manner. Using this functional code, I wrote search programs
226 that take a particular game-state and try out different combinations
227 of button presses to get any desired effect. By combining different
228 styles of search with different initial conditions, I created high
229 level functions that could each accomplish a certain general task,
230 like walking and buying items. For example, here is some actual code:
232 #+begin_src clojure
233 (defn-memo viridian-store->oaks-lab
234 ([] (viridian-store->oaks-lab
235 (get-oaks-parcel)))
236 ([script]
237 (->> script
238 (walk [↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
239 ← ← ← ← ← ← ← ← ←
240 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
241 ← ←
242 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
243 ↓ ↓ ↓ ↓ ↓ ↓ ↓
244 → → → → → → → →
245 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
246 ← ← ← ← ←
247 ↓ ↓ ↓ ↓
248 ])
249 (walk-thru-grass
250 [↓ ↓ ↓ ↓ ↓ ↓ ↓])
251 (walk [↓ ↓ ← ↓ ↓ ↓ ←
252 ↓ ↓ ↓ ↓ ↓ ↓
253 → → → ↑])
255 (do-nothing 1))))
256 #+end_src
258 This script walks from the Viridian City pokemon store to Oak's
259 Lab in the most efficient way possible. The walk-thru-grass function
260 guarantees that no wild battles will happen by manipulating the game's
261 random number generator.
263 #+begin_src clojure
264 (defn-memo hacking-10
265 ([] (hacking-10 (hacking-9)))
266 ([script]
267 (->> script
268 begin-deposit
269 (deposit-held-item 17 230)
270 (deposit-held-item-named :parlyz-heal 55)
271 (deposit-held-item 14 178)
272 (deposit-held-item-named :water-stone 29)
273 (deposit-held-item 14 32)
274 (deposit-held-item-named :TM18 1)
275 (deposit-held-item 13 1)
276 (deposit-held-item 13 191)
277 (deposit-held-item-named :TM02 98)
278 (deposit-held-item-named :TM09 1)
279 close-menu)))
280 #+end_src
282 This script calculates the fastest sequence of key presses to deposit
283 the requested items into a PC, assuming that the character starts out
284 in front of a computer.
286 I also wrote functions that could grovel through the game's memory and
287 present the internal data structures in usable ways. For example, the
288 function =print-inventory= returns the current inventory in a human
289 readable format.
291 #+begin_src clojure :results output :exports both
292 (com.aurellem.gb.items/print-inventory)
293 #+end_src
295 #+results:
296 #+begin_example
297 +-------------------+----------+
298 |##| Item | Quantity |
299 +--+----------------+----------+
300 |0 | poke-ball | 14 |
301 |1 | TM28 | 1 |
302 |2 | TM11 | 1 |
303 |3 | TM45 | 1 |
304 |4 | nugget | 1 |
305 |5 | s.s.ticket | 1 |
306 |6 | helix-fossil | 1 |
307 |7 | moon-stone | 1 |
308 +--+----------------+----------+
310 #+end_example
313 Armed with these functions, I constructed a bootstrapping program that
314 could be expressed as items. This is particularly hard, since many
315 useful opcodes do not correspond any item, and the item quantities
316 must all be less than 99.
318 Here is the first bootstrapping program in all its glory.
320 #+begin_src clojure
321 (defn pc-item-writer-program
322 []
323 (let [;;limit 75
324 limit 201 ;; (item-hack 201 is the smallest I could make this.)
325 [target-high target-low] (disect-bytes-2 pokemon-list-start)]
326 (flatten
327 [[0x00 ;; (item-hack) no-op (can't buy repel (1E) at celadon)
328 0x1E ;; load limit into E
329 limit
330 0x3F ;; (item-hack) set carry flag no-op
332 ;; load 2 into C.
333 0x0E ;; C == 1 means input-first nybble
334 0x04 ;; C == 0 means input-second nybble
336 0x21 ;; load target into HL
337 target-low
338 target-high
339 0x37 ;; (item-hack) set carry flag no-op
341 0x00 ;; (item-hack) no-op
342 0x37 ;; (item-hack) set carry flag no-op
344 0x00 ;; (item-hack) no-op
345 0xF3 ;; disable interrupts
346 ;; Input Section
348 0x3E ;; load 0x20 into A, to measure buttons
349 0x10
351 0x00 ;; (item-hack) no-op
352 0xE0 ;; load A into [FF00]
353 0x00
355 0xF0 ;; load 0xFF00 into A to get
356 0x00 ;; button presses
358 0xE6
359 0x0F ;; select bottom four bits of A
360 0x37 ;; (item-hack) set carry flag no-op
362 0x00 ;; (item-hack) no-op
363 0xB8 ;; see if input is different (CP A B)
365 0x00 ;; (item-hack) (INC SP)
366 0x28 ;; repeat above steps if input is not different
367 ;; (jump relative backwards if B != A)
368 0xED ;; (literal -19) (item-hack) -19 == egg bomb (TM37)
370 0x47 ;; load A into B
372 0x0D ;; dec C
373 0x37 ;; (item-hack) set-carry flag
374 ;; branch based on C:
375 0x20 ;; JR NZ
376 23 ;; skip "input second nybble" and "jump to target" below
378 ;; input second nybble
380 0x0C ;; inc C
381 0x0C ;; inc C
383 0x00 ;; (item-hack) no-op
384 0xE6 ;; select bottom bits
385 0x0F
386 0x37 ;; (item-hack) set-carry flag no-op
388 0x00 ;; (item-hack) no-op
389 0xB2 ;; (OR A D) -> A
391 0x22 ;; (do (A -> (HL)) (INC HL))
393 0x1D ;; (DEC E)
395 0x00 ;; (item-hack)
396 0x20 ;; jump back to input section if not done
397 0xDA ;; literal -36 == TM 18 (counter)
398 0x01 ;; (item-hack) set BC to literal (no-op)
400 ;; jump to target
401 0x00 ;; (item-hack) these two bytes can be anything.
402 0x01
404 0x00 ;; (item-hack) no-op
405 0xBF ;; (CP A A) ensures Z
407 0xCA ;; (item-hack) jump if Z
408 target-low
409 target-high
410 0x01 ;; (item-hack) will never be reached.
412 ;; input first nybble
413 0x00
414 0xCB
415 0x37 ;; swap nybbles on A
417 0x57 ;; A -> D
419 0x37 ;; (item-hack) set carry flag no-op
420 0x18 ;; relative jump backwards
421 0xCD ;; literal -51 == TM05; go back to input section
422 0x01 ;; (item-hack) will never reach this instruction
424 ]
425 (repeat 8 [0x00 0x01]);; these can be anything
427 [;; jump to actual program
428 0x00
429 0x37 ;; (item-hack) set carry flag no-op
431 0x2E ;; 0x3A -> L
432 0x3A
435 0x00 ;; (item-hack) no-op
436 0x26 ;; 0xD5 -> L
437 0xD5
438 0x01 ;; (item-hack) set-carry BC
440 0x00 ;; (item-hack) these can be anything
441 0x01
443 0x00
444 0xE9 ;; jump to (HL)
445 ]])))
447 #+end_src
449 I use the glitch items 0x00 and 0xFF to great effect in my run. 0x00
450 sells for almost half of maximum money --- I use just 3 of them to
451 finance the purchase of all the other items I need. 0x00 is also a
452 NO-OP in the gameboy's machine language, which means that I can stick
453 them anywhere where I need to break up an otherwise illegal pair of
454 opcodes. 0xFF is also extremely useful because it is the end-of-list
455 sentinel. Normally, the game will "compact" your items whenever you
456 make a purchase or deposit. For example, if you deposit a pokeball,
457 then deposit another pokeball, the item list looks like:
459 #+begin_example
460 pokeball x2
461 #+end_example
463 instead of:
465 #+begin_example
466 pokeball x1
467 pokeball x1
468 #+end_example
470 However, the compaction stops after the first 0xFF item, so if there
471 is an 0xFF item at the beginning of the list, it will "shield" all the
472 items below it from compaction. It the beginning of the run, I stick
473 an 0xFF item at the top of the PC item list, allowing me to put items
474 in with impunity. At the end, I toss the 0xFF away to reveal the
475 completed bootstrap program.
477 The final payload program is multiple programs. I created a reduced
478 form of MIDI and implemented it in gameboy machine language. Then I
479 translated a midi file from http://www.everyponysings.com/ into this
480 reduced MIDI language. The payload program contains both the music
481 data and the MIDI interpreter to play that data. The picture works in
482 a similar way. There is code to translate a png file into a form that
483 can be displayed on a gameboy, and other code to actually display that
484 image. Both the image and the display code are also written by the
485 final bootstrapping program. Even though my final payload is rather
486 simple, you can write any program at all as the payload. The source
487 for the sound and image displaying code is at
488 http://hg.bortreb.com/vba-clojure.