I don’t really like games.
Screen graphics make me nauseous. The political interactions between players are tedious. I’m not a fan of chance, I stink at riddles and it’s rare that someone can concoct a mystery that I cannot immediately resolve.
Then I became an app pentester. And not long after I started my new career, I realized I’d found a game I loved. I stayed at my pentesting job at Matasano 3x longer than any other job. Why? Every week, there was a new puzzle to solve.
Security games have context. They have worlds. Severe vulnerabilities for online banking are footnotes for CRMs. Each gig, I figured this out on the fly, designed test programs on the fly. There was time pressure. I had to think. I had to solve. So when I hosed a $50,000 “data loss protection” server for 24 hours with a single packet, or DDOS’d a high availability trading server, I felt really fucking smart. I am a utilitarian at heart, and this was my fix.
Fast forward almost a decade.
We’ve started a company to help fix hiring. We had two ideas: run job interviews for other companies Somewhere in an alternate universe, we are building a far less ambitious codebase and hating life just as much. , or build a giant game, a CTF, that replicated the experience of doing work. We had to pick one idea. The CTF/game idea, at the time, sounded like a lot more fun, so we went with it.
In 2014, my former co-workers built a CTF called Microcorruption. In it, you reverse-engineer a series of locks built on a microcontroller, exploiting flaws in the lock’s code. I loved Microcorruption. I think I got through 10 levels before I ran out of free time. I’d never before watched a machine execute instructions, step by step, seeing the stack pointer move through the program memory while meaningful numbers were loaded into registers and shuffled around. This… this is my kind of game.
You can still play Microcorruption; it’s still running. We knew we wanted Starfighter to be like Microcorruption. But we also knew it had to be more.
For Microcorruption, Tom wrote a TI MSP430 emulator in Go. When we began Starfighter, Tom said to me, “You’re going to write an AVR emulator.” At the time, I didn’t really think to ask why. I had no idea what AVR was beyond “an instruction set.” I just smiled and said, “Okay.”
So I wrote an emulator using the Atmel 8-Bit AVR specs. I’d never written an emulator. Or anything else as big as an emulator. It’s one of the hardest things I’ve ever done Not quite as hard as jumping over a pile of sandbags on skates, but still hard. . Each night, for almost two months, I’d crawl into bed, completely mentally drained. There were more problems to solve than I knew how to handle. And I was like a pig at a slop trough.
Tom wrote a guidebook based on his experience writing Microcorruption’s MSP340 emulator for me, but it’s only today —– long after the emulator is finished —– that I read the second half. Because at some point, it became very apparent that AVR… well, it was just plain weird.
His guidebook describes a CPU as a struct with two arrays: one for memory and another for registers, stack pointer, program counter and status bits. Those of you who know a little AVR will be amused to hear me say that I did not get very far with that design.
“Some of these instructions seem to be looking for the stack pointer in memory,” says I.
“It can’t work that way,” Tom responded.
“Yes it can.”
“No it can’t. That’s not how computers work.”
We squabbled. I really did try it his way. I pushed the square peg of Tom’s CPU description through the squiggly amoeba-shaped hole of the AVR ISA. Hard. Then I gave up and rewrote my code, putting the program instructions in one array and the the stack pointer, general purpose registers and the status register in another.
A few days later, Tom says, “Something something blah blah Harvard Architecture blahdy-blah.” I’m sure this is not exactly what he said, but I was in such a fugue state by this point that time was folding in on itself.
A Harvard Architecture has two distinct memories; there is program memory (imem, typically flash) and data memory (dmem, typically SRAM). They live in two different address spaces. The CPU reads instructions from imem, but instructions themselves read and write dmem.
This is neat because makes exploits harder to write. You can’t simply upload code in a buffer and somehow point the PC at it; that buffer is in dmem, not imem. You’ll see what I mean in a few weeks.
AVR gets weirder. The stack pointer gets IN’d and OUT’d to an IO address in memory — it’s a peripheral. “Computers don’t work that way!”, says Tom. I ignored him.
The general purpose registers and IO are in reserved data memory address space. The status register is also in the dmem address space. Yes, computers work that way, Tom. Some instructions look in a reserved location in IO memory to retrieve the stack pointer. But you can read all about registers on page 8 of the ATMega8515 Datasheet Summary. And in my corner of the Starfighter game, you’ll get to play with all of this stuff.
AVR is not like MSP430. It’s not like X86. It is not, as Thomas claims, “like someone vomited up an instruction set”. It’s a complicated microcontroller instruction set designed for tiny parts with small programs that don’t change often. To date, I’ve ‘discovered’ 142 instructions through test code. There are something like 16 load and 13 store instructions. A summary table can be found on pages 10-12 of the ATMega8515 Datasheet Summary.
Well, I did say I wanted to work on something more fun, didn’t I?
Yeah, so… I was planning on telling you more about our game. Sorry. I have a tendency to natter.
Back in the dawn of time, before electricity and running water, when dinosaurs roamed the earth and stack pointers weren’t peripherals and an emulator was “just a pair of arrays”, Patrick wrote a post about what we’re doing. The one where he said there’d be tech trees.
The goal in Microcorruption was trivial. Flip a bit, open a lock. Lock software gets patched; overflow memory, open a lock. Starfighter is more ambitious. It has PVP elements. I draws on all the fun stuff we’ve done over the years at Matasano. Stuff like when Tom called me and asked if he could have a truckload of pork bellies (CME ticker:GBP. And: I told him no.) delivered to our house.
For the past two months, Patrick has been been building an online trading market. A virtual stock exchange with realistic limit order book markets. With NPCs that trade, in real orders. In Patrick’s tech tree, your gameplay can move markets. At some levels, you’ll play not just to game the market but to compete with other players —– if that’s how you get your fix.
(Y.T., knowing diddly about markets, is very much looking forward to playing the market tree.)
Players on the security tech tree are given a handheld device of the sort a trader could carry around the floor to execute trades. But you’re not a trader; you’re more like a runner. A gopher. Your handheld is locked; you’re not allowed to trade. So you learn AVR. You subvert the device. Escalate your read-only privileges to read-write. Submit your own trades. Crawl through the HVAC ducts into the machinery of the market and see how much damage you can do.
Don’t want to learn AVR? Don’t worry! Patrick’s trading application is just the sort of third party JSON/REST tool you’d see on a day trader’s desktop. But — there’s always a ‘but’, isn’t there? — in upcoming levels, to get high-performance access to the markets, you’ll benefit from writing low level code to talk to markets.
But not necessarily AVR. Thomas built a compiler for Starfighter. This, dear reader, is why you have been waiting ever so patiently for our release. As it turns out, even a crappy compiler is tricky to write.
Unlike Microcorruption, we wanted Starfighter to be multi-architecture. It will be, but in chapter 1, only sort of. Instead, players work with C, with an executable bytecode IR, and with its translation into AVR.
It is a terrible compiler. I could barely write enough C to test my AVR emulator and I know it’s a crappy compiler. Hint: terrible is part of the point.
We’re giving players the dev kit for the handheld trading device. You can program it in AVR assembly. But the vendor also offers support for a very limited dialect of C, compiled to bytecode IR or to AVR. Emphasis on “limited”. You know, because we did less of the fun stuff for you.
(In later releases, we’re hoping to do a tech tree with challenges that focus on compiler design.)
Just two months ago, Tom and I were driving to the grocery store and he says in the most idle and preoccupied tone, “This code base is really ambitious.” My reply: “No shit? You’re just now figuring this out?” Then I punched him in the shoulder.
Our code is a hot mess (of Golang and React) right now, but I’m excited.
We set out to build a game that would make it easy for people around the world to demonstrate raw aptitude for programming, and to spice it up with the endorphin fix we get from reversing and breaking complicated systems. I think we picked the right foundations to build on. Electronic trading is a huge problem domain that reaches into distributed systems and high-performance computing. Low-level software security pulls in compiler theory, cryptography, and language runtimes.
Network API programming! Trading! Order books! Assembly language! Runtime security! Cryptography! Reversing! Us pretending all our bugs were intentional, to make things more like the real world!
I think we’ve given ourselves a lot of places to go. We’re looking forward to seeing where you go with it. See you in a “few” weeks!