table of Contents
CS APP experiment 2, dismantling bomb
Here is the linux environment through gdb debugger carried out
Enter gdb debugging mode
An input terminal$ gdb bomb
View main function
Entry(gdb) list main
Found initialization function initialize_bomb()
, the two print
output prompt, and then followed by a input = read_line()
, we will call as a parameter input phase_1
function.
So this phase_1
should be the function of the input checking, see the compilation of the function.
phase_1 function
- Entry
(gdb) disassemble phase_1
Output follows
Dump of assembler code for function phase_1:
0x08048b80 <+0>: push %ebp
0x08048b81 <+1>: mov %esp,%ebp
0x08048b83 <+3>: sub $0x8,%esp
0x08048b86 <+6>: movl $0x8049928,0x4(%esp)
0x08048b8e <+14>: mov 0x8(%ebp),%eax
0x08048b91 <+17>: mov %eax,(%esp)
0x08048b94 <+20>: call 0x8049067 <strings_not_equal>
0x08048b99 <+25>: test %eax,%eax
0x08048b9b <+27>: je 0x8048ba2 <phase_1+34>
0x08048b9d <+29>: call 0x804962e <explode_bomb>
0x08048ba2 <+34>: leave
0x08048ba3 <+35>: ret
End of assembler dump.
- Wherein two before the current contents of registers push ebp, esp stack pointer register and the base register and the current stack address ebp modified.
Current state
栈底方向^
...
main
...
参数
旧ebp <- ebp, esp寄存器
- The third line of the stack pointer move 8 bytes
栈底方向^
...
旧ebp <- ebp
空
空 <- esp寄存器
- Mov instruction and then two, the two values are the air out of the stack into position, one of which is
0x08049928
the other is based on an offset of 8 bytes ebp stack content to the bottom of the stack direction, that is, our argumentsinput
栈底方向^
...
旧ebp <- ebp
0x8049928
0x8(%ebp) <- esp寄存器
- Then call the function
<strings_not_equal>
, so we are in the memory0x08049928
for viewing content, is the string we need to dismantle the bomb.
(gdb) x/s 0x8049928
答案是:Why make trillions when we could make... billions?
phase_2 function
- Entry
(gdb) disassemble phase_1
0x08048ba4 <+0>: push %ebp
0x08048ba5 <+1>: mov %esp,%ebp
0x08048ba7 <+3>: sub $0x28,%esp
0x08048baa <+6>: movl $0x0,-0x4(%ebp)
0x08048bb1 <+13>: lea -0x20(%ebp),%eax
0x08048bb4 <+16>: mov %eax,0x4(%esp)
0x08048bb8 <+20>: mov 0x8(%ebp),%eax
0x08048bbb <+23>: mov %eax,(%esp)
0x08048bbe <+26>: call 0x8048fd4 <read_six_numbers>
0x08048bc3 <+31>: movl $0x0,-0x8(%ebp)
0x08048bca <+38>: jmp 0x8048bf3 <phase_2+79>
0x08048bcc <+40>: mov -0x8(%ebp),%eax
0x08048bcf <+43>: mov -0x20(%ebp,%eax,4),%edx
0x08048bd3 <+47>: mov -0x8(%ebp),%eax
0x08048bd6 <+50>: add $0x3,%eax
0x08048bd9 <+53>: mov -0x20(%ebp,%eax,4),%eax
0x08048bdd <+57>: cmp %eax,%edx
0x08048bdf <+59>: je 0x8048be6 <phase_2+66>
0x08048be1 <+61>: call 0x804962e <explode_bomb>
0x08048be6 <+66>: mov -0x8(%ebp),%eax
0x08048be9 <+69>: mov -0x20(%ebp,%eax,4),%eax
0x08048bed <+73>: add %eax,-0x4(%ebp)
0x08048bf0 <+76>: incl -0x8(%ebp)
0x08048bf3 <+79>: cmpl $0x2,-0x8(%ebp)
0x08048bf7 <+83>: jle 0x8048bcc <phase_2+40>
0x08048bf9 <+85>: cmpl $0x0,-0x4(%ebp)
0x08048bfd <+89>: jne 0x8048c04 <phase_2+96>
0x08048bff <+91>: call 0x804962e <explode_bomb>
0x08048c04 <+96>: leave
0x08048c05 <+97>: ret
sub $0x28,%esp
First, the downward pointer sp vacated space 40B is 0x28, 32-bit system, a total of 10 units, for convenience called M0 ~ M9
movl $0x0,-0x4(%ebp)
No. 0h unit will then set to zero, i.e.
M0=0
lea -0x20(%ebp),%eax; mov %eax,0x4(%esp)
No. 7 address unit is assigned to No. 8 cells. That is,
M8=&M7
it can be inferred, M8 may be a pointer to an array, M7 is the first address of the array.mov 0x8(%ebp),%eax;mov %eax,(%esp);call 0x8048fd4 <read_six_numbers>
The arguments in the last unit M9, and then calls the function, read 6 digits. Exactly 10 remaining six units, consisting of an array of 6 elements, it should be placed in M6 ~ M2, where we become A0 ~ A5.
$movl 0x0,-0x8(%ebp)
Zeroing out the number 1, M1 = 0
$cmpl 0x2,-0x8(%ebp);jle 0x8048bcc <phase_2+40>
M1 and the second comparator, the loop condition is less than or equal
mov -0x8(%ebp),%eax; mov -0x20(%ebp,%eax,4),%edx
The value ebp-20 + 4 * M1 into edx, in fact, edx = A [M1]
-0x8(%ebp),%eax; add $0x3,%eax; mov -0x20(%ebp,%eax,4),%eax
eax=A[M1+3]
cmp %eax,%edx; je 0x8048be6 <phase_2+66>; call 0x804962e <explode_bomb>
Compare eax and edx, if not equal this call exploed_bomb
mov -0x8(%ebp),%eax; mov -0x20(%ebp,%eax,4),%eax; add %eax,-0x4(%ebp); incl -0x8(%ebp)
The A [M1] is written M0, M1 ++
By inference, the original function as follows
void phase_2(char* input){
int result = 0;
int a[6];
input >> a;
for(int i=0;i<=2;i++){
if (a[i]!=a[i+3])
bomb();
result += a[i];
}
if(reuslt == 0)
bomb()
}
So the answer is an array of six elements, a [i], and to a [i + 3] the same, and the sum (a [0], a [1], a [2])! = 0 can be. As
1 2 3 1 2 3
or1 1 1 1 1 1
phase_3 function
Dump of assembler code for function phase_3:
0x08048c06 <+0>: push %ebp
0x08048c07 <+1>: mov %esp,%ebp
0x08048c09 <+3>: sub $0x28,%esp
0x08048c0c <+6>: movl $0x0,-0x8(%ebp)
0x08048c13 <+13>: movl $0x0,-0x4(%ebp)
0x08048c1a <+20>: lea -0x10(%ebp),%eax
0x08048c1d <+23>: mov %eax,0xc(%esp)
0x08048c21 <+27>: lea -0xc(%ebp),%eax
0x08048c24 <+30>: mov %eax,0x8(%esp)
0x08048c28 <+34>: movl $0x804995b,0x4(%esp)
0x08048c30 <+42>: mov 0x8(%ebp),%eax
0x08048c33 <+45>: mov %eax,(%esp)
0x08048c36 <+48>: call 0x8048868 <sscanf@plt>
0x08048c3b <+53>: mov %eax,-0x4(%ebp)
0x08048c3e <+56>: cmpl $0x1,-0x4(%ebp)
0x08048c42 <+60>: jg 0x8048c49 <phase_3+67>
0x08048c44 <+62>: call 0x804962e <explode_bomb>
0x08048c49 <+67>: mov -0xc(%ebp),%eax
0x08048c4c <+70>: mov %eax,-0x14(%ebp)
0x08048c4f <+73>: cmpl $0x7,-0x14(%ebp)
0x08048c53 <+77>: ja 0x8048c98 <phase_3+146>
0x08048c55 <+79>: mov -0x14(%ebp),%edx
0x08048c58 <+82>: mov 0x8049964(,%edx,4),%eax
0x08048c5f <+89>: jmp *%eax
0x08048c61 <+91>: addl $0x2cc,-0x8(%ebp)
0x08048c68 <+98>: subl $0x3a9,-0x8(%ebp)
0x08048c6f <+105>: addl $0x12f,-0x8(%ebp)
0x08048c76 <+112>: subl $0xcb,-0x8(%ebp)
0x08048c7d <+119>: addl $0x5d,-0x8(%ebp)
0x08048c81 <+123>: subl $0x2f4,-0x8(%ebp)
0x08048c88 <+130>: addl $0x2f4,-0x8(%ebp)
0x08048c8f <+137>: subl $0x207,-0x8(%ebp)
0x08048c96 <+144>: jmp 0x8048c9d <phase_3+151>
0x08048c98 <+146>: call 0x804962e <explode_bomb>
0x08048c9d <+151>: mov -0xc(%ebp),%eax
0x08048ca0 <+154>: cmp $0x5,%eax
0x08048ca3 <+157>: jg 0x8048cad <phase_3+167>
0x08048ca5 <+159>: mov -0x10(%ebp),%eax
0x08048ca8 <+162>: cmp %eax,-0x8(%ebp)
0x08048cab <+165>: je 0x8048cb2 <phase_3+172>
0x08048cad <+167>: call 0x804962e <explode_bomb>
0x08048cb2 <+172>: leave
0x08048cb3 <+173>: ret
End of assembler dump.
0x08048c06 ~ 0x08048c36
Were as follows, the application 10 words (4B / word) space
M0=0, M1=0, M6=&M3, M7=&M2,M8=0x804995b, M9=%ebp+8
(still from ebp-0x4 to ebp-0x28, each as a unit 4B), and then calls the functionsscanf
.Our convention where M9 is input, then the unknown M8, M7, M2 as a parameter to pass a pointer value into M2, M3, since the parameters of the stack in reverse order.
We check the contents M8 (0x804995b) of
It can be found, which is stored character string "% d% d"
Which tells us two digital inputs and two digital transfer is achieved by precisely two pointers.
0x08048c3b~0x08048c44
On the
sscanf
results of the check to see if greater than 1, otherwise the call bomb ()0x08048c49~0x08048c53
Num1 to check requires not more than 7.
0x08048c55~0x08048c5f
An unconditional jump statement to jump (num1 * 4 + 0x8049964), attention outside
*
, the branch destination is notnum1*4+0x8049964
, but the value of the address in the memory, since the current range is not more than 7 num1, little Big0x08048c61~0x08048c96
This part should be on a jump statement to jump position, namely M1 plus or minus a certain number.
0x08048c9d~0x08048ca3
Num1 and then check for required no more than 5, once again reduced the scope herein num1
0x08048ca5~0x08048cab
And num2 compared to M1, equal requirements
Therefore, it should be num2 calculation result of M1, while the value num1 is less than or equal to 5, we can take 5, num2 calculated position -519
phase_4 function
Dump of assembler code for function phase_4:
0x08048ce3 <+0>: push %ebp
0x08048ce4 <+1>: mov %esp,%ebp
0x08048ce6 <+3>: sub $0x28,%esp
0x08048ce9 <+6>: lea -0xc(%ebp),%eax
0x08048cec <+9>: mov %eax,0x8(%esp)
0x08048cf0 <+13>: movl $0x8049984,0x4(%esp)
0x08048cf8 <+21>: mov 0x8(%ebp),%eax
0x08048cfb <+24>: mov %eax,(%esp)
0x08048cfe <+27>: call 0x8048868 <sscanf@plt>
0x08048d03 <+32>: mov %eax,-0x4(%ebp)
0x08048d06 <+35>: cmpl $0x1,-0x4(%ebp)
0x08048d0a <+39>: jne 0x8048d13 <phase_4+48>
0x08048d0c <+41>: mov -0xc(%ebp),%eax
0x08048d0f <+44>: test %eax,%eax
0x08048d11 <+46>: jg 0x8048d18 <phase_4+53>
0x08048d13 <+48>: call 0x804962e <explode_bomb>
0x08048d18 <+53>: mov -0xc(%ebp),%eax
0x08048d1b <+56>: mov %eax,(%esp)
0x08048d1e <+59>: call 0x8048cb4 <func4>
0x08048d23 <+64>: mov %eax,-0x8(%ebp)
0x08048d26 <+67>: cmpl $0x78,-0x8(%ebp)
0x08048d2a <+71>: je 0x8048d31 <phase_4+78>
0x08048d2c <+73>: call 0x804962e <explode_bomb>
0x08048d31 <+78>: leave
0x08048d32 <+79>: ret
End of assembler dump.
0x08048ce3~0x08048cfe
Performed as follows: the application stack space 4B * 10, and the M2 (
ebp-0xc
) writes the address M7 (esp+0x8
), the0x8049984
write M8, pass incoming parameters into the upper M9, then call<sscanf@plt>
We
0x8049984
check, which is a string%d
, an integer with visible read write pointer M2 M70x08048d03~0x08048d06
Of
sscanf
return value check it requires only a numerical value input0x08048d0c~0x08048d11
Checking the number of the input request is greater than 0
0x08048d18~0x08048d1e
As the input parameters, calling func4
Check func4
Can be found, func4 is a recursive factorial function.
0x08048d23~0x08048d2a
The return value into func4 M1, M1, and 0x78 is compared to the required equal, i.e. in claim M1 == 120
We just need to find the factorial of the number of 120-bit result of that answer: 5
phase_5
(gdb) disassemble phase_5
Dump of assembler code for function phase_5:
0x08048d33 <+0>: push %ebp
0x08048d34 <+1>: mov %esp,%ebp
0x08048d36 <+3>: sub $0x18,%esp
0x08048d39 <+6>: mov 0x8(%ebp),%eax
0x08048d3c <+9>: mov %eax,(%esp)
0x08048d3f <+12>: call 0x804903d <string_length>
0x08048d44 <+17>: mov %eax,-0x4(%ebp)
0x08048d47 <+20>: cmpl $0x6,-0x4(%ebp)
0x08048d4b <+24>: je 0x8048d52 <phase_5+31>
0x08048d4d <+26>: call 0x804962e <explode_bomb>
0x08048d52 <+31>: movl $0x0,-0x8(%ebp)
0x08048d59 <+38>: movl $0x0,-0xc(%ebp)
0x08048d60 <+45>: jmp 0x8048d7e <phase_5+75>
0x08048d62 <+47>: mov -0xc(%ebp),%eax
0x08048d65 <+50>: add 0x8(%ebp),%eax
0x08048d68 <+53>: movzbl (%eax),%eax
0x08048d6b <+56>: movsbl %al,%eax
0x08048d6e <+59>: and $0xf,%eax
0x08048d71 <+62>: mov 0x804a5c0(,%eax,4),%eax
0x08048d78 <+69>: add %eax,-0x8(%ebp)
0x08048d7b <+72>: incl -0xc(%ebp)
0x08048d7e <+75>: cmpl $0x5,-0xc(%ebp)
0x08048d82 <+79>: jle 0x8048d62 <phase_5+47>
0x08048d84 <+81>: cmpl $0x49,-0x8(%ebp)
0x08048d88 <+85>: je 0x8048d8f <phase_5+92>
0x08048d8a <+87>: call 0x804962e <explode_bomb>
0x08048d8f <+92>: leave
0x08048d90 <+93>: ret
End of assembler dump.
0x08048d33~0x08048d44
Application stack space 4B * 6, the function is called as an input
<string_length>
, and writes the results M0, i.e.,M0=length(input)
0x08048d47~0x08048d4d
Checking the input length, length in claim 6.
0x08048d52~0x08048d60
The M1, M2 assigned to 0, jump
0x08048d62~0x08048d6e
The (input + M2) 0 expanded into the eax, eax then removed in the corresponding address value, because the input string is in fact, which is equivalent to
eax=input[M2]
, and taken after the eight eax, sign extension write back, and finally taken the last four digits. Here is an ascii code as input, so the range of 0 to 127 0 sign extension must be extended. The final series of operations which is equivalent to the four inputs take ascii code value for each character.0x08048d71~0x08048d78
Taken based on
0x804a5c0
the content of the shift memory, the accumulated into M10x08048d7b~0x08048d82
M2 increment, is less than or equal to 5 is determined, continue to cycle
0x08048d84
0x49 bit accumulation results in claim
Check the
0x804a5c0
contentsCorresponding values: 2, 10, 6, 1, 12, 16, 9, 3, 4, 7, 14, 5, 11, 8, 15,
If we take the six, and make equal 0x49
Here, I remove the standard number of 2,5,5,5,5,7 6, as long as the four conditions can be satisfied, so that the string can take
255557
phase_6
(gdb) disassemble phase_6
Dump of assembler code for function phase_6:
0x08048e25 <+0>: push %ebp
0x08048e26 <+1>: mov %esp,%ebp
0x08048e28 <+3>: sub $0x18,%esp
0x08048e2b <+6>: movl $0x804a660,-0x8(%ebp)
0x08048e32 <+13>: mov 0x8(%ebp),%eax
0x08048e35 <+16>: mov %eax,(%esp)
0x08048e38 <+19>: call 0x8048858 <atoi@plt>
0x08048e3d <+24>: mov %eax,-0xc(%ebp)
0x08048e40 <+27>: mov -0x8(%ebp),%eax
0x08048e43 <+30>: mov %eax,(%esp)
0x08048e46 <+33>: call 0x8048d91 <fun6>
0x08048e4b <+38>: mov %eax,-0x8(%ebp)
0x08048e4e <+41>: mov -0x8(%ebp),%eax
0x08048e51 <+44>: mov %eax,-0x4(%ebp)
0x08048e54 <+47>: movl $0x1,-0x10(%ebp)
0x08048e5b <+54>: jmp 0x8048e69 <phase_6+68>
0x08048e5d <+56>: mov -0x4(%ebp),%eax
0x08048e60 <+59>: mov 0x8(%eax),%eax
0x08048e63 <+62>: mov %eax,-0x4(%ebp)
0x08048e66 <+65>: incl -0x10(%ebp)
0x08048e69 <+68>: cmpl $0x4,-0x10(%ebp)
0x08048e6d <+72>: jne 0x8048e5d <phase_6+56>
0x08048e6f <+74>: mov -0x4(%ebp),%eax
0x08048e72 <+77>: mov (%eax),%eax
0x08048e74 <+79>: cmp -0xc(%ebp),%eax
0x08048e77 <+82>: je 0x8048e7e <phase_6+89>
0x08048e79 <+84>: call 0x804962e <explode_bomb>
0x08048e7e <+89>: leave
0x08048e7f <+90>: ret
End of assembler dump.
0x08048e25~0x08048e3d
Application stack space 4B * 6 will
0x804a660
put M1, the input invoked as an argument<atoi@plt>
and returns the result is written M20x08048e40~0x08048e4b
The M1 as an argument, call fun6, will return to write the result back M1
emmm, fun6 not look
To be continued, ha ha ha