assemblyx86-64reverse-engineeringattsign-extension

What is happening in this Assembly code?


Background: I am doing a "binary bomb" assignment in which I must pass 6 different phases to 'defuse' the bomb. I can use a debugger to help keep track of values and step through each line of the Assembly. I am stuck on the second phase.

Goal: Find the 'password' for this phase that satisfy the following program. The correct password will move me on to the next phase

What I think I know: It looks like right away, it's trying to read in 6 numbers. When I disassembled the main() function of the entire bomb, I noticed the a line with "%d %d %d %d %d %d" so this phase must require 6 numbers. Also, it looks like there's a loop starting at 1 and ending after the counter is greater than 5. It seems to being tracked in the -0x4(%rbp) part of memory. It looks like at line, it compares what is being tracked in %eax to what is entered by the user(earlier stored in %edx at line to see if they're equal. If they aren't, the bomb will explode. If they are, it'll continue through the loop.

0x400ec9 <phase_2>:     push   %rbp
0x400eca <phase_2+1>:   mov    %rsp,%rbp
0x400ecd <phase_2+4>:   sub    $0x30,%rsp
0x400ed1 <phase_2+8>:   mov    %rdi,-0x28(%rbp)
0x400ed5 <phase_2+12>:  lea    -0x20(%rbp),%rsi
0x400ed9 <phase_2+16>:  mov    -0x28(%rbp),%rdi
0x400edd <phase_2+20>:  callq  0x4013e9 <read_six_numbers>
0x400ee2 <phase_2+25>:  mov    -0x20(%rbp),%eax
0x400ee5 <phase_2+28>:  test   %eax,%eax
0x400ee7 <phase_2+30>:  jns    0x400eee <phase_2+37>
0x400ee9 <phase_2+32>:  callq  0x401983 <explode_bomb>
0x400eee <phase_2+37>:  movl   $0x1,-0x4(%rbp)
0x400ef5 <phase_2+44>:  jmp    0x400f1f <phase_2+86>
0x400ef7 <phase_2+46>:  mov    -0x4(%rbp),%eax
0x400efa <phase_2+49>:  cltq
0x400efc <phase_2+51>:  mov    -0x20(%rbp,%rax,4),%edx
0x400f00 <phase_2+55>:  mov    -0x4(%rbp),%eax
0x400f03 <phase_2+58>:  sub    $0x1,%eax
0x400f06 <phase_2+61>:  cltq
0x400f08 <phase_2+63>:  mov    -0x20(%rbp,%rax,4),%eax
0x400f0c <phase_2+67>:  add    -0x4(%rbp),%eax
0x400f0f <phase_2+70>:  add    $0x1,%eax
0x400f12 <phase_2+73>:  cmp    %eax,%edx
0x400f14 <phase_2+75>:  je     0x400f1b <phase_2+82>
0x400f16 <phase_2+77>:  callq  0x401983 <explode_bomb>
0x400f1b <phase_2+82>:  addl   $0x1,-0x4(%rbp)
0x400f1f <phase_2+86>:  cmpl   $0x5,-0x4(%rbp)
0x400f23 <phase_2+90>:  jle    0x400ef7 <phase_2+46>
0x400f25 <phase_2+92>:  leaveq
0x400f26 <phase_2+93>:  retq

What I don't know: There are some new instructions here I'm not familiar with. 'cltq' apparently performs "sign-extend %eax to %rax" but I'm not really sure what that means in this case. Also, I don't understand the line 'mov -0x20(%rbp, %rax, 4), %edx' and what it does exactly. I understand it's moving what's stored in 0x20 to the %rdx register, but I don't know what should be in that spot in memory at that time. I know when doing my debugging, %rbp at -0x20 holds one of the 6 values I entered. But I'm not really sure what %rax and 4 do exactly.

If someone can see what the 6 numbers required are, GREAT! If not, I hope someone can at least shed some light on this code and the problems I'm having to help nudge me in the right direction! Thanks

Some wrong solutions I tested: 1 2 3 4 5 6; 10 20 30 40 50 60

(I didn't want to keep trying because each time I explode the bomb, I get a point off the assignment grade)


Solution

  • Let me see if I can break this code...

    I've tried to turn this into C code, so here goes:

    void read_six_numbers(int *array);
    void explode();
    
    int phase_2()
    {
        int array[6];
    
        read_six_numbers(array);
    
        if (array[0] < 0)
        {
            explode();
        }
    
        for (int i = 1; i <= 5; ++i)
        {
            int cur  = array[i];   // %edx
            int prev = array[i-1]; // %eax
    
            prev += i;
            prev++;
    
            if (prev != cur)
            {
                explode();
            }
        }
    }
    

    So to pass the test you will need the following sequence of numbers:

    n, n + 2, (n + 2) + 3, ((n + 2) + 3) + 4, (((n + 2) + 3) + 4) + 5, ((((n + 2) + 3) + 4) + 5) + 6
    

    or

    n, n + 2, n + 5, n + 9, n + 14, n + 20
    

    Where n is a positive number or zero.

    Here are my annotations of your assembly code:

    0x400ec9 <phase_2>:     push   %rbp
    0x400eca <phase_2+1>:   mov    %rsp,%rbp
    0x400ecd <phase_2+4>:   sub    $0x30,%rsp          // Reserve some space on the stack...
    0x400ed1 <phase_2+8>:   mov    %rdi,-0x28(%rbp)
    0x400ed5 <phase_2+12>:  lea    -0x20(%rbp),%rsi   // Compute the address of -0x20(%rbp) and store it in %rsi (I'm assuming this is an argument for read_six_numbers below)
    0x400ed9 <phase_2+16>:  mov    -0x28(%rbp),%rdi
    0x400edd <phase_2+20>:  callq  0x4013e9 <read_six_numbers>
    0x400ee2 <phase_2+25>:  mov    -0x20(%rbp),%eax       // From the code this looks like an array. Load its first element.
    0x400ee5 <phase_2+28>:  test   %eax,%eax              // bitwise and that sets the flags.
    0x400ee7 <phase_2+30>:  jns    0x400eee <phase_2+37>  // Jump not signed (jump if positive), so we can deduce Rule 1: First number is positive!
    0x400ee9 <phase_2+32>:  callq  0x401983 <explode_bomb> // Explode!
    0x400eee <phase_2+37>:  movl   $0x1,-0x4(%rbp)         // -0x4(%rbp) looks like a counter that starts at one so I'll call it `int i = 0;`
    0x400ef5 <phase_2+44>:  jmp    0x400f1f <phase_2+86>   // Goto loop condition!
    0x400ef7 <phase_2+46>:  mov    -0x4(%rbp),%eax         // Loop body:
    0x400efa <phase_2+49>:  cltq   // Extend sign for %eax (converts %eax [int32] to %rax [int64])
    0x400efc <phase_2+51>:  mov    -0x20(%rbp,%rax,4),%edx // Our read values are in an array located at -0x20(%rbp) I'll call it array from now on. So this line ends up being %edx = array[i]
    0x400f00 <phase_2+55>:  mov    -0x4(%rbp),%eax         // reset i back to it's last value...
    0x400f03 <phase_2+58>:  sub    $0x1,%eax               // Subtract 1 from i (are we checking our values backwards?)
    0x400f06 <phase_2+61>:  cltq
    0x400f08 <phase_2+63>:  mov    -0x20(%rbp,%rax,4),%eax // Load array[i] into %eax
    0x400f0c <phase_2+67>:  add    -0x4(%rbp),%eax         // Add i to this value? Nice trick...
    0x400f0f <phase_2+70>:  add    $0x1,%eax
    0x400f12 <phase_2+73>:  cmp    %eax,%edx
    0x400f14 <phase_2+75>:  je     0x400f1b <phase_2+82>
    0x400f16 <phase_2+77>:  callq  0x401983 <explode_bomb>
    0x400f1b <phase_2+82>:  addl   $0x1,-0x4(%rbp)
    0x400f1f <phase_2+86>:  cmpl   $0x5,-0x4(%rbp)         // Loop condition: Check i against 5.
    0x400f23 <phase_2+90>:  jle    0x400ef7 <phase_2+46>   // If i <= 5 goto Loop body
    0x400f25 <phase_2+92>:  leaveq
    0x400f26 <phase_2+93>:  retq