1 准备
1.1 安装gdb-peda
gdb-peda是gdb的插件,加强gdb调试能力。
安装方法如下:
1 | gdb-peda$ set disassembly-flavor att$ git clone htgdb-peda$ set disassembly-flavor atttps://github.com/longld/peda.git ~/peda |
安装插件后汇编指令格式改为了intel模式,不太习惯,改变为AT&T格式:
1 | # 改为AT&T格式 |
参考:gdb-peda安装
1.2 gdb&peda使用
1 | # 载入可执行程序 |
1.3 计组知识
汇编格式:
- Intel格式:目的操作数在左,MASM采用
- AT&T格式:目的操作数在右,objdump和gcc默认格式
栈:
- 先进后出
- 从高地址向低地址增长
- ESP指向栈顶
- EBP指向栈底
大小端模式:
- 大端(Big-Endian):高字节存低地址,低字节存低高地址
- 小端(Little-Endian):低字节存低地址,高字节存高地址
常见指令:
push
:R[sp] ← R[sp] - 2 或者 R[esp] ← R[esp] - 4,然后将一个字或双字从指定寄存器送到SP或者ESP指示的单元;pop
:然后将一个字或双字从SP或者ESP指示的单元送到指定寄存器,再执行R[sp] ← R[sp] + 2 或者 R[esp] ← R[esp] + 4call <func_addr>
:先push EIP(当前指令的第一条指令地址),再执行jmp <func_addr>ret
:pop EIPleave
:先执行mov %ebp %esp,再pop %ebp
1.4 lab概览
通过IDA打开bomb文件,找到主函数main,发现需要需要进行六次输入,对应phase_1到phase_6函数,每次输入需要躲开explode_bomb()函数,否则拆炸弹失败。
2 phase_1
2.1 解析
IDA查看phase_1函数伪代码:
1 | int __cdecl phase_1(int a1) |
gdb查看phase_1函数汇编代码:
1 | gdb-peda$ disassemble phase_1 |
2.2 思路
看伪代码直接得出答案,输入需要与给定字符串一致。
如果不看伪代码,使用gdb动态调试则:
-
载入bomb:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20$ gdb bomb
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
warning: build/bdist.linux-i686/wheel/peda/peda.py: No such file or directory
Reading symbols from bomb...done.
gdb-peda$ -
在main函数处打断点,并执行到该断点:
1
2
3gdb-peda$ b main
Breakpoint 1 at 0x14cd: file bomb.c, line 37.
gdb-peda$ r -
在phase_1函数处打断点,并执行到该断点:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15gdb-peda$ b phase_1
Breakpoint 2 at 0x401662
gdb-peda$ c
Continuing.
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
[-------------------------------------code-------------------------------------]
0x401651 <main+388>: call 0x401300 <__printf_chk@plt>
0x401656 <main+393>: mov DWORD PTR [esp],0x8
0x40165d <main+400>: call 0x4012a0 <exit@plt>
=> 0x401662 <phase_1>: endbr32
0x401666 <phase_1+4>: push ebp
0x401667 <phase_1+5>: mov ebp,esp
0x401669 <phase_1+7>: push ebx
0x40166a <phase_1+8>: sub esp,0xc -
执行8步到
0x0040167e <+28>: push eax
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33gdb-peda$ n 8
[----------------------------------registers-----------------------------------]
EAX: 0x403144 ("And they have no disregard for human life.")
EBX: 0x404f64 --> 0x4e6c ('lN')
ECX: 0x2b ('+')
EDX: 0x1
ESI: 0xbffff574 --> 0xbffff6bf ("/home/liuzhenlong/lab_debug/bomb_162020203/bomb95/bomb")
EDI: 0xb7fbc000 --> 0x1d9d6c
EBP: 0xbffff498 --> 0xbffff4c8 --> 0x0
ESP: 0xbffff488 --> 0xb7e13cb9 (<__new_exitfn+9>: add ebx,0x1a8347)
EIP: 0x40167e (<phase_1+28>: push eax)
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x40166d <phase_1+11>: call 0x4013d0 <__x86.get_pc_thunk.bx>
0x401672 <phase_1+16>: add ebx,0x38f2
0x401678 <phase_1+22>: lea eax,[ebx-0x1e20]
=> 0x40167e <phase_1+28>: push eax
0x40167f <phase_1+29>: push DWORD PTR [ebp+0x8]
0x401682 <phase_1+32>: call 0x401bdf <strings_not_equal>
0x401687 <phase_1+37>: add esp,0x10
0x40168a <phase_1+40>: test eax,eax
[------------------------------------stack-------------------------------------]
0000| 0xbffff488 --> 0xb7e13cb9 (<__new_exitfn+9>: add ebx,0x1a8347)
0004| 0xbffff48c --> 0x404f64 --> 0x4e6c ('lN')
0008| 0xbffff490 --> 0xbffff574 --> 0xbffff6bf ("/home/liuzhenlong/lab_debug/bomb_162020203/bomb95/bomb")
0012| 0xbffff494 --> 0x404f64 --> 0x4e6c ('lN')
0016| 0xbffff498 --> 0xbffff4c8 --> 0x0
0020| 0xbffff49c --> 0x40155a (<main+141>: call 0x40203c <phase_defused>)
0024| 0xbffff4a0 --> 0x405760 ("And they have no disregard for human life.")
0028| 0xbffff4a4 --> 0x404f64 --> 0x4e6c ('lN')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0040167e in phase_1 ()此时可以看到EAX中所指向的字符串,也就是答案。
答案:
1 | And they have no disregard for human life. |
3 phase_2
3.1 解析
IDA查看phase_2函数伪代码:
1 | int __cdecl read_six_numbers(int a1, int a2) |
gdb查看phase_2函数汇编代码:
1 | gdb-peda$ disassemble phase_2 |
3.2 思路
从伪代码看:需要输入6个数字,而且第一个数字为1,后面的数字是前面的两倍。
答案:
1 | 1 2 4 8 16 32 |
4 phase_3
4.1 解析
IDA查看phase_3函数伪代码:
1 | void __cdecl phase_3(int a1) |
gdb查看phase_3函数汇编代码:
1 | gdb-peda$ disassemble phase_3 |
4.2 思路
从伪代码看,phase_3需要输入两个整数,第一个整数需要小于等于7,然后跳转到EDX,其他信息无法获取,需要gdb调试。
假设第一个数为0,进行动态调试:
-
运行到
<+79>
,此时EDX=0x401771 (<phase_3+96>: mov eax,0x398
) -
<+86>
表示跳转到EDX对应的指令地址,也就是<+96>
-
<+126>
和<+130>
表示第一个数还需要小于等于5:1
20x0040178f <+126>: cmp DWORD PTR [ebp-0x14],0x5
0x00401793 <+130>: jg 0x40179a <phase_3+137> -
<+132>
表示第二个数需要等于EAX,此时的EAX为0x42f:1
2
3
4gdb-peda$ p $eax
$24 = 0x42f
gdb-peda$ d $24
No breakpoint number 1071. -
此时可以得到一组答案
0 1071
,答案不唯一。
答案:
1 | 0 1071 |
5 phase_4
5.1 解析
IDA查看phase_4函数伪代码:
1 | int __cdecl func4(int a1, int a2) |
gdb查看phase_4函数汇编代码:
1 | gdb-peda$ disassemble phase_4 |
5.2 思路
从伪代码来看,phase_4需要输入两个整数,第二个可能是2、3、4,第一个需要满足一定的条件。
-
假设第二个为2,进入gdb动态调试;
-
执行到
<+96>
,第一个值需要等于此时的EAX,查看EAX的值:1
2
3
4gdb-peda$ p $eax
$28 = 0x18
gdb-peda$ d $28
No breakpoint number 24. -
所以其中一个答案是
24 2
答案:
1 | 24 2 |
6 phase_5
6.1 解析
IDA查看phase_5函数伪代码:
1 | _BYTE *__cdecl phase_5(_BYTE *a1) |
gdb查看phase_5函数汇编代码:
1 | gdb-peda$ disassemble phase_5 |
6.2 思路
观察伪代码发现,输入是一段长度为6的字符串,而且需要满足一定的条件。
在IDA中双击array_3066
查看该数组的值:
1 | array_3066 dd 2, 0Ah, 6, 1, 0Ch, 10h, 9, 3, 4, 7, 0Eh, 5, 0Bh, 8 |
或者在gdb中查看,运行至<+51>
:
1 | gdb-peda$ x/20x $ebx-0x1da4 |
下标可以这样组合:1 1 1 1 0 0 (也就是10+10+10+10+2+2=44,满足条件)
对应到字符串是:111100
或 AAAA@@
等。
答案:
1 | 111100 |
7 phase_6
7.1 解析
IDA查看phase_6函数伪代码:
1 | unsigned int __cdecl phase_6(int a1) |
gdb查看phase_6函数汇编代码:
1 | gdb-peda$ disassemble phase_6 |
7.2 思路
-
查看伪代码需要输入六个数字;
-
观察这部分代码块(对应汇编代码
<+47>
到<+98>
)可得,这六个数字必须从1 2 3 4 5 6
中选,而且互不相同;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16while ( 1 )
{
if ( (unsigned int)(*((_DWORD *)v14 - 1) - 1) > 5 )
explode_bomb();
if ( ++v15 > 5 )
break;
v1 = (int *)v14;
do
{
if ( *((_DWORD *)v14 - 1) == *v1 )
explode_bomb();
++v1;
}
while ( &v18 != v1 );
v14 += 4;
} -
查看这部分代码块可得,是根据输入的六个数字对node链表进行排序,node链表最后要升序排列(可以有相等的);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25for ( i = 0; i != 6; ++i )
{
v3 = *(&v16 + i);
v4 = 1;
v5 = &node1;
if ( v3 > 1 )
{
do
{
v5 = (_DWORD *)v5[2];
++v4;
}
while ( v4 != v3 );
}
*(&v18 + i) = (int)v5;
}
do
{
if ( *(_DWORD *)v6 > **(_DWORD **)(v6 + 8) )
explode_bomb();
v6 = *(_DWORD *)(v6 + 8);
--v12;
}
while ( v12 ); -
运行至
<+156> lea edx,[ebx+0x594]
,查看各个node结点的数值:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43[----------------------------------registers-----------------------------------]
EAX: 0x1
EBX: 0x404f64 --> 0x4e6c ('lN')
ECX: 0x4
EDX: 0x4054f8 --> 0x2a0
ESI: 0x1
EDI: 0x1
EBP: 0xbffff498 --> 0xbffff4c8 --> 0x0
ESP: 0xbffff430 --> 0x3
EIP: 0x4019c7 (<phase_6+162>: cmp ecx,0x1)
EFLAGS: 0x293 (CARRY parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x4019b8 <phase_6+147>: mov ecx,DWORD PTR [ebp+esi*4-0x4c]
0x4019bc <phase_6+151>: mov eax,0x1
0x4019c1 <phase_6+156>: lea edx,[ebx+0x594]
=> 0x4019c7 <phase_6+162>: cmp ecx,0x1
0x4019ca <phase_6+165>: jle 0x4019d6 <phase_6+177>
0x4019cc <phase_6+167>: mov edx,DWORD PTR [edx+0x8]
0x4019cf <phase_6+170>: add eax,0x1
0x4019d2 <phase_6+173>: cmp eax,ecx
[------------------------------------stack-------------------------------------]
0000| 0xbffff430 --> 0x3
0004| 0xbffff434 --> 0xbffff464 --> 0x405528 --> 0x133
0008| 0xbffff438 --> 0x6
0012| 0xbffff43c --> 0xbffff464 --> 0x405528 --> 0x133
0016| 0xbffff440 --> 0x4058f0 ("5 4 2 1 6 3")
0020| 0xbffff444 --> 0x50 ('P')
0024| 0xbffff448 --> 0xb7fbc5c0 --> 0xfbad2288
0028| 0xbffff44c --> 0x5
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x004019c7 in phase_6 ()
gdb-peda$ x/21x $ebx+0x594
0x4054f8 <node1>: 0x000002a0 0x00000001 0x00405504 0x0000026d
0x405508 <node2+4>: 0x00000002 0x00405510 0x000001ea 0x00000003
0x405518 <node3+8>: 0x0040551c 0x00000038 0x00000004 0x00405528
0x405528 <node5>: 0x00000133 0x00000005 0x00405080 0x00000000
0x405538: 0x00000000 0x00000000 0x00403417 0x00000000
0x405548 <host_table+8>: 0x00000000
gdb-peda$ x 0x00405080
0x405080 <node6>: 0x000000ca
gdb-peda$ x/3x 0x00405080
0x405080 <node6>: 0x000000ca 0x00000006 0x00000000注意:在IDA中查看注意截断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20.data:000054F8 public node1
.data:000054F8 node1 db 0A0h ; DATA XREF: phase_6+9C↑o
.data:000054F9 db 2
.data:000054FA db 0
.data:000054FB db 0
.data:000054FC db 1
.data:000054FD db 0
.data:000054FE db 0
.data:000054FF db 0
.data:00005500 dd offset node2
.data:00005504 public node2
.data:00005504 node2 db 6Dh ; m ; DATA XREF: .data:00005500↑o
.data:00005505 db 2
.data:00005506 db 0
.data:00005507 db 0
.data:00005508 db 2
.data:00005509 db 0
.data:0000550A db 0
.data:0000550B db 0
.data:0000550C dd offset node3可以得出:
-
node结点的结构:
1
2
3
4
5struct node {
int val;
int index;
struct node * next;
}; -
node排列:
1
|node1=0x2a0| -> |node2=0x260| -> |node3=0x1ea| -> |node4=0x038| -> |node5=0x133| -> |node6=0x0ca|
所以应输入从小到大排列序号为:4 6 5 3 2 1
-
答案:
1 | 4 6 5 3 2 1 |
8 bomblab隐藏关卡
8.1 解析
在bomb的伪代码内找到调用 secret_phase 的函数-- phase_defused ,研究phase_defused 汇编代码:首先调用 sscanf ,要求输入 %d %d %s ,而且调用strings_not_equal 函数,只有第三个输入是 DrEvil
时触发 secret_phase() 函数。
1 | unsigned int phase_defused() |
将已经解决的问题答案放到txt文件中,便于操作;找到一个输入是两个整数的阶段,这里选择了phase_4,成功触发隐藏关卡;(第三阶段无法触发,不知为何?
1 | And they have no disregard for human life. |
1 | $ ./bomb flag.txt |
secret_phase伪代码 :
1 | unsigned int secret_phase() |
fun7伪代码:
1 | int __cdecl fun7(_DWORD *a1, int a2) |
8.2 思路
-
进入 secret_phase:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44gdb-peda$ disassemble secret_phase
Dump of assembler code for function secret_phase:
0x00401a98 <+0>: endbr32
0x00401a9c <+4>: push ebp
0x00401a9d <+5>: mov ebp,esp
0x00401a9f <+7>: push esi
0x00401aa0 <+8>: push ebx
0x00401aa1 <+9>: call 0x4013d0 <__x86.get_pc_thunk.bx>
0x00401aa6 <+14>: add ebx,0x34be
0x00401aac <+20>: call 0x401f09 <read_line>
0x00401ab1 <+25>: sub esp,0x4
0x00401ab4 <+28>: push 0xa
0x00401ab6 <+30>: push 0x0
0x00401ab8 <+32>: push eax
0x00401ab9 <+33>: call 0x401340 <strtol@plt>
0x00401abe <+38>: mov esi,eax
0x00401ac0 <+40>: lea eax,[eax-0x1]
0x00401ac3 <+43>: add esp,0x10
0x00401ac6 <+46>: cmp eax,0x3e8
0x00401acb <+51>: ja 0x401b03 <secret_phase+107>
0x00401acd <+53>: sub esp,0x8
0x00401ad0 <+56>: push esi
0x00401ad1 <+57>: lea eax,[ebx+0x540]
0x00401ad7 <+63>: push eax
0x00401ad8 <+64>: call 0x401a42 <fun7>
0x00401add <+69>: add esp,0x10
0x00401ae0 <+72>: cmp eax,0x3
0x00401ae3 <+75>: jne 0x401b0a <secret_phase+114>
0x00401ae5 <+77>: sub esp,0xc
0x00401ae8 <+80>: lea eax,[ebx-0x1df4]
0x00401aee <+86>: push eax
0x00401aef <+87>: call 0x401280 <puts@plt>
0x00401af4 <+92>: call 0x40203c <phase_defused>
0x00401af9 <+97>: add esp,0x10
0x00401afc <+100>: lea esp,[ebp-0x8]
0x00401aff <+103>: pop ebx
0x00401b00 <+104>: pop esi
0x00401b01 <+105>: pop ebp
0x00401b02 <+106>: ret
0x00401b03 <+107>: call 0x401e64 <explode_bomb>
0x00401b08 <+112>: jmp 0x401acd <secret_phase+53>
0x00401b0a <+114>: call 0x401e64 <explode_bomb>
0x00401b0f <+119>: jmp 0x401ae5 <secret_phase+77>
End of assembler dump.可以看到
<+20>
调用了read_line函数,接着把read_line的返回值赋给了eax,并调用了strtol函数,这个标准库函数的作用是把一个字符串转换成对应的长整型数值。返回值还是存放在eax中,<+38>
将eax赋值给了esi,<+40>
将eax减1赋给eax,<+46>
与1000(0x3e8)进行比较,如果这个值小于等于0x3e8就跳过引爆代码。看到这里可以知道我们需要再加入一行数据,它应该是一个小于等于1001的数值。 -
<+53>
将 esi 赋给了 M[esp + 4] ,也就是一开始输入的 eax 值。<+57>
将ebx+0x540赋给了 M[esp] ,<+64>
调用了 fun7 函数。函数返回后令返回值 eax 与 0x3 做了一个比较,如果相等则跳过引爆代码。所以fun7函数需要返回3; -
查看 fun7 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36gdb-peda$ disassemble fun7
Dump of assembler code for function fun7:
0x00401a42 <+0>: endbr32
0x00401a46 <+4>: push ebp
0x00401a47 <+5>: mov ebp,esp
0x00401a49 <+7>: push ebx
0x00401a4a <+8>: sub esp,0x4
0x00401a4d <+11>: mov edx,DWORD PTR [ebp+0x8]
0x00401a50 <+14>: mov ecx,DWORD PTR [ebp+0xc]
0x00401a53 <+17>: test edx,edx
0x00401a55 <+19>: je 0x401a91 <fun7+79>
0x00401a57 <+21>: mov ebx,DWORD PTR [edx]
0x00401a59 <+23>: cmp ebx,ecx
0x00401a5b <+25>: jg 0x401a69 <fun7+39>
0x00401a5d <+27>: mov eax,0x0
0x00401a62 <+32>: jne 0x401a7c <fun7+58>
0x00401a64 <+34>: mov ebx,DWORD PTR [ebp-0x4]
0x00401a67 <+37>: leave
0x00401a68 <+38>: ret
0x00401a69 <+39>: sub esp,0x8
0x00401a6c <+42>: push ecx
0x00401a6d <+43>: push DWORD PTR [edx+0x4]
0x00401a70 <+46>: call 0x401a42 <fun7>
0x00401a75 <+51>: add esp,0x10
0x00401a78 <+54>: add eax,eax
0x00401a7a <+56>: jmp 0x401a64 <fun7+34>
0x00401a7c <+58>: sub esp,0x8
0x00401a7f <+61>: push ecx
0x00401a80 <+62>: push DWORD PTR [edx+0x8]
0x00401a83 <+65>: call 0x401a42 <fun7>
0x00401a88 <+70>: add esp,0x10
0x00401a8b <+73>: lea eax,[eax+eax*1+0x1]
0x00401a8f <+77>: jmp 0x401a64 <fun7+34>
0x00401a91 <+79>: mov eax,0xffffffff
0x00401a96 <+84>: jmp 0x401a64 <fun7+34>
End of assembler dump.查看一下 M[esp] 这个地址里存放的什么数据结构:
1
2
3
4
5
6
7
8gdb-peda$ b *0x00401ad8 #打断点至<+64>
gdb-peda$ x/24xw $eax
0x4054a4 <n1>: 0x00000024 0x004054b0 0x004054bc 0x00000008
0x4054b4 <n21+4>: 0x004054e0 0x004054c8 0x00000032 0x004054d4
0x4054c4 <n22+8>: 0x004054ec 0x00000016 0x0040505c 0x00405044
0x4054d4 <n33>: 0x0000002d 0x00405020 0x00405068 0x00000006
0x4054e4 <n31+4>: 0x0040502c 0x00405050 0x0000006b 0x00405038
0x4054f4 <n34+8>: 0x00405074 0x000002a0 0x00000001 0x00000000仔细观察可以发现这是一个二叉树的结构,每个节点第1个4字节存放数据,第2个4字节存放左子树地址,第3个4字节存放右子树位置。并且命名也有规律,
nab
,a
代表层数,b
代表从左至右第b个节点。整理可得:1
2
3
4
5
6
7
8
9
10
11
12
13
14
150x4054a4 <n1>: 0x00000024 0x004054b0 0x004054bc
0x4054b0 <n21>: 0x00000008 0x004054e0 0x004054c8
0x4054bc <n22>: 0x00000032 0x004054d4 0x004054ec
0x4054e0 <n31>: 0x00000006 0x0040502c 0x00405050
0x4054c8 <n32>: 0x00000016 0x0040505c 0x00405044
0x4054d4 <n33>: 0x0000002d 0x00405020 0x00405068
0x4054ec <n34>: 0x0000006b 0x00405038 0x00405074
0x40502c <n41>: 0x00000001 0x00000000 0x00000000
0x405050 <n42>: 0x00000007 0x00000000 0x00000000
0x40505c <n43>: 0x00000014 0x00000000 0x00000000
0x405044 <n44>: 0x00000023 0x00000000 0x00000000
0x405020 <n45>: 0x00000028 0x00000000 0x00000000
0x405068 <n46>: 0x0000002f 0x00000000 0x00000000
0x405038 <n47>: 0x00000063 0x00000000 0x00000000
0x405074 <n48>: 0x000003e9 0x00000000 0x000000001
2
3
4
5
6
7
8
9
10
11
12
13
14
15graph TB
0x24 --> 0x08
0x24 --> 0x32
0x08 --> 0x06
0x08 --> 0x16
0x32 --> 0x2d
0x32 --> 0x6b
0x06 --> 0x01
0x06 --> 0x07
0x2d --> 0x28
0x2d --> 0x2f
0x6b --> 0x63
0x6b --> 0x3e9
0x16 --> 0x14
0x16 --> 0x23 -
总结上面的过程: M[esp] 指向树的一个节点,令节点的值与读入的值进行比较。
- 如果前者大于后者: M[esp] 移至左子树,返回 2 * eax ;
- 如果前者不等于后者: M[esp] 移至右子树,返回 2 * eax + 1 ;
- 如果前者等于后者:返回0
-
那么我们需要返回3,根据递归可得当输入是 0x63(99)时返回3。
答案:
1 | 99 |
9 最终答案
flag.txt
:
1 | And they have no disregard for human life. |
运行:
1 | $ ./bomb flag.txt |