1

So I have annotated what I think it means next to each instruction and have put a (?) next to each instruction which I am unsure of/not quite certain it does that function. There are probably a lot more of ones I am unsure of than I have marked, but they are mostly the same type of instruction.

0x0000000000401251 <+0>:     sub    $0x8,%rsp 
0x0000000000401255 <+4>:     cmp    $0x1,%rdi                              #compare num of inputs (?)
0x0000000000401259 <+8>:     jg     0x40126c <phase_3+27>                  #blow up if not >1
0x000000000040125b <+10>:    callq  0x401c01 <bomb_ignition>
0x0000000000401260 <+15>:    mov    $0xffffffffffffffff,%rax
0x0000000000401267 <+22>:    jmpq   0x40136c <phase_3+283>
0x000000000040126c <+27>:    lea    0x16(%rdi),%rax                        #rax = rdi[22] (?)
0x0000000000401270 <+31>:    sub    $0x4b,%rsi                             #rsi -= 75 
0x0000000000401274 <+35>:    cmp    $0x2b,%rsi                             #rsi == 43
0x0000000000401278 <+39>:    ja     0x40133a <phase_3+233> bomb_ignition   #rsi>43 -> blow up (?)
0x000000000040127e <+45>:    jmpq   *0x4027b0(,%rsi,8)                     # (?) 
0x0000000000401285 <+52>:    mov    %rdi,%rax                              #rax = rdi
0x0000000000401288 <+55>:    neg    %rax                                   #rax = -rax (flip bits)
0x000000000040128b <+58>:    sub    $0x7,%rax                              #rax -= 7
0x000000000040128f <+62>:    lea    0x14(%rax,%rax,2),%rdi                 #rdi = rax*3+20
0x0000000000401294 <+67>:    jmpq   0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x0000000000401299 <+72>:    sar    %rax                                   #rax /= 2
0x000000000040129c <+75>:    mov    %rax,%rdi                              #rdi = rax
0x000000000040129f <+78>:    jmpq   0x401351 <phase_3+256                  #goto <256>/ compare rdi == 120
0x00000000004012a4 <+83>:    lea    0x0(,%rax,8),%rdi                      #rdi = rax+8
0x00000000004012ac <+91>:    jmpq   0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x00000000004012b1 <+96>:    sar    $0x2,%rax                              #rax /= 4
0x00000000004012b5 <+100>:   mov    %rax,%rdi                              #rdi = rax
0x00000000004012b8 <+103>:   jmpq   0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x00000000004012bd <+108>:   callq  0x401c01 <bomb_ignition>               #bomb_ignition
0x00000000004012c2 <+113>:   mov    $0xfffffffffffffffe,%rax
0x00000000004012c9 <+120>:   jmpq   0x40136c <phase_3+283>                 #exit            (2 bomb explosions in a row?)
0x00000000004012ce <+125>:   callq  0x401c01 <bomb_ignition>               #bomb_ignition
0x00000000004012d3 <+130>:   mov    $0xfffffffffffffffd,%rax               
0x00000000004012da <+137>:   jmpq   0x40136c <phase_3+283>                 #exit
0x00000000004012df <+142>:   lea    (%rax,%rax,1),%rdi                     #rdi = rax*2
0x00000000004012e3 <+146>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x00000000004012e5 <+148>:   lea    0x0(,%rax,4),%rdi                      #rdi = rax*4
0x00000000004012ed <+156>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x00000000004012ef <+158>:   lea    (%rax,%rax,8),%rdi                     #rdi = rax*9
0x00000000004012f3 <+162>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x00000000004012f5 <+164>:   lea    0xb(,%rax,4),%rax                      #rax = rax*4+11
0x00000000004012fd <+172>:   sub    $0xb,%rax                              #rax -= 11
0x0000000000401301 <+176>:   add    $0x15,%rax                             #rax += 21
0x0000000000401305 <+180>:   lea    0x14(%rax,%rax,4),%rdi                 #rdi = rax*5
0x000000000040130a <+185>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x000000000040130c <+187>:   lea    0xb(%rax,%rax,1),%rdi                  #rdi = rax*2+11
0x0000000000401311 <+192>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x0000000000401313 <+194>:   lea    0x13(,%rax,8),%rdi                     #rdi = rax*8+19
0x000000000040131b <+202>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x000000000040131d <+204>:   lea    (%rax,%rax,4),%rdi                     #rdi = rax*5
0x0000000000401321 <+208>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120              
0x0000000000401323 <+210>:   add    $0x24,%rdi                             #rdi += 36              
0x0000000000401327 <+214>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x0000000000401329 <+216>:   mov    $0x11,%edi                             #edi = 17
0x000000000040132e <+221>:   sub    %rax,%rdi                              #rdi -= rax 
0x0000000000401331 <+224>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x0000000000401333 <+226>:   lea    0x15(%rax,%rax,8),%rdi                 #rdi = rax*9+21
0x0000000000401338 <+231>:   jmp    0x401351 <phase_3+256>                 #goto <256> / compare rdi == 120
0x000000000040133a <+233>:   callq  0x401c01 <bomb_ignition>               #bomb
0x000000000040133f <+238>:   mov    $0xffffffffffffffff,%rax
0x0000000000401346 <+245>:   jmp    0x40136c <phase_3+283>                 #exit
0x0000000000401348 <+247>:   lea    (%rax,%rax,2),%rax                     #rax = rax*3
0x000000000040134c <+251>:   lea    0x8(%rax,%rax,4),%rdi                  #rdi = rax*5+8
0x0000000000401351 <+256>:   cmp    $0x78,%rdi                             #rdi == 120
0x0000000000401355 <+260>:   sete   %al
0x0000000000401358 <+263>:   movzbl %al,%eax
0x000000000040135b <+266>:   cmp    %rdx,%rdi                              #rdi == rdx
0x000000000040135e <+269>:   je     0x40136c <phase_3+283>                 #exit if rdi == rdx
0x0000000000401360 <+271>:   callq  0x401c01 <bomb_ignition>
0x0000000000401365 <+276>:   mov    $0xffffffffffffffff,%rax
0x000000000040136c <+283>:   add    $0x8,%rsp
0x0000000000401370 <+287>:   retq

What i think it does is takes 2 inputs. rax then becomes the item at the 22nd index of rdi. This is where Im already uncertain as I thought rdi is number of inputs. Also, im not sure if thats how lea works. Then it does some math on rsi and if its greater than 43, then blow up. So rsi should be 118, quick maths. Although could it be any number smaller than 118? Seeing as subtracting 75 will make it smaller than 43? Anyway. It then jmpq. Which is again where I am uncertain. This is a lookup table, correct? So I put into gdb and got the following:

(gdb) x/8a 0x4027b0
0x4027b0: 0x4012bd <phase_3+108>  0x401299 <phase_3+72>
0x4027c0: 0x40133a <phase_3+233>  0x40130c <phase_3+187>
0x4027d0: 0x4012df <phase_3+142>  0x401333 <phase_3+226>
0x4027e0: 0x401301 <phase_3+176>  0x4012df <phase_3+142>

So the 8th one is <phase_3+142>. So does this just jump to that position? And skip everything between it? Im hoping and assuming so, as there is a lot of calculations that happen if you dont. Have I looked at the correct thing in gdb? If so, then it goes to <+142> which changes rdi to rax*2. Is that what lea does, have I correctly assumed what that instruction is doing? Then it immediately jumps to <+256> which compared rdi to 120. And then rdx should also be the same.

So working backwords, rdx = rdi = 120. Then rdi = rax*2, so rax = 60. But, rax = rdi[22], again assuming thats what lea is doing. But if rdi is number of inputs, how can it have 22 characters? Then assuming its not number of inputs, how can the 22nd character be a 2 digit number?

Based on previous phase (you can see my history if you like), I think that %rdi contains the number of inputs. I could be wrong though. Here is the actual working in bomb.c

k = sscanf(input, "%d %d", &a, &b);
status = phase_3(k, a, b);
phase_defused(status);

So based on that, I assume &a and &b are the inputs, and are registers %rsi and %rdx respectively. I tried 118 120 but it blew up.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Alonzo Robbe
  • 465
  • 1
  • 8
  • 23
  • That first `lea` is just `rax = rdi + 22`. The C equivalent is `rax = &rdi[22]`. You were missing the `&`. LEA is a shift-and-add instruction that uses addressing mode syntax and machine encoding. https://stackoverflow.com/a/7071164/224132 – Peter Cordes Sep 20 '17 at 12:00
  • Yes, `jmpq *0x4027b0(,%rsi,8)` is an indirect jump from a table of addresses. I didn't know gdb had a `/a` format that put symbolic labels onto addresses; that's cool :P (Usually I have source, and am not reverse-engineering). It looks like you're using it correctly. Once the CPU figures out the jump target address, it works exactly like an ordinary direct jump. The next instruction to be executed is the one at that target address, and execution continues from there. – Peter Cordes Sep 20 '17 at 12:05
  • You might want to try marking jump targets in the disassembly. E.g. add a blank line before `0x4012bd`, and put `jumptable_0:` on it. Agner Fog's [`objconv` disassembler](http://agner.org/optimize/#objconv) can add branch targets for you, but I think you'll only get that for direct jumps. (Still, can be useful to find the top of loops easily.) I had good results with it when doing a binary bomb for fun a while ago. – Peter Cordes Sep 20 '17 at 12:10
  • BTW, have you tried single-stepping in GDB to follow the execution of your guess? Or is that considered cheating by making it too easy? See GDB tips at the bottom of https://stackoverflow.com/tags/x86/info. You can see values in registers to confirm that you're right about `rdi` being the scanf return value. (I'm sure that's correct, though.) – Peter Cordes Sep 20 '17 at 12:12
  • I didn't try to grok the whole code, just answer some of what you specifically asked about. Hopefully that gets you un-stuck. – Peter Cordes Sep 20 '17 at 12:15
  • @PeterCordes Thank you so much for the writeups. I'll try my best. If you ever have the chance, or free time, would you mind trying to grok the thing? Thanks again! – Alonzo Robbe Sep 21 '17 at 03:58
  • Hint, we know `rdi` has to be 2 on function entry, because scanf can't ever return more than the number of conversions (and less than 2 would explode). So `lea 0x16(%rdi),%rax` sets `rax=24`. Again, I highly recommend single-stepping this with GDB to see values in registers. (`layout reg`). – Peter Cordes Sep 21 '17 at 04:09
  • @PeterCordes Hmm yes, I inputted `118 120` and looked at `layout regs` and `rdi` is amount of inputs, confirmed. `rdx` = 120 and `rsi` = 43 after calculations. `rax` = 24 like you said. However, with this information, how do I make it so `rax` = 60? I tried putting `118 120 1 1 1 1... (36 1s)` so `rdi` would be 38, then 38+22 = 60. However it told me input is too long. And furthermore `layout regs` showed absurd values for the regs. If input `1`s such that it isnt too long, then `rdi` still only shows `2`, and `rax = 24` – Alonzo Robbe Sep 21 '17 at 04:48
  • Like I said, `scanf` won't ever return higher than 2 with `"%d %d"` as the format string, because it only has 2 conversion specifiers, so it will leave later digits unread. See http://man7.org/linux/man-pages/man3/scanf.3.html#RETURN_VALUE. – Peter Cordes Sep 21 '17 at 05:14
  • Hint: when commenting the asm, try giving symbolic names to the values, and use a new name for the result of a sequence of calculations. So instead of `#rdi = rax*3+20`, maybe `tmp3 = tmp2*3 + 20`. This helps you separate an independent use of a register from an earlier use, so it's like mental register renaming. – Peter Cordes Sep 21 '17 at 05:20
  • @PeterCordes of course, I dont know how I skimmed over/forgot that `scanf` only takes 2. I guess ill try to change the names, but I dont know how, because arent they all reusing the same register and overwriting their values? BTW, do you know what the answer is, or an idea of what it is supposed to be? – Alonzo Robbe Sep 21 '17 at 08:07
  • No, I haven't worked through it. This one's more complicated than the last, so it would take me several minutes of effort. (Also, I don't have the binary so I can't just single-step it). – Peter Cordes Sep 21 '17 at 09:35
  • Well, compilers think about data flow using a new name after every step: https://en.wikipedia.org/wiki/Static_single_assignment_form. (CPU hardware register renaming is similar.) What I was suggesting was SSA except using the same name within a series of calculations on the same register, to collapse multiple asm instructions into something like `z = (6 * y + 4)` or something if that was done in multiple steps. But any time variables interact with each other (compared or used as inputs), use a new name. – Peter Cordes Sep 21 '17 at 09:39
  • You'll probably simplify more than that pretty quickly once you start, maybe using some more meaningful names once you see how a variable is used (like `index` maybe?). But my point is to start from SSA, instead of just treating register names as C variables, because that doesn't get you anywhere. You can just read the instructions directly to see that `sub $0x7,%rax` does `rax -= 7`. That's not a useful comment if you understand asm syntax. But `offset -= 7` could be a useful comment. – Peter Cordes Sep 21 '17 at 09:41
  • @PeterCordes Just a thought that came to my mind. Have I done the lookup table correctly? Like the correct input into `gdb` and looking at the 8th value? Also, whats purpose is `(,%rsi,8)`. I know its `rsi*8` but what is it actually doing? Is it changing `rsi`'s value, or is it just there because it has to? – Alonzo Robbe Sep 22 '17 at 04:13
  • Addressing modes only read registers you use in them. `0x4027b0(,%rsi,8)` is AT&T syntax for `[0x4027b0 + rsi*8]`. In AT&T syntax, it's even more clear that this addressing mode has a disp32 and a scaled index register, but no base register (the empty slot between the `(` and first `,`). See also https://stackoverflow.com/questions/34058101/referencing-the-contents-of-a-memory-location-x86-addressing-modes – Peter Cordes Sep 22 '17 at 04:48
  • @PeterCordes okay, so `0x4027b0 + rsi*8`, with `rsi=43` gives `0x402908` If I view this in `gdb`, `x/1a 0x402908`, it returns `0x4012ce `.. which is `bomb_ignition`. Ive been wracking my brain for 3 days and Im literally all out of ideas. Im sorry if im not understanding your hints, or comments, I do appreciate them. – Alonzo Robbe Sep 22 '17 at 05:07
  • BTW, this comment is wrong: `#rax = -rax (flip bits)`. `neg` is 2's complement. Flipping the bits would be `not`, one's complement. `0-x` is `~x + 1` in 2's complement. – Peter Cordes Sep 22 '17 at 05:56
  • `rsi` gives you a choice of 43 branch targets. That's a lot. Have you tried working backwards from the `ret` at the end to see what execution paths can get you there? – Peter Cordes Sep 22 '17 at 05:58

0 Answers0