Emu 2.0

Emulation, 50 points

Description

Hey! We have found this old cartridge under a desk in the library of Lapland. It appears to be for a system called "Emu 2.0", made back in 1978. These systems don't get produced anymore, and we can't seem to find anyone that owns one.

Thankfully we have the documentation for it, so maybe we can use it to write an emulator and see what this ROM does?

Author: Milkdrop

Files : rom, documentation.pdf

Solution

This challenge was pretty straightforward; we were given a ROM file along with a short 3-page specification, and we had to code an emulator to run the ROM which would print out the flag.

There's nothing much to detail further, so here's my implementation of the emulator in Python.

import sys

def emulate(filename):
    rom = open(filename, 'rb').read()
    assert len(rom) == 0xf00

    A = 0
    PC = 0x100
    mem = [0] * 0x100 + [x for x in rom]
    blocked = [False] * 0x1000

    while 0 <= PC < 0xfff:
        op = mem[PC:PC + 2]

        # Arithmetic
        if op[0] == 0x00:
            A = (A + op[1]) & 0xff
        elif op[0] == 0x01:
            A = op[1]
        elif op[0] == 0x02:
            A ^= op[1]
        elif op[0] == 0x03:
            A |= op[1]
        elif op[0] == 0x04:
            A &= op[1]
        elif op[0] >> 4 == 0x08:
            A = mem[((op[0] & 0x0f) << 8) | op[1]]
        elif op[0] >> 4 == 0x0d:
            if not blocked[((op[0] & 0x0f) << 8) | op[1]]:
                mem[((op[0] & 0x0f) << 8) | op[1]] ^= A
        elif op[0] >> 4 == 0x0f:
            if not blocked[((op[0] & 0x0f) << 8) | op[1]]:
                mem[((op[0] & 0x0f) << 8) | op[1]] = A

        # I/O        
        elif op[0] == 0x13 and op[1] == 0x37:
            sys.stdout.write(chr(A))
            sys.stdout.flush()

        # Control Flow
        elif op[0] >> 4 == 0x02:
            PC = ((op[0] & 0x0f) << 8) | op[1]
            continue
        elif op[0] >> 4 == 0x03:
            if A == 0x00:
                PC = ((op[0] & 0x0f) << 8) | op[1]
                continue
        elif op[0] >> 4 == 0x04:
            if A == 0x01:
                PC = ((op[0] & 0x0f) << 8) | op[1]
                continue
        elif op[0] >> 4 == 0x05:
            if A == 0xff:
                PC = ((op[0] & 0x0f) << 8) | op[1]
                continue
        elif op[0] == 0x60:
            if A == op[1]:
                A = 0x00
            elif A > op[1]:
                A = 0xff
            else:
                A = 0x01
        elif op[0] >> 4 == 0x07:
            c = mem[((op[0] & 0x0f) << 8) | op[1]]
            if A == c:
                A = 0x00
            elif A > c:
                A = 0xff
            else:
                A = 0x01
        elif op[0] == 0xbe and op[1] == 0xef:
            PC = 0x100
            A = 0x42
            continue

        # Security
        elif op[0] >> 4 == 0x09:
            blocked[((op[0] & 0x0f) << 8) | op[1]] = True
        elif op[0] >> 4 == 0x0a:
            blocked[((op[0] & 0x0f) << 8) | op[1]] = False
        elif op[0] >> 4 == 0x0c:
            if not blocked[((op[0] & 0x0f) << 8) | op[1]]:
                mem[((op[0] & 0x0f) << 8) | op[1]] ^= 0x42

        # Misc
        elif op[0] == 0xee and op[1] == 0xee:
            pass

        else:
            A = (A - 1) & 0xff

        PC += 2

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('[-] Usage: %s <romfile>' % sys.argv[0])
        sys.exit(1)
    sys.exit(emulate(sys.argv[1]))

Let's run it on the file.

╭─face0xff@aniesu-chan /den/ctf/xmas  
╰─$ python rom.py rom                                                                                                                                                                                      1 ↵
X-MAS{S4nt4_U5e5_An_Emu_2.0_M4ch1n3}

We can notice the program actually never ends because it is stuck in an infinite loop. Indeed, at PC=0x408, the instruction is 24 08 which means "jump to 0x408".

Enjoy

Last updated