The description for the challenge is as follows:

This looks retro but somewhat futuristic! I always lose though, can you win? My friends solved this without IDA!

The challenge also included a file called ‘chall.ino.hex’.

First exploration

Having embedded software experience, the ‘ino.hex’ extension already gave a lot away: .ino is a project file for Arduino and .hex is most likely the Intel HEX format. Arduino’s are development kits that usually have AVR-microcontrollers on them. Opening the hex file in a text editor confirmed this:


See that 0C 94 that keeps repeating? That’s almost certainly the JMP instruction on the AVR, and the first area in any AVR application contains the interrupt vector table. When an interrupt occurs, the AVR jumps to (vector number * 4). Commonly, this table is filled with JMP instructions to jump to some other area of the program where the interrupts are handled. The first vector is called the ‘reset vector’ which is executed at the start of the program.

At this point, I was digging into the disassembly listing I had created, but soon realised this was the wrong approach. This challenge was marked as ‘easy’ and Google can’t be expecting people to know AVR assembler for an ‘easy’ challenge. The puzzle description also revealed a hint, saying it should be doable without IDA, so let’s keep looking.

So what else is there?

After converting the hex file to a binary with hex2bin I looked for strings in the binary, but that didn’t reveal anything interesting (and that would be too easy).

This being a graphical application, there are most likely some sprites in the binary aswell. I wrote a little PHP script to dump a sprite to a PNG:

// Arguments: <offset> <byte length> <pixels per row>
$offset = $argv[1];
$length = $argv[2];
$pprow = $argv[3];

$bin = file_get_contents('chall.ino.bin');
$img = imagecreatetruecolor($pprow, ceil(($length * 8) / $pprow));
$white = imagecolorallocate($img, 255, 255, 255);

for ($i = 0; $i < $length; $i++) {
    $byte = unpack('c', substr($bin, $offset + $i, 1))[1];
    for ($j = 0; $j < 8; $j++) {
        if ($byte & (1 << $j)) {
            $x = (int)((($i * 8) + (8 - $j)) % $pprow);
            $y = (int)((($i * 8) + (8 - $j)) / $pprow);
            imagesetpixel($img, $x, $y, $white);
imagepng($img, 'out.png');

After a bit of fiddling it turns out the sprites are 128 pixels wide (which is a common LCD display size) and the script came up with a readable output:

Bingo, there’s the flag!