BinaryGolf 2023: Building A GameBoy-Bash Polyglot

binary ctf

In the BinaryGolf competition, specific file related problems have to be solved with the least amount of bytes. This was the challenge for the 2023 edition:

Me and some other guy decided to go for a GameBoy ROM with an embedded bash script, since old file formats like game ROMs are quite interesting. In the end, we came up with such a polyglot file that met all criteria of the challenge and was 397 bytes in size. This is a short demo of it:

As you can see, the file is a valid bash script that launches a GameBoy emulator with its own file as input to display a 4 after replicating.

The first obvious idea to create this file was to use a GameBoy ROM creator like GB Studio. However, even a ROM with minimal content was still huge in size. It seems that being lazy was not the way to go :). In the end, we used a simple Hello World example in pure ASM as a template. Of course we didn’t understand all aspects of this template but we still managed to reduce the resulting file size a bit by removing parts using trial and error. An important thing to do is to strip all zero bytes at the end of the resulting ROM file, since they seem to be irrelevant.



Our initial plan was to use an example that just printed some text on the screen so that we could replace the text with a 4. However, it seems that font files have to be included when printing a pre-defined string to the screen. Since most fonts are huge, we decided to try something else. In the old days of the GameBoy, disk space was a limiting factor, so clever developers used various tricks to save some of that. One of them was a technique called Tile Map. This basically allows to define (and to design) a small number of visual tiles once and referencing them multiple times using tile maps, which are ultimately used to draw content on the screen. To display a 4, you could define a white tile once and re-use it a number of times to draw all pixels required for the desired result.

We found out that this does not only save space but also allows embedding a shell script inside of the ROM file because tile data is placed at the start of the ROM. Therefore, we can overwrite this tile data partially using a hex editor after compiling the ROM. The hardest part was defining the tiles and tile maps because low-level GameBoy tooling is nuts.

You can find our source code here (which is based on this Hello World example):

INCLUDE "hardware.inc"

SECTION "Header", ROM0[$100]

	jp EntryPoint
	ds $150 - @, 0 ; Make room for the header

EntryPoint:
	; Shut down audio circuitry
	ld a, 0
	ld [rNR52], a
    ld a, 4

	; Do not turn the LCD off outside of VBlank
WaitVBlank:
	ld a, [rLY]
	cp 144
	jp c, WaitVBlank

	; Turn the LCD off
	ld a, 0
	ld [rLCDC], a

	; Copy the tile data
	ld de, Tiles
	ld hl, $9000
	ld bc, TilesEnd - Tiles
CopyTiles:
	ld a, [de]
	ld [hli], a
	inc de
	dec bc
	ld a, b
	or a, c
	jp nz, CopyTiles

	; Copy the tilemap
	ld de, Tilemap
	ld hl, $9800
	ld bc, TilemapEnd - Tilemap
CopyTilemap:
	ld a, [de]
	ld [hli], a
	inc de
	dec bc
	ld a, b
	or a, c
	jp nz, CopyTilemap

	; Turn the LCD on
	ld a, LCDCF_ON | LCDCF_BGON
	ld [rLCDC], a

	; During the first (blank) frame, initialize display registers
	ld a, %11100100
	ld [rBGP], a

Done:
	jp Done

SECTION "Tile data", ROM0

Tiles:
	db $00,$00,$20,$00,$20,$00,$20,$00,$28,$00,$3C,$00,$08,$00,$08,$00
TilesEnd:

SECTION "Tilemap", ROM0

Tilemap:
	db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, 0,0,0,0,0,0,0,0,0,0,0,0
TilemapEnd:

This is the resulting ROM in Base64:

IyEvYmluL3NoCmNwICQwIDQ7Z2VhcmJveSAkMCAjAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wD/AP8A/wD/AP8A/wD/AIAAgACAAIAAgACAAIAAgMNQAQDO7WZmzA0ACwNzAIMADAANAAgRH4iJAA7czG7m3d3Zmbu7Z2NuDuzM3dyZn7u5Mz4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5/22PgDqJv8+BPpE//6Q2lcBPgDqQP8R4AAhAJABIAAaIhMLeLHCbQERAAAhAJgB4AAaIhMLeLHCfwE+gepA/w==

37C3 CTF: ezrop

ctf reversing exploitation rop radare2 r2

Game Hacking #5: Hacking Walls and Particles

reverse-engineering c++ binary gamehacking

Game Hacking #4: Cheating in Unity Games

frida gamehacking binary