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)
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