pages/blog/r2wars-2020.md (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
--- template: slug: r2wars-2020 title: My submissions for r2wars 2020 subtitle: If I learnt one thing, it's that ARM is the future date: 2020-09-13 --- [r2wars](https://github.com/radareorg/r2wars) is a [CoreWar](http://corewars.org)-like game thar runs within the radare2 [ESIL](https://radare.gitbooks.io/radare2book/content/disassembling/esil.html) virtual machine. In short, you have two programs running in a shared memory space (1kb), with the goal of killing the other and surviving as long as possible. r2wars was conducted as a part of [r2con2020](https://rada.re/con/2020). ## day 1 My first submission was an incredibly simple "bomber". All it does is write code to a location, jump there, and continue executing the same thing over and over. ```asm mov eax, 0xfeebfeeb; just some bad jumps mov ebx, eax mov ecx, eax mov edx, eax mov ebp, eax mov edi, eax mov esp, 0x3fc mov esi, 0x3fd mov [esi], 0xe6ff60 jmp esi ``` Specifically, it writes `0xe6ff60`, which is ```asm pushal jmp esi ``` effectively looping over and over. `pushal` is a very interesting x86 instruction, that pushes all the registers and decrements the stack pointer `esp` by how many ever bytes were pushed. Nifty, especially if you're looking for high throughput (to bomb the address space). Here, it starts bombing from `0x3fc` - `0x000` (and below, because there's no bounds checking in place), and ends up killing itself, since writing outside of the arena (`0x000` - `0x400`) is illegal. Ultimately, this bot placed 7th out of 9 contestants -- an underwhelming outcome. I had to fix this. ![day 1](https://cdn.icyphox.sh/gk1i0.png) ## day 2 I sat for a second and recollected the different reasons for my bot getting killed, and the one that occurred the most was my bot insta-dying to bad instructions being written from `0x400` -- i.e. from near where I'm positioned. Nearly all competing bots write from bottom up, because `pushal` _decrements_ the stack pointer. So the obvious solution was to reposition my initial payload way above, at `0x000`. And of course, it goes without saying that this assumes everyone's using `pushal` (they are). ```asm mov eax, 0xffffffff mov ecx, eax mov edx, eax mov ebx, eax mov ebp, eax mov esi, eax check: mov edi, 0x000 cmp [edi], 0 jne planb mov esp, 0x400 inc edi mov [edi], 0xe7ff6060; pushal, jmp edi jmp edi planb: mov edi, 0x3fb mov [edi], 0xe7ff6060 mov esp, 0x3fa jmp edi ``` I also added a (pretty redundant) check to see if the stuff at `edi` was 0, since the entire arena is initially `0x0`. My reasoning, albeit flawed, was that if it wasn't 0, then it was unsafe to go there. In hindsight, it would've been _safer_, since it's already been written over by somebody. In any case, `planb` never got executed because of what I'd mentioned earlier -- *everyone* writes from `0x400`. Or anywhere above `0x000`, for that matter. So I'm relatively safer than I was in day 1. These changes paid off, though. I placed 4th on day 2, out of 13 contestants! This screenshot was taken on my phone as I was eating dinner. ![day 2](https://cdn.icyphox.sh/5ZJfT.png) All wasn't well though -- I still lost 4 matches, for the reasons below: 1. I'd get snuffed out before my bomb wave from `0x400` would reach the opponent. 2. I'd end up bombing myself without hitting anyone on the way up. ## day 3 I needed to add some checks to prevent killing myself in the process of bombing. ```asm mov eax, 0xffffffff mov ecx, eax mov edx, eax mov ebx, eax mov ebp, eax mov esi, eax mov edi, 0x000 mov esp, 0x400 mov [edi], 0x20fc8360 mov [edi+4], 0xff600374 mov [edi+8], 0x0400bce7 mov [edi+12], 0xe7ff0000 jmp edi ``` If you noticed, the initial payload I'm writing to the address at `edi` is a bit more complex this time -- let's break it down. ``` 0x20fc8360 0xff600374 0x0400bce7 0xe7ff0000 ``` This translates to: ```asm 60 pushal 83 FC 20 cmp esp, 0x20 74 03 je 9 60 pushal FF E7 jmp edi BC 04 00 00 00 mov esp, 0x400; <- 0x9 FF E7 jmp edi ``` I check if the stack pointer is `0x20` (decrements from `0x400` due to `pushal`); if yes, reset to `0x400`, else continue looping. This prevented me from writing myself over, and also resets bombing from `0x400` -- better chance of hitting someone we missed in our first wave. Sounds good? That's what I thought too. Day 3 had a bunch of new bot submissions (and some updated submissions), and a lot of them checked `0x000` for existence of a bot, effectively recking me. I placed 8th out of 14 contestants, with 7 wins and 6 losses. Tough day. ![day 3](https://cdn.icyphox.sh/IKqxD.png) ## day 4: the finals I spent a lot of time refactoring my bot. I tried all kinds of things, even reworked it to be entirely mobile using the `pushal` + `jmp esp` trick, but I just wasn't satisfied. In the end, I decided to address the problem in the simplest way possible. You're checking `0x000`? Okay, I'll reposition my initial payload to `0xd`. And this surprisingly tiny change landed me in 4th place out of 15 contestants, which was _way_ better than I'd anticipated! The top spots were all claimed by ARM, and naturally so -- they had a potential throughput of 64 bytes per cycle thanks to `stmia`, compared to x86's 32 bytes. Pretty neat! ![day 4](https://cdn.icyphox.sh/DJbEE.png) ## links and references - [Anisse's r2wars 2019 post](https://anisse.astier.eu/r2wars-2019.html) - [Emile's intro to r2wars](https://www.tildeho.me/r2wars/) - [How not to suck at r2wars](https://bananamafia.dev/post/r2wars-2019/) - [r2wars: Shall we play a game?](https://ackcent.com/r2wars-shall-we-play-a-game/) - [Shell Storm's online (dis)assembler](http://shell-storm.org/online/Online-Assembler-and-Disassembler) - [radare2](https://github.com/radareorg/radare2) - [r2wars game engine](https://github.com/radareorg/r2wars) - [Anisse's bot workspace](https://github.com/anisse/r2warsbots) - [My bot dev workspace](https://github.com/icyphox/r2wars-bots) - [r2con YouTube](https://www.youtube.com/channel/UCZo6gyBPj6Vgg8u2dfIhY4Q) ## closing thoughts This was my first ever r2wars, and it was an incredible experience. Who woulda thunk staring at colored boxes on the screen would be so much fun?! So much so that my parents walked over to see what all the fuss was about. Shoutout to [Abel](https://twitter.com/sanguinawer) and [pancake](https://twitter.com/trufae) for taking the time out to work on this, and _especially_ Abel for dealing with all the last minute updates and bot submissions! All things said, mine was still the best x86 bot -- so that's a win. ;) |