view org/total-control.org @ 609:65b7c5b47de1

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