GeistHaus
log in · sign up

https://vaguilar.com/atom.xml

atom
5 posts
Polling state
Status active
Last polled May 19, 2026 00:46 UTC
Next poll May 20, 2026 01:53 UTC
Poll interval 86400s
ETag W/"69c1f3e1-107f6"
Last-Modified Tue, 24 Mar 2026 02:16:01 GMT

Posts

How I Obtained Mew in Pokémon Red on a Real Game Boy
Show full content

I built a USB device that emulates a Game Boy over the link cable and used it to inject a fully valid Mew into Pokémon Red. All code available on GitHub.

If you grew up with Pokémon Red/Blue/Yellow, you probably remember Mew. Not the one you caught (because you didn’t), but the one you heard about. The one your friend’s cousin totally had. The one that was supposedly hiding under a truck if you used Strength at just the right moment. For most players, Mew was unobtainable unless you attended a distribution event or used a GameShark (which kinda feels like cheating). More recently, methods exist to manipulate the game’s memory using in-game glitches to cause Mew to appear (with some limitations)! Having previously poked around the trade logic of these Pokémon games, I wanted to see if I could trick a real Game Boy into trading me a Mew that had never actually existed.

What Pokémon Trading Actually Looks Like

Pokémon Red/Blue/Yellow’s trade system is quite simple and has been well documented by others. When two Game Boys connect to trade Pokémon over a link cable, the first system to initiate the interaction becomes the primary Game Boy, while the other acts as the secondary. Both sides start off by repeatedly transmit menu state information until the Trade option is selected, at which point both players begin exchanging party information. Each Game Boy sends its data to the other in three consecutive data blocks: a 10-byte random seed (used to synchronize random events and animations), a 418-byte party data structure that lists information on each Pokémon, and a patch list used to work around limitations of the Game Boy’s serial protocol. Certain byte values (like 0xFE) have special meanings on the link cable and cannot be transmitted directly. When those values appear inside the party data, they are omitted during transmission and later reinserted using a list of offsets. Each data block is preceded by an arbitrary number of 0xFD preamble bytes to mark boundaries. A few more menu state transmissions follow until a pair of Pokémon are successfully traded.

Party Data Layout

The Pokémon party data itself is sent as a fixed-layout block of memory (credit to Bulbapedia) and looks like this:

Name Length (bytes) Comment Player Name 11 Terminated with 0x50 Size of Pokémon Party 1 Maximum of 6 Pokémon Species IDs 7 List terminated with 0xFF, padded with 0x00 if less than 6 Pokémon Pokémon #1 44 First Pokémon’s data including Species ID, Pokémon Type, HP, etc. … 44 … Pokémon #6 44 Last Pokémon’s data Nicknames 66 11 bytes each, terminated with 0x50 Original Trainer Names 66 11 bytes each, terminated with 0x50 ??? 3 Unknown

Crucially, the trade system does not attempt to validate where this data comes from. It only cares that it arrives in the correct format and passes basic consistency checks. If the received bytes are structurally valid, the game accepts them without question. Editing these values makes it possible to “trade” a Mew.

The Missing Link

PC connected to Game Boy with cable

Pokémon trades were designed to happen over the Game Boy Link Cable — a simple, peer-to-peer serial interface intended to connect two handhelds sitting next to each other. In my previous post, I had used an Arduino to mimic this serial communication and hardcoded the trade responses directly on the microcontroller. I wanted a bit more flexibility and wondered if I could send data from my computer instead, to make this more extensible and easier to iterate with. To do that, I needed a device that physically connects to the Link Port, understands the serial timing, and exposes the exchange to a modern computer in a controllable way. So I designed one:

GBLink PCB

The result is a small PCB that bridges the Game Boy Link Port to a standard UART interface, which can then be connected to a PC over USB. A low-power ATtiny412 microcontroller handles real-time link protocol timing. The Game Boy sees a perfectly valid link partner, while the computer sees a simple serial device. From the Game Boy’s perspective, it’s just trading with another handheld. From the PC’s perspective, it’s just talking bytes over a serial port. I called it GBLink.

Trading a Mew That Never Existed

Armed with a freshly built GBLink, I wrote a program on the host (PC) side that simply echoes back whatever it receives from the real Game Boy. This allows me to get surprisingly far into the trading process. It’s enough to capture a full dump of the data exchanged between the two Game Boys, which gave me something concrete to examine:

...
 60 60 00 00 fd fd fd fd  fd fd fd fd e6 6b f2 7b  # random seed
 05 91 1f af 41 d5 fd fd  fd fd fd fd fd fd fd 81  # party starts
 8b 94 84 50 86 80 91 98  50 89 01 b1 ff 00 00 00 
 00 00 b1 00 18 00 00 15  15 2d 21 27 00 00 d6 d3  # pokemon 1
 00 01 1f 00 c3 00 f0 00  cc 01 1d 00 c3 18 b9 23
 1e 00 00 07 00 18 00 0c  00 0f 00 0c 00 0d 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 81 8b 94 84 50 86  # OT
 80 91 98 50 89 00 00 00  00 00 00 00 00 00 00 00 
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00  00 00 00 00 92 90 94 88  # nicknames
 91 93 8b 84 50 50 50 00  00 00 00 00 00 00 00 00
...

Full trade dump available here.

At first glance, it might seem like obtaining Mew is as simple as swapping the Pokémon species ID of a replayed trade exchange, and that’s only somewhat true. But we also need to update a few other fields such as the Pokémon’s type and its list of moves to line up with what a “real” Mew would have. Also, to make the Mew compatible with other games like Poké Transporter, we must modify the Original Trainer name and Trainer ID to specific expected values, otherwise this Mew would not be tradable. This is a limitation of other methods of obtaining this mythical Pokémon. I also wanted the trade implementation to be robust and extensible so others could experiment with it.

State machine diagram of happy path of Pokémon Trade

After mapping the data exchanged, as well as deciphering most of the menu options that are used to transition before and after trading, I was able to start putting together a state machine for Pokémon trades. I wrote a Python program on the host side that opens a UART connection for the GBLink, waits for the other Pokémon game’s link handshake, and enters a state machine to handle the data exchange. The cartridge responds to the output and progresses its own trading state machine until we finally inject a custom party data block containing a handcrafted Mew from the host into the Game Boy:

Pokemon trade in progress on Gameboy

Then it’s time to run the trade for real. I offer a level 3 Rattata in exchange for the GBLink’s mythical Pokémon. The animations play. The trade completes. Nothing crashes. And suddenly, there’s a Mew in my party. Just a normal trade — with a partner that doesn’t exist.

Mew trade completed!

Closing Thoughts

Back when these games were first released, Mew felt mythical. Today, with a little hardware and a lot of curiosity, it turns out Mew was never hiding under a truck, but in plain sight, waiting for the right bytes to be sent over a link cable.

I made a small batch of these GBLink devices that you can buy on my Tindie page!

https://vaguilar.com/2026/02/18/how-i-obtained-mew-in-pokemon-red-on-a-real-game-boy
Programming tinyAVR 1-Series Microcontrollers on macOS
Show full content

A microcontroller

I have found myself having to set up this development environment several times and I keep forgetting how to do it easily. Sharing these steps on how to set up the tooling for these new ICs and the other new series of chips.

First, install brew from brew.sh if you don’t have it already, and then install avr-gcc:

brew tap osx-cross/avr
brew install avr-gcc

This installs a recent version of the compiler tools, but lacks libraries and headers for the latest series of microcontrollers. For this, you should clone the official Microchip avr-libc repository:

git clone https://github.com/avrdudes/avr-libc

Now, when you want to compile for a specific IC, you can point your avr-gcc to use the relevant files from the repo you just cloned (replace /path/to/avr-libc with the actual path you cloned to):

avr-gcc \
    -mmcu=attiny412 \
    -I/path/to/avr-libc/include \
    -B/path/to/avr-libc/avr/devices/attiny412 \
    -Wall -Os \
    main.c

And finally you can use avr-objcopy -O ihex a.out main.hex to generate a proper hex file that is ready for flashing.

https://vaguilar.com/2025/02/27/tinyavr-1-series
Writing arm64 Assembly for iOS
Show full content

An AI generated image of the Apple logo

Even as mobile devices continue to become more powerful, iOS developers can still benefit from strategies to optimize their apps for performance. One way to do this is by utilizing low-level assembly code, specifically the ARM64 architecture found in more recent iOS devices. This post will cover how to setup up your Xcode project for this and go over some basics of arm64 assembly for improving performance of Swift apps.

Why?

Generally, you don’t want to do this. But sometimes you need to optimize a particular routine in your app by processing data more efficiently and using the GPU is overkill or not the right tool. In particular, taking advantage of the NEON instruction set allows parallel processing on data which can make your software more efficient.

Setup

You’ll need to create a few files in your Xcode project:

  • Bridging-Header.h - the Xcode Bridging Header to connect assembly functions to Swift code

  • Assembly.s - where we’ll store our assembly routines

Along with these, you’ll need to configure some settings in Xcode to make this work:

  • Designate your bridging header file for your target

  • If your app also builds for other architectures like x86_64, you should exclude the Assembly.s for Intel architectures. If not, you’ll hit errors when building all architectures.

A Contrived Example

Let’s say we needed to round millions of floating point numbers. We can write a function to do this that takes two parameters: a pointer to an array of float values and the length of the array.

Assembly

In Assembly.s, we can write a function using NEON instructions to simultaneously round several floating point values. We’ll load 8 floats (8 32-bit values) into v0 and v1 vector registers, use the frintx instruction which rounds 4 floats at the same time, and then store them back to the array buffer. I won’t go into too much detail on how this is set up and what it’s doing, but you can read more about in the attached resources at the end of the post:

.global   _fastArrayRound
.p2align 2

// register x0 is a pointer to the array, x1 is the length
_fastArrayRound:
    ld1 {v0.16b, v1.16b}, [x0]  // load floats into v0 and v1
    frintx v0.4s, v0.4s // round floats in v0
    frintx v1.4s, v1.4s // round floats in v1
    st1 {v0.16b, v1.16b}, [x0], #32 // store them back, x0 += 32
    subs x1, x1, #8
    bgt _fastArrayRound // jump back to beginning if we're not done
    ret
Bridging Header

This should have C function header for your arm64 routine:

void fastArrayRound(float *arr, int size);

And now it should now be available to use in Swift by calling it like this:

fastArrayRound(...)

If you are also compiling for x86_64, you can provide a fallback for this architecture when you want to call our architecture specific code:

#if arch(arm64)
fastArrayRound(...)
#else
// x86_64/other arch fallback
#endif
Performance Metrics

How much faster is this? A naive implementation might look something like this:

func arrayRound(_ arr: inout [Float32]) {
    for i in 0..<arr.count {
        arr[i].round(.towardZero)
    }
}

Benchmarking it on an array of 224 random floats with a simple program:

var arr: [Float32] = (0..<16777216).map{ _ in Float32.random(in: 0...10) }

arrayRound(&arr)
vaguilar@Victors-MacBook-Air src % time ./array_round

real	0m22.938s
user	0m22.537s
sys	0m0.070s

And then using arm64 NEON fastArrayRound function in the previous section:

vaguilar@Victors-MacBook-Air src % time ./fast_array_round

real	0m16.229s
user	0m15.995s
sys	0m0.035s

This results in a ~30% speed up in the program. You can probably optimize this further with other techniques but we can save that for another post.

More Resources
https://vaguilar.com/2023/03/24/writing-assembly-for-ios
DIY Arduino Board Compatible with 5v and 3.3v
Show full content

A long time ago I created a breakout board for an ATmega328p to prototype some projects, but time has not been too kind with it. It was hastily made on a single sided homemade PCB, has lots of jumper wires and some of the pins no longer work, probably because my soldering job wasn’t too great. After getting tired of these issues and having to put up with different voltages for different components, I decided to create a better board that can work with both 3.3v and 5v.

Design

The ATmega328p chip is only rated up to 8MHz for 3.3v, so makes sense to run it at 5v and convert the output down to 3.3v to run it at 16MHz. The idea then is to find a chip that you can easily connect outpins to and then have the signals converted to 3.3v.

I’m not too fond of SMT parts since they require patience and time to put together, of which I have neither at the moment. So I looked around and found this 74LVC245 IC that is fast enough to convert voltages to use UART and SPI. 5v signals go in one end and 3.3v come out the other side. Perfect. Conversion from 3.3v to 5v isn’t necessary since the ATmega will read them just fine. Probably. And off to Eagle CAD we go.

I use a USBasp Programmer that I bought off eBay to program my AVR chips (JP1). If you want to do that as well, be sure to buy one thats programmed already, if not you’ll end up with a chicken and egg problem where you need a programmer to program the firmware to your programmer (learned the hard way). The USBasp provides 5v from the USB port and then a LD1117v33 (U$1) is used to provide the 3.3v we need for the 74LVC245 chip. Note that the pins are wired incorrectly for the LD1117V33 in the schematic because I used the footprint for another similiar chip that I was too lazy to edit. When designing the schematic, the typical applications section from the data sheets of each chip are quite helpful. They sometimes have an example of exactly what you are trying to do

And then came the somewhat tedious and boring part; lots of trial and error for placing the components and routing the board efficiently. I tried my best to keep the size of the PCB small to decrease cost, but it ended up being only slightly smaller than an Arduino due to not using SMT components. I also added labels for both Arduino pin numbers and the traditional ATmega pin names, as sometimes I need both. Parts and boards were ordered off Digi-key and OSH Park respectively.

Result

Took a whole afternoon to solder everything together but it turned out great. The onboard 5v to 3.3v conversion works fantastic, beats having to constantly switch the power supply to the ATmega. It is a perfect replacement for the old board. Now I just need projects ideas to use it…

https://vaguilar.com/2016/05/02/diy-arduino-board
Arbitrary Code Execution in Pokemon Red
Show full content

The Gameboy Color is a nifty piece of hardware. After reading about several projects related to the original Pokemon games, I decided to give it a go myself. I dusted off my old Gameboy Color and ordered a copy of Pokemon Red off eBay and set off to do something.

While I waited, I began to sift through the awesome Pokemon R/B/Y disassembly project, and found the section dedicated to the Cable Club. The Cable Club is the room inside Pokemon Centers where you can trade Pokemon with another person using a link cable. This part intruiged me since data is sent over the link cable and curiosity lead me to search for some way to manipulate the data other than spoofing a trade . Using the BGB emulator and its documentation on its link cable protocol, I slapped together a Python script to interact with the Pokemon ROM.

The Exchange

The initial communication between Gameboys is outlined here pretty well. It’s not very interesting or relevant to the exploit, but basically the first Gameboy to talk to the Cable Club lady is the master (the emulator or the actual Gameboy later, referred to as Player 1 from here on out) while the other is the slave (Player 2, the script/Arduino). The menu options are then transmitted back and forth repeatedly as players choose what to do. Once the trade option is selected you are taken to a room to begin sending the other player your Pokemon data. It is sent in three parts:

Random seed value: 10 bytes
Pokemon party structure: 415 bytes
Patch list: 196 bytes

The random seed value is used so random events have the same outcome on both Gameboys. The pokemon party data section includes the other player’s name, party (species of Pokemon, nicknames, HP, attacks etc.), as well as the original trainer’s names. And finally, since the byte 0xFE has a special meaning when received as serial data (it is the designated “no data” byte, along with 0xFD being the preamble byte), the patch list is simply the offset of bytes in the party that should have the byte 0xFE. When these are transmitted, the sections of data are preceded by an arbitray number of 0xFD bytes.

The party structure is organized like so: (credit to Bulbapedia)

Name Length (bytes) Comment Player Name 11 Terminated with 0x50 Size of Pokemon Party 1 Normally max size of 6 Pokemon Species IDs 7 List terminated with 0xFF, padded with 0x00 if less than 6 Pokemon Pokemon #1 44 First Pokemon’s data … 44 … Pokemon #6 44 Last Pokemon’s data Nicknames 66 11 bytes each, terminated with 0x50 Original Trainer Names 66 11 bytes each, terminated with 0x50 ??? 3 Unknown

When this party data is sent over the link cable, the Player 2’s name is stored separately in memory at address 0xD887 and the rest of the data at 0xD89C:

0xD887 | 80 - First character of the Player 2's name
...
0xD89C | 06 - Number of Pokemon in Player 2's party
0xD98D | 01 - Species ID of 1st Pokemon
0xD98E | 02 - Species ID of 2nd Pokemon
0xD98F | 03 - Species ID of 3rd Pokemon
0xD990 | 04 - Species ID of 4th Pokemon
0xD991 | 05 - Species ID of 5th Pokemon
0xD992 | 06 - Species ID of 6th Pokemon
0xD993 | FF - List terminator
0xD994 | 01 - Start of 1st Pokemon data
...
The Buffer Overflow

When you finally enter the trading room, each of the player’s original Pokemon names are printed to the screen (not their nicknames for some reason). The way older video game consoles displayed some graphics is by using tiles. The video buffer is simply an array of tile IDs that are to be displayed on screen. This applies to the text on screen as well. Each letter is its own tile, and as a result the function to write strings to the screen simply writes bytes to the corresponding area of video buffer starting at 0xC4A0 (1 byte per tile, 20x16 in total):

...
	hlCoord 2, 1	; $C4A0
	ld de, wPartySpecies ; $D89D
	call TradeCenter_PrintPartyListNames
...

TradeCenter_PrintPartyListNames:
	ld c, $0
.loop
	ld a, [de]
	cp $ff
	ret z
	ld [wd11e], a
	push bc
	push hl
	push de
	push hl
	ld a, c
	ld [$ff95], a
	call GetMonName
	pop hl
	call PlaceString
	pop de
	inc de
	pop hl
	ld bc, 20
	add hl, bc
	pop bc
	inc c
	jr .loop

Or in C, roughly:

// TradeCenter_PrintPartyListNames(0xD89D, 0xC4A0);

void TradeCenter_PrintPartyListNames(char* start_ids, char* dest) {
	char* current_id = start_ids;
	while (*current_id != 0xFF) {
		char* name_str = GetMonName(*current_id); // Returns pointer to a string
		PlaceString(name_str, dest); // Essentially strcpy, but 0x50 terminated
		dest += 20; // Move to next line in buffer
	}
}

The TradeCenter_PrintPartyListNames function is passed the address of Player 2’s first Pokemon ID and begins to write all of the names to the video buffer. But the way the function is written, a Pokemon’s name can be written outside the intended area of memory if the byte 0xFF is not encountered within 7 bytes. Past that, we can write outside of the video buffer all together and even further down memory to where the stack is located (0xD000-0xDFFF). What good is writing Pokemon names to the stack though?

GetMonName:: ; 2f9e (0:2f9e)
	push hl
	ld a,[H_LOADEDROMBANK]
	push af
	ld a,BANK(MonsterNames) ; 07
	ld [H_LOADEDROMBANK],a
	ld [$2000],a
	ld a,[wd11e]
	dec a
	ld hl,MonsterNames ; 421E
	ld c,10
	ld b,0
	call AddNTimes
	ld de,wcd6d
	push de
	ld bc,10
	call CopyData
	ld hl,wcd77
	ld [hl], "@"
	pop de
	pop af
	ld [H_LOADEDROMBANK],a
	ld [$2000],a
	pop hl
	ret

C pseudo-code:

char* GetMonName(char id) {

	char* buffer, current, i;

	// Switch to the bank that stores the Pokemon names
	// along with other data...
	switchBank(7);

	// Names start at 421E and contain 10 bytes each
	current = 0x421E + (id * 10);
	buffer  = 0xCD77; // buffer

	// CopyData, essentially memcpy
	for (i = 0; i < 10; i++) {
		buffer[i] = current[i];
	}

	buffer[i] = 0x50; // Make sure string is terminated

	return buffer;
}

The GetMonName function looks up the Pokemon’s name in ROM bank 7 (one of the extra sections of memory of the Gameboy) and copies it into a buffer. There are only 151 pokemon in the game and it makes sense that there should only be that many names too. Space is quite limited in Gameboy games so there is some unrelated code/data directly after the table of names:

This data can be copied to the buffer just like a Pokemon name if we pass a value greater than 151 for a species ID. We can now wreck havoc on the stack and write whatever 10 byte sequence we find in the table to certain parts of the stack. We’ll now try to overwrite something interesting.

Setting a breakpoint inside the PlaceString function, we see that the return address stored in the stack is at address 0xDFDD. When the PlaceString function finishes and executes its RET instruction, it will jump to this memory address and continue executing from there. Could we possibly write to this address and have the Gameboy execute other code elsewhere?

I choose you, @(*#&!
// TradeCenter_PrintPartyListNames(0xD89D, 0xC4A0);

void TradeCenter_PrintPartyListNames(char* start_ids, char* dest) {
	char* current_id = start_ids;
	while (*current_id != 0xFF) {
		char* name_str = GetMonName(*current_id); // Returns pointer to a string
		PlaceString(name_str, dest); // Essentially strcpy, but 0x50 terminated
		dest += 20; // Move to next line in buffer
	}
}

Taking a look at this code again, we can write up to 10 bytes every 20 bytes starting at 0xC4A0. Doing some math (20n + 0xC4A0), we see that we can indeed start writing at address 0xDFD6 which is 7 bytes before the return address (n = 346 which is less than the total party size of 415). Perfect! Now, what are the chances that an address to some place useful is located in the unrelated data past the Pokemon names, in little endian format no less?

...
0xcc   4A 23 23 78 22 79 22 C9 17 AD
0xcd   5D 22 50 CD 3C 3C 21 26 D1 CB
0xce   EE 21 96 D7 CB 86 21 **A3 D7** CB
0xcf   8E 21 34 4A FA 39 D6 C3 97 3D
0xd0   38 4A 73 4A 06 2B CD 93 34 C0
...

(left column is the species ID and the corresponding "name")

The address 0xD7A3 is at the right location to be injected into the return value. Player 2’s name just so happens to be located at 0xD887, about 230 bytes after the potential return value. By sheer luck, the portion of memory between just happens to be filled with mostly 0’s (the nop opcode!) and makes a nice nop sled for us! What are the odds?

There is still one issue. To get this far down the stack we spray Pokemon names all over the place (since we have to print 346 of them to get this far) and potentially over important parts of the game. Let’s do something about that.

...
0xe1   49 3C C3 D7 24 17 BF 55 23 50
0xe2   17 43 56 23 0B 50 17 52 56 23
0xe3   **50** 17 7C 56 23 50 17 9F 56 23
0xe4   **50** 17 20 57 23 50 05 06 05 C0
0xe5   41 82 50 0E 4B 00 0A 54 FA 4B
0xe6   D7 CB 77 C4 76 50 3E 01 EA 0C
...

(left column is the species ID and the corresponding "name")

There are two “names” that begin with 0x50, the string terminating byte. Calling PlaceName on these means that nothing will be written to memory for that species ID. At this point we have enough to write a bootstrapping program to execute arbitary code.

The Payload

By sending Player 2’s name as assembled Z80 code, we can jump to any part of memory (and fix the stack if we’d like to return to the game). And as a consequence of our crafted party that lacks any 0xFE bytes, the patch list will be mostly empty, save for two 0xFF terminating bytes at the beginning. We can then stash our shell code here. We include a jump instruction to the patch list in Player 2’s name, C3 D6 C5 (JP $C5D6) and our party looks like this:

# Fix stack to previous state, jump to 0xc5d6, the patch list
name         | f8 00 36 fd 01 3e 58 c5 c3 d6 c5
party size   | 06                   # not actualy used, can be any value
species IDs  | 15 15 15 15 15 15    # arbitrary species IDs, in this case Mew's
pokemon data | e3 (346x) ... ce ff 00 00 00 ...
# crafted party structure, terminated with 0xff byte and followed by 0's

For the shellcode, there are a couple of assemblers for the Gameboy’s Z80 like processor , but I found that only WLA DX allows you to easily assemble code for the WRAM section of memory (0xC000-0xCFFF). I have put together a simple animated hello world proof of concept with a simple build file to put it all together. There are only 194 bytes available in the patch list for our shell code but its enough to do some interesting things. One thing to remember is that we can’t send any 0xFE bytes in the patch list or party, so any instructions using that byte can’t be sent (the compare immediate value instruction is one of them).

Now for Real

So far we’ve been using an emulator for this hack, but wouldn’t it be much more satisfying to see this happen on actual hardware?

The Gameboy uses a primitive serial protocol for the link cable that runs at 5V. The four main connections are serial in, serial out, clock and ground. The master Gameboy initiates the serial transfer and a byte is simultaneously pushed out as one is read in. This can be implemented easily with a microcontroller and has been done so already for the Arduino. Building off that project, it was easily modified to send the patch list as well. All that was required was cut up a Link Cable that I got off eBay for $2, no resistors or anything much else. I recommend you break the plastic off one of the connectors and then pry the metal to expose the easily connectable prongs.

Conclusion

I didn’t have as much time as I’d like to explore possibilites of taking this further, but having done nothing like this before this project was quite an adventure. It can be extended to send over even larger programs as a payload, as there are portions of memory that can be overwritten (without side effects, like Player 2’s party data) by sending a bootstrap program that requests more data over serial. It can be used as a “GameShark” that allows you to modify parts of the game (more money, add arbitary Pokemon to your party, etc). You could dump your save file and keep a backup on your computer. Or even dump the whole ROM!

Even though this project has been written for Pokemon Red, I’m sure it could run on Pokemon Blue, maybe even Yellow. If you do anything interesting, I’d like to hear about it.

https://vaguilar.com/2015/05/26/arbitrary-code-execution-in-pokemon-red