Add summary, fixups, and brain meme

This commit is contained in:
Jay 2020-08-30 11:01:09 -07:00
parent b7a8a80350
commit e0173f270b
2 changed files with 18 additions and 5 deletions

View File

@ -1,5 +1,16 @@
# Google CTF 2020 Write-up: Sprint
In this challenge, we're given a binary to reverse engineer. We find
that it's an interpreter for a Turing-complete language made entirely
of `sprintf` format strings, along with a program in this language.
We write a disassembler for this language, and use it to
reverse engineer the embedded program. We find that the embedded
program is a game, and map out a series of moves to win the game.
![The galaxy brain meme. Small brain: Writing a game in a high-level
language. Medium brain: Writing a game in x86 assembly. Large brain:
Writing a game in sprintf format strings](brain_meme.jpg)
## Picking apart the binary
We're given a single binary file. Running it through `objdump`, we
@ -149,7 +160,7 @@ In order:
to by vararg 3. That is, it writes it to the lower two bytes of
`regs[0]`.
3. `%1$65498s` writes 65498 spaces, so the total number of spaces so
far is 65536, or `0x10000`.
far is 65536, or `0x10000`.
4. `%1$28672s` writes 28672 spaces, or `0x7000` spaces.
5. `%9$hn` counts the number of characters written so far, and writes
it to the `short int` pointed to by vararg 9. That is, the lower
@ -346,7 +357,7 @@ Now we can see the output:
### Using `gdb`
Now we have yet another chunk of assembly to reverse. It will be
useful to be able to use `gdb` to step through this code, so lets
useful to be able to use `gdb` to step through this code, so let's
understand how to do that. The call to `sprintf` is at `main+555`, so
by putting a breakpoint there, we can step through the embedded code
one instruction at a time. To view the 10 registers, we can examine
@ -404,7 +415,9 @@ but I'll leave that out for brevity.
We'll jump straight to the first place where we read the user input.
Instead of picking apart the code before that, we can just use `gdb`
to examine the state of the program at this point.
to examine the state of the program at this point. Since the earlier
code doesn't reference the user input, the state here will always be
the same.
0374: mov 0xe000, %r2 # Address of user input
039a: mov 0x0, %r3 # Counter, initialized to 0
@ -444,7 +457,7 @@ Next we load some data into registers
0536: mov 0x0, %r2
0558: mov 0x0, %r3
057b: mov 0xf100, %r1
05a1: mov (%r1), %r4 # Read from 0xf100, value = 0x11
05a1: mov (%r1), %r4 # Read from 0xf100, value = 0x11
05c6: mov 0x1, %r5
05e9: mov 0x0, %r9
@ -588,7 +601,7 @@ can't ever enter an invalid direction, and we can't ever step on
nonzero terrain. We also see that we need to step on exactly nine
checkpoints.
The register `%r9` appears to hold a "reason code" for why we lose.
The register `%r9` appears to hold a reason code for why we lose.
This could be useful for debugging later.
There's still more code after, but for now our task is clear: we need

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB