Bomb(32bit)
Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the VICTIM) explicit permission to use this bomb (the BOMB).
This is a time limited license, which expires on the death of the VICTIM.
The PERPETRATOR takes no responsibility for damage, frustration, insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other harm to the VICTIM.
Unless the PERPETRATOR wants to take credit, that is.
The VICTIM may not distribute this bomb source code to any enemies of the PERPETRATOR. No VICTIM may debug, reverse-engineer, run “strings” on, decompile, decrypt, or use any other technique to gain knowledge of and defuse the BOMB.
BOMB proof clothing may not be worn when handling this program.
The PERPETRATOR will not apologize for the PERPETRATOR’s poor sense of humor.
This license is null and void where the BOMB is prohibited by law.
The next image is the changes in stack frame during procedure call
![image-20201117000604340](https://i.loli.net/2020/11/19/QAlNYEPFa7pJvHV.png)
The image blow is the entry parameters(入口参数) of the stack frame
![image-20201117000852848](https://i.loli.net/2020/11/19/KbdQgz1iupyLqhA.png)
phase_0
Stage description: This stage requires the input of a byte sequence that matches a specific string built in the program
Main asm
80492f1: e8 90 0a 00 00 call 8049d86 <read_line>
80492f6: 89 45 f4 mov %eax,-0xc(%ebp)
80492f9: 83 ec 0c sub $0xc,%esp
80492fc: ff 75 f4 pushl -0xc(%ebp)
;这里是输入的字符串,作为入口参数传递过去
80492ff: e8 50 01 00 00 call 8049454 <phase_0>
8049304: 83 c4 10 add $0x10,%esp
8049307: 85 c0 test %eax,%eax
8049309: 74 15 je 8049320 <main+0xee>
804930b: e8 e2 0b 00 00 call 8049ef2 <phase_defused>
8049310: 83 ec 0c sub $0xc,%esp
8049313: 68 ac a0 04 08 push $0x804a0ac
8049318: e8 73 fd ff ff call 8049090 <puts@plt>
804931d: 83 c4 10 add $0x10,%esp
Phase_0
08049454 <phase_0>:
8049454: 55 push %ebp
8049455: 89 e5 mov %esp,%ebp
8049457: 83 ec 08 sub $0x8,%esp
804945a: 83 ec 08 sub $0x8,%esp
804945d: 68 e0 a1 04 08 push $0x804a1e0
8049462: ff 75 08 pushl 0x8(%ebp) ;0x0804c260
8049465: e8 f7 07 00 00 call 8049c61 <strings_not_equal>;return address
804946a: 83 c4 10 add $0x10,%esp
804946d: 85 c0 test %eax,%eax
804946f: 74 0c je 804947d <phase_0+0x29>
8049471: e8 53 0a 00 00 call 8049ec9 <explode_bomb>
8049476: b8 00 00 00 00 mov $0x0,%eax
804947b: eb 05 jmp 8049482 <phase_0+0x2e>
804947d: b8 01 00 00 00 mov $0x1,%eax
8049482: c9 leave
8049483: c3 ret
此时 GDB
调试该程序,进入 phase_0
函数内其 ebp
,esp
的如下
(gdb) i r esp ebp
esp 0xffffcfd0 0xffffcfd0
ebp 0xffffcfe8 0xffffcfe8
Here the stack frame is~~
![image-20201119170650385](https://i.loli.net/2020/11/19/C714i6AUjfgLs8Q.png)
08049454 <phase_0>:
804945d: 68 e0 a1 04 08 push $0x804a1e0
8049462: ff 75 08 pushl 0x8(%ebp) ;0x0804c260
The 0xffffcfd4
stored the 0x0804a1e0
where stored the specific string.
The 0xffffcfd0
stored the 0x0804c260
where stored the input string.
And then enter the string_not_equal
function, here is the asm of this procedure call
String_not_equal
8049c61 <strings_not_equal>:
8049c61: 55 push %ebp
8049c62: 89 e5 mov %esp,%ebp
8049c64: 53 push %ebx
8049c65: 83 ec 10 sub $0x10,%esp
8049c68: ff 75 08 pushl 0x8(%ebp);input string
8049c6b: e8 c5 ff ff ff call 8049c35 <string_length>
8049c70: 83 c4 04 add $0x4,%esp
8049c73: 89 c3 mov %eax,%ebx
8049c75: ff 75 0c pushl 0xc(%ebp);specific string
8049c78: e8 b8 ff ff ff call 8049c35 <string_length>
8049c7d: 83 c4 04 add $0x4,%esp
8049c80: 39 c3 cmp %eax,%ebx;length equal?
8049c82: 74 07 je 8049c8b <strings_not_equal+0x2a>
8049c84: b8 01 00 00 00 mov $0x1,%eax
8049c89: eb 3c jmp 8049cc7 <strings_not_equal+0x66>
8049c8b: 8b 45 08 mov 0x8(%ebp),%eax
8049c8e: 89 45 f8 mov %eax,-0x8(%ebp);input string
8049c91: 8b 45 0c mov 0xc(%ebp),%eax
8049c94: 89 45 f4 mov %eax,-0xc(%ebp);specific string
8049c97: eb 1f jmp 8049cb8 <strings_not_equal+0x57>
8049c99: 8b 45 f8 mov -0x8(%ebp),%eax
8049c9c: 0f b6 10 movzbl (%eax),%edx
8049c9f: 8b 45 f4 mov -0xc(%ebp),%eax
8049ca2: 0f b6 00 movzbl (%eax),%eax
8049ca5: 38 c2 cmp %al,%dl
8049ca7: 74 07 je 8049cb0 <strings_not_equal+0x4f>
8049ca9: b8 01 00 00 00 mov $0x1,%eax
8049cae: eb 17 jmp 8049cc7 <strings_not_equal+0x66>
8049cb0: 83 45 f8 01 addl $0x1,-0x8(%ebp)
8049cb4: 83 45 f4 01 addl $0x1,-0xc(%ebp)
8049cb8: 8b 45 f8 mov -0x8(%ebp),%eax
8049cbb: 0f b6 00 movzbl (%eax),%eax
8049cbe: 84 c0 test %al,%al
8049cc0: 75 d7 jne 8049c99 <strings_not_equal+0x38>
8049cc2: b8 00 00 00 00 mov $0x0,%eax
8049cc7: 8b 5d fc mov -0x4(%ebp),%ebx
8049cca: c9 leave
8049ccb: c3 ret
Break point in the 0x8049c6b
which call 8049c35 <string_length>. Here is the stack frame in this time. And now the entry parameters is the input string address 0x0804c260
![image-20201119170725833](https://i.loli.net/2020/11/19/sTHKk9tY2EzLfDr.png)
So now we enter the string_length
function~~
String_length
08049c35 <string_length>:
8049c35: 55 push %ebp
8049c36: 89 e5 mov %esp,%ebp
8049c38: 83 ec 10 sub $0x10,%esp
8049c3b: 8b 45 08 mov 0x8(%ebp),%eax;entry parameter
8049c3e: 89 45 f8 mov %eax,-0x8(%ebp);input string add
8049c41: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp);Record times
8049c48: eb 08 jmp 8049c52 <string_length+0x1d>
8049c4a: 83 45 f8 01 addl $0x1,-0x8(%ebp)
8049c4e: 83 45 fc 01 addl $0x1,-0x4(%ebp)
8049c52: 8b 45 f8 mov -0x8(%ebp),%eax
8049c55: 0f b6 00 movzbl (%eax),%eax
8049c58: 84 c0 test %al,%al
8049c5a: 75 ee jne 8049c4a <string_length+0x15>
8049c5c: 8b 45 fc mov -0x4(%ebp),%eax
8049c5f: c9 leave
8049c60: c3 ret
Always the first step of procedure call is push %ebp
, this make the esp-=4
to get a new stack frame storage unit. And then execute mov %esp, %ebp
, make ebp->(esp->)
![image-20201119170749139](https://i.loli.net/2020/11/19/Bf6RcaYD2gPiqb5.png)
M[0x0804c260]
is the ASCII for the input string. this function get one BYTE once, if this BYTE is not zero, that is mean not end, so inc the num and loop again. We can use the x/40xw
to read 40 Word
start from 0x0804c260
. It can be found that it happened to be the string we entered.
The same we can get the specific string from the address 0x0804a1e0
as followers:
0x804a1e0: 0x65742041 0x6c207478 0x20656e69 0x61207369
0x804a1f0: 0x71657320 0x636e6575 0x666f2065 0x43534120
0x804a200: 0x63204949 0x61726168 0x72657463 0x25002e73;Little endian 73 2e 00
Keep it simple we can use (gdb)x/1s 0x0804a1e0
to display the specific string which is A text line is a sequence of ASCII characters.
phase_1
Stage description: We don’t anything about this stage, so we have to study step and step in assembly code
Main
Always in Main procedure call. It read a input string first and deliver it to phase_1 function as the entry parameters. And the %eax
stored the return value of the phase_1 function, then if %eax
equals 1
, defused the BOMB!
804931d: 83 c4 10 add $0x10,%esp
8049320: e8 61 0a 00 00 call 8049d86 <read_line>
8049325: 89 45 f4 mov %eax,-0xc(%ebp)
8049328: 83 ec 0c sub $0xc,%esp
804932b: ff 75 f4 pushl -0xc(%ebp)
804932e: e8 51 01 00 00 call 8049484 <phase_1>
8049333: 83 c4 10 add $0x10,%esp
8049336: 85 c0 test %eax,%eax
8049338: 74 15 je 804934f <main+0x11d>
804933a: e8 b3 0b 00 00 call 8049ef2 <phase_defused>
phase_1
And now let’s enter the phase_1 procedure call to Check it out.
08049484 <phase_1>:
8049484: 55 push %ebp
8049485: 89 e5 mov %esp,%ebp
8049487: 83 ec 28 sub $0x28,%esp
804948a: c7 45 f4 a1 84 76 09 movl $0x97684a1,-0xc(%ebp)
8049491: db 45 f4 fildl -0xc(%ebp)
8049494: dd 5d e8 fstpl -0x18(%ebp)
;Prepare for the function call below
8049497: 8d 45 e0 lea -0x20(%ebp),%eax
804949a: 50 push %eax
804949b: 8d 45 e4 lea -0x1c(%ebp),%eax
804949e: 50 push %eax
804949f: 68 0f a2 04 08 push $0x804a20f;the
80494a4: ff 75 08 pushl 0x8(%ebp);the input string
80494a7: e8 24 fc ff ff call 80490d0 <__isoc99_sscanf@plt>
If you want to create a stack frame, you should push %ebp(old) and make the ebp point to esp.
The core of this assembly code is fildl
and fstpl
. fildl
mean (double)int
which convert int(32bit)
to double(80bit)
and stored in ST(0)
. fstpl
mean pop the ST(0)(80bit)
and stored in -0x18(%ebp)(64bit)
. we notice that it may cause accuracy loss(精度损失).
(gdb) x/4xw $ebp-0x18
0xffffd000: 0x42000000 0x41a2ed09 0xffffd028 0x097684a1
(gdb) x/fg $ebp-0x18
0xffffd000: 158762145
(gdb) x/dw $ebp-0xc
0xffffd00c: 158762145
It turns out that there is no loss of precision(精确度) in this question 😃
Ok, now we must be find What format string do we need. Next 4 instruct stored 2 address in stack frame. And then push $0x804a20f
, what is this mean?🧐 Maybe we can found a clue in the process of using gdb.
(gdb) x/xw 0x0804a20f
0x804a20f: 0x25206425
(gdb) x/s 0x0804a20f
0x804a20f: "%d %d"
(gdb) x/s 0x0804c2b0
0x804c2b0 <input_strings+80>: "9 8"
Oh! Oh! Oh! Get it. The format of the input string. And %ebp+8
usually is the entry parameters of this procedure call. That is our input string.
The next instruct is call 80490d0 __isoc99_sscanf@plt
. The sscanf is the C standard library functions.
int sscanf(const char *str, const char *format, ...)
return the number of successful matches and assignments
The first entry parameter is char *str
, corresponding to the “9 8” we input. And the second entry parameter is char *format
, corresponding to the “%d %d”.
- we can get the
%eax
which is the return value must be 2. - we can konw
-0x1c(%ebp)
and-0x20(%ebp)
is the address which stored the binary number(convert from the input string)
Now we can move to the next step.
80494ac: 83 c4 10 add $0x10,%esp
80494af: 83 f8 02 cmp $0x2,%eax
80494b2: 74 0c je 80494c0 <phase_1+0x3c>
80494b4: e8 10 0a 00 00 call 8049ec9 <explode_bomb>
80494b9: b8 00 00 00 00 mov $0x0,%eax
80494be: eb 2c jmp 80494ec <phase_1+0x68>
80494c0: 8d 45 e8 lea -0x18(%ebp),%eax
80494c3: 8b 10 mov (%eax),%edx
80494c5: 8b 45 e4 mov -0x1c(%ebp),%eax
80494c8: 39 c2 cmp %eax,%edx
80494ca: 75 0f jne 80494db <phase_1+0x57>
80494cc: 8d 45 e8 lea -0x18(%ebp),%eax
80494cf: 83 c0 04 add $0x4,%eax
80494d2: 8b 10 mov (%eax),%edx
80494d4: 8b 45 e0 mov -0x20(%ebp),%eax
80494d7: 39 c2 cmp %eax,%edx
80494d9: 74 0c je 80494e7 <phase_1+0x63>
80494db: e8 e9 09 00 00 call 8049ec9 <explode_bomb>
80494e0: b8 00 00 00 00 mov $0x0,%eax
80494e5: eb 05 jmp 80494ec <phase_1+0x68>
80494e7: b8 01 00 00 00 mov $0x1,%eax
80494ec: c9 leave
80494ed: c3 ret
If the return value of the sccanf
is not 2, it will explode the BOMB! Or je
to 80494c0
(gdb) x/10xw $esp
0xffffcff0: 0x0804a3b7 0xf7fb0000 0x00000008 0x00000009
0xffffd000: 0x42000000 0x41a2ed09 0xffffd028 0x097684a1
(gdb) i r ebp esp
ebp 0xffffd018 0xffffd018
esp 0xffffcff0 0xffffcff0
The first input number stored in 0xffffcffc
and the second input number stroed in 0xffffcff8
80494c0: 8d 45 e8 lea -0x18(%ebp),%eax
80494c3: 8b 10 mov (%eax),%edx
80494c5: 8b 45 e4 mov -0x1c(%ebp),%eax
80494c8: 39 c2 cmp %eax,%edx
Determine whether M[0xffffcffc]
and M[0xffffd000]
are equal.
And next Determine whether M[0xffffcff8]
and M[0xffffd004]
are equal
So the first number we input must be 0x42000000 and the next is 0x41a2ed09. Decimal is 1107296256 1101196553
Good job!🤪