CSAPP-Lab2:BombLab

目录

1、实验文档注释

2、实验题目

2.1 分析bomb.c

2.2 反汇编phase_1

2.3 反汇编phase_2 

2.4 反汇编phase_3

2.5 反汇编phase_4

2.6 反汇编phase_5

2.7 反汇编phase_6

2.8 反汇编phase_defused

3、总结


1、实验文档注释

邪恶博士公司(PERPETRATOR)特此授予您(受害者)使用此炸弹(bomb)的明确许可。这是一个有时限的许可证,在受害者死亡时到期。PERPETRATOR对受害者的损伤、沮丧、精神错乱、虫眼、腕管综合征、睡眠不足或其他伤害不承担任何责任。除非PERPETRATOR想获得荣誉。受害者不得将此炸弹源代码分发给PERPETRATER的任何敌人。VICTIM不得调试、逆向工程、运行“字符串”、反编译、解密或使用任何其他技术来获得BOMB的知识并消除BOMB。在处理此程序时,可能不穿防炸弹服装。主持人不会为主持人缺乏幽默感而道歉。在法律禁止BOMB的情况下,本许可证无效。

2、实验题目

给了一个 bomb.c(无法编译)和 bomb,运行 bomb 会要求输入六个字符串,任何一个错误的都会BOOM!!! 我们必须利用反汇编工具逆向分析这个文件,找出这六个字符串,从而正确输入。

先启动 gdb 测试一下

gdb bomb

输入 ,然后输入 test 测试

 

以上为bomb程序初步运行过程。

2.1 分析bomb.c

代码主要结构为:

    input = read_line();             /* Get input                   */phase_1(input);                  /* Run the phase               */phase_defused();                 /* Drat!  They figured it out! *//* Let me know how they did it.*/printf("Phase 1 defused. How about the next one?\n");

1、将我们输入的字符串传入 phase_1

2、若可以执行到 phase_defused 函数,则代表拆除成功(盲猜拆除错误时直接退出程序)

所以我们需要分析这个 phase_1 ,使用正确的输入得到函数可以正确返回

2.2 反汇编phase_1

disassemble phase_1

   0x0000000000400ee0 <+0>:	    sub    $0x8,%rsp0x0000000000400ee4 <+4>:    	mov    $0x402400,%esi0x0000000000400ee9 <+9>:    	callq  0x401338 0x0000000000400eee <+14>:	test   %eax,%eax0x0000000000400ef0 <+16>:	je     0x400ef7 0x0000000000400ef2 <+18>:	callq  0x40143a 0x0000000000400ef7 <+23>:	add    $0x8,%rsp0x0000000000400efb <+27>:	retq  

1、分配栈帧

2、将 0x402400 放入 esi (存放第二个函数参数的寄存器)

3、调用

4、按位与比较

5、相等跳转

6、不相等跳转  (爆炸?)

 较明显,此处是将 0x402400 的值放入函数中比较,故该值大概率为phase_1答案,直接使用语句 x/s 0x402400 查看

0x402400:	"Border relations with Canada have never been better."

所以第一题答案为:Border relations with Canada have never been better.

2.3 反汇编phase_2 

disassemble phase_2

   0x0000000000400efc <+0>:	push   %rbp0x0000000000400efd <+1>:	push   %rbx0x0000000000400efe <+2>:	sub    $0x28,%rsp

1、rbp 入栈

2、rbx(caller save)入栈

3、分配栈帧

   0x0000000000400f02 <+6>:	mov    %rsp,%rsi0x0000000000400f05 <+9>:	callq  0x40145c 

1、将 rsp rsi,便于后续操作 rsp

2、rsi作为第二个参数调用 (看起来像输入6个数字)

不妨看看

   0x000000000040145c <+0>:	    sub    $0x18,%rsp0x0000000000401460 <+4>:	    mov    %rsi,%rdx0x0000000000401463 <+7>:	    lea    0x4(%rsi),%rcx0x0000000000401467 <+11>:	lea    0x14(%rsi),%rax0x000000000040146b <+15>:	mov    %rax,0x8(%rsp)0x0000000000401470 <+20>:	lea    0x10(%rsi),%rax0x0000000000401474 <+24>:	mov    %rax,(%rsp)0x0000000000401478 <+28>:	lea    0xc(%rsi),%r90x000000000040147c <+32>:	lea    0x8(%rsi),%r80x0000000000401480 <+36>:    mov    $0x4025c3,%esi0x0000000000401485 <+41>:    mov    $0x0,%eax0x000000000040148a <+46>:    callq  0x400bf0 <__isoc99_sscanf@plt>0x000000000040148f <+51>:    cmp    $0x5,%eax0x0000000000401492 <+54>:    jg     0x401499 0x0000000000401494 <+56>:    callq  0x40143a 0x0000000000401499 <+61>:    add    $0x18,%rsp0x000000000040149d <+65>:    retq

直接看不直观,建议自己画个栈,以 rsi 为头,跟着走一遍,箭头代表指向,最终如下:

所以此时传入了 6 个参数,4 个存入寄存器,2 个存入栈。此时可通过访问 rsi(注意,上层函数的 rsp 即等于此处 rsi )查看 6 个数。返回到上层 phase_2

   0x0000000000400f0a <+14>:	cmpl   $0x1,(%rsp)0x0000000000400f0e <+18>:	je     0x400f30 0x0000000000400f10 <+20>:	callq  0x40143a 0x0000000000400f15 <+25>:	jmp    0x400f30 0x0000000000400f17 <+27>:	mov    -0x4(%rbx),%eax0x0000000000400f1a <+30>:	add    %eax,%eax0x0000000000400f1c <+32>:	cmp    %eax,(%rbx)0x0000000000400f1e <+34>:	je     0x400f25 0x0000000000400f20 <+36>:	callq  0x40143a 0x0000000000400f25 <+41>:	add    $0x4,%rbx0x0000000000400f29 <+45>:	cmp    %rbp,%rbx0x0000000000400f2c <+48>:	jne    0x400f17 0x0000000000400f2e <+50>:	jmp    0x400f3c 0x0000000000400f30 <+52>:	lea    0x4(%rsp),%rbx0x0000000000400f35 <+57>:	lea    0x18(%rsp),%rbp0x0000000000400f3a <+62>:	jmp    0x400f17 0x0000000000400f3c <+64>:	add    $0x28,%rsp0x0000000000400f40 <+68>:	pop    %rbx0x0000000000400f41 <+69>:	pop    %rbp0x0000000000400f42 <+70>:	retq 

1、比较 0x01,可知第一个数为 0x01,正确则跳转+52

2、rcx 的值传入 rbxrbp 后文用作循环终止条件,跳转+27,将 rbx 指向位置的前一个数(即 1)翻倍与rbx比较,则第二个数为 2,跳转+41

3、rbx 地址+0x04,指向第三个数,cmp 可理解为判断循环是否该终止,未终止则跳回+27

4、循环将 rbx 前一个数的两倍与当前 rbx 比较,则可知后续数都是2倍关系

所以第二题答案为:1 2 4 8 16 32

2.4 反汇编phase_3

disassemble phase_3

   0x0000000000400f43 <+0>:	sub    $0x18,%rsp0x0000000000400f47 <+4>:	lea    0xc(%rsp),%rcx0x0000000000400f4c <+9>:	lea    0x8(%rsp),%rdx0x0000000000400f51 <+14>:	mov    $0x4025cf,%esi0x0000000000400f56 <+19>:	mov    $0x0,%eax0x0000000000400f5b <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>0x0000000000400f60 <+29>:	cmp    $0x1,%eax0x0000000000400f63 <+32>:	jg     0x400f6a 0x0000000000400f65 <+34>:	callq  0x40143a 

1、存栈帧

2、分别存入 rcx rdx

3、将格式化字符串 "%d %d" 的地址 0x4025cf 存储到 esi 寄存器中,用于为 sscanf 函数提供解析格式

4、调用 sscanf 函数开始解析用户输入,将输入内容按照 "%d %d" 的格式拆分为两个整数,并将这两个整数存储到 rcx rdx 位置上

5、看返回值的个数,大于 1 跳到+39

   0x0000000000400f6a <+39>:	cmpl   $0x7,0x8(%rsp)0x0000000000400f6f <+44>:	ja     0x400fad 

1、若 rdx 大于 7,跳转 bomb

   0x0000000000400f71 <+46>:	mov    0x8(%rsp),%eax0x0000000000400f75 <+50>:	jmpq   *0x402470(,%rax,8)

1、把 rdx 值传入 eax

2、跳转到 (0x402470 + %rax * 8) 的位置去

3、若 rax 为 0 ,则跳转到 0x402470,check一下,是跳转到 0x400f7c

(gdb) x/x 0x402470
0x402470:	0x7c

跳转到 0x400f7c

   0x0000000000400f7c <+57>:	mov    $0xcf,%eax0x0000000000400f81 <+62>:	jmp    0x400fbe 

1、0xcf 存入 eax

2、跳转+123

   0x0000000000400fbe <+123>:	cmp    0xc(%rsp),%eax0x0000000000400fc2 <+127>:	je     0x400fc9 

1、比较 rcx 0xcf是否相等

2、相等则跳转结束

注:该题答案不唯一,第一个数的取值会导致第个数变化

所以第三题答案之一为:0 207

2.5 反汇编phase_4

disassemble phase_4

   0x000000000040100c <+0>:	    sub    $0x18,%rsp0x0000000000401010 <+4>:    	lea    0xc(%rsp),%rcx0x0000000000401015 <+9>:    	lea    0x8(%rsp),%rdx0x000000000040101a <+14>:	mov    $0x4025cf,%esi0x000000000040101f <+19>:	mov    $0x0,%eax0x0000000000401024 <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>0x0000000000401029 <+29>:	cmp    $0x2,%eax0x000000000040102c <+32>:	jne    0x401035 

不再赘述,输入 2 个数,否则 bomb

   0x000000000040102e <+34>:	cmpl   $0xe,0x8(%rsp)0x0000000000401033 <+39>:	jbe    0x40103a 0x0000000000401035 <+41>:	callq  0x40143a 

1、比较 14 rdx 

2、<= 则跳转,> 则 bomb

   0x000000000040103a <+46>:	mov    $0xe,%edx0x000000000040103f <+51>:	mov    $0x0,%esi0x0000000000401044 <+56>:	mov    0x8(%rsp),%edi0x0000000000401048 <+60>:	callq  0x400fce 0x000000000040104d <+65>:	test   %eax,%eax0x000000000040104f <+67>:	jne    0x401058 

1、0x0e edx0x00 esia edi

2、调用函数

3、确认返回值,不等于 0 的话,爆炸

4、看看

   0x00400fce <+0>:	    sub    $0x8,%rsp                //栈帧0x00400fd2 <+4>:    	mov    %edx,%eax                //eax=0x0e0x00400fd4 <+6>:    	sub    %esi,%eax                //eax=0x0e-0=0x0e0x00400fd6 <+8>:    	mov    %eax,%ecx                //ecx=0x0e0x00400fd8 <+10>:	shr    $0x1f,%ecx               //逻辑右移31位,ecx=00x00400fdb <+13>:	add    %ecx,%eax                //eax=0x0e+0=0x0e0x00400fdd <+15>:	sar    %eax                     //eax=0x07,算术右移(补符号)0x00400fdf <+17>:	lea    (%rax,%rsi,1),%ecx       //ecx=0x07+0x00=0x070x00400fe2 <+20>:	cmp    %edi,%ecx                //%ecx-%edi=0x07-a0x00400fe4 <+22>:	jle    0x400ff2       //a>=0x07则跳转+360x00400fe6 <+24>:	lea    -0x1(%rcx),%edx0x00400fe9 <+27>:	callq  0x400fce 0x00400fee <+32>:	add    %eax,%eax0x00400ff0 <+34>:	jmp    0x401007 0x00400ff2 <+36>:	mov    $0x0,%eax                //eax=0x00,返回值0x00400ff7 <+41>:	cmp    %edi,%ecx                //%ecx-%edi0x00400ff9 <+43>:	jge    0x401007       //a<=0x07则跳转+570x00400ffb <+45>:	lea    0x1(%rcx),%esi0x00400ffe <+48>:	callq  0x400fce 0x00401003 <+53>:	lea    0x1(%rax,%rax,1),%eax0x00401007 <+57>:	add    $0x8,%rsp0x0040100b <+61>:	retq  

1、挺长的,注释写里面了,可以看出 第一个参数需要满足 >=0x07 <=0x07,为 0x07

2、回到 phase_4

   0x000000000040104d <+65>:	test   %eax,%eax0x000000000040104f <+67>:	jne    0x401058 0x0000000000401051 <+69>:	cmpl   $0x0,0xc(%rsp)0x0000000000401056 <+74>:	je     0x40105d 0x0000000000401058 <+76>:	callq  0x40143a 0x000000000040105d <+81>:	add    $0x18,%rsp0x0000000000401061 <+85>:	retq 

1、前文提到,确认返回值,不等于 0 的话则跳转+76爆炸

2、比较第二个参数和 0x00

3、相等则跳转+81结束,则第二个参数为 0

所以第4题答案为:7 0

2.6 反汇编phase_5

disassemble phase_5

   0x0000000000401062 <+0>:	    push   %rbx0x0000000000401063 <+1>:	    sub    $0x20,%rsp0x0000000000401067 <+5>:	    mov    %rdi,%rbx0x000000000040106a <+8>:	    mov    %fs:0x28,%rax0x0000000000401073 <+17>:	mov    %rax,0x18(%rsp)0x0000000000401078 <+22>:	xor    %eax,%eax0x000000000040107a <+24>:	callq  0x40131b 0x000000000040107f <+29>:	cmp    $0x6,%eax0x0000000000401082 <+32>:	je     0x4010d2 0x0000000000401084 <+34>:	callq  0x40143a 

1、rdi 存入 rbx

2、fs 段偏移28的值存入 0x18(%rsp) (防止缓冲区溢出)

3、eax 异或清0

4、调用看长度是否为 6,不为 6 爆炸,为 6 跳转+112

   0x00000000004010d2 <+112>:	mov    $0x0,%eax0x00000000004010d7 <+117>:	jmp    0x40108b 

1、0 放入 eax

2、跳转+41

   0x000000000040108b <+41>:	movzbl (%rbx,%rax,1),%ecx0x000000000040108f <+45>:	mov    %cl,(%rsp)0x0000000000401092 <+48>:	mov    (%rsp),%rdx0x0000000000401096 <+52>:	and    $0xf,%edx0x0000000000401099 <+55>:	movzbl 0x4024b0(%rdx),%edx0x00000000004010a0 <+62>:	mov    %dl,0x10(%rsp,%rax,1)0x00000000004010a4 <+66>:	add    $0x1,%rax0x00000000004010a8 <+70>:	cmp    $0x6,%rax0x00000000004010ac <+74>:	jne    0x40108b 

1、rbx 存的是输入的 6 个数/字母,rax 初始为 0,则 ecx=rsi

2、ecx 的低 8 位放入 rsp,放入 rdx

3、取 edx 的低 4 位

4、取 0x4024b0 中的字符串,以 %rdx 为索引取一个字母,放入 edx

5、将 edx 的低 8 位存在 rsp+0x10 开始的位置

6、循环 次,得到以 rsp+0x10 开始的 6 个字母

   0x00000000004010ae <+76>:	movb   $0x0,0x16(%rsp)0x00000000004010b3 <+81>:	mov    $0x40245e,%esi0x00000000004010b8 <+86>:	lea    0x10(%rsp),%rdi0x00000000004010bd <+91>:	callq  0x401338 0x00000000004010c2 <+96>:	test   %eax,%eax0x00000000004010c4 <+98>:	je     0x4010d9 0x00000000004010c6 <+100>:	callq  0x40143a 

1、0x00 rsp+0x16,做字符串结束标志

2、0x40245e(flyers)给 esi

3、依次比较,所以我们需要让前文得到的 rsp+0x10 的 6 个字母为flyers

回看+41处的代码:

   0x000000000040108b <+41>:	movzbl (%rbx,%rax,1),%ecx0x000000000040108f <+45>:	mov    %cl,(%rsp)0x0000000000401092 <+48>:	mov    (%rsp),%rdx0x0000000000401096 <+52>:	and    $0xf,%edx0x0000000000401099 <+55>:	movzbl 0x4024b0(%rdx),%edx0x00000000004010a0 <+62>:	mov    %dl,0x10(%rsp,%rax,1)0x00000000004010a4 <+66>:	add    $0x1,%rax0x00000000004010a8 <+70>:	cmp    $0x6,%rax0x00000000004010ac <+74>:	jne    0x40108b 

通过对输入的rbx开始的六个数,每个数取最低4位作为索引,所以找到对应的索引值就好。对应的低 4 位分别为:f-1001  l-1111  y-1110  e-0101  r-0110  s-0111

对应到字母的ascii码,则取 IONEFG

所以第 5 题答案为:IONEFG

2.7 反汇编phase_6

disassemble phase_6

   0x00000000004010f4 <+0>:	    push   %r140x00000000004010f6 <+2>:    	push   %r130x00000000004010f8 <+4>:    	push   %r120x00000000004010fa <+6>:    	push   %rbp0x00000000004010fb <+7>:    	push   %rbx0x00000000004010fc <+8>:    	sub    $0x50,%rsp0x0000000000401100 <+12>:	mov    %rsp,%r130x0000000000401103 <+15>:	mov    %rsp,%rsi0x0000000000401106 <+18>:	callq  0x40145c 

1、不赘述,保存参数,分配栈帧,call函数

2、函数在 phase_2 中介绍过,所以用此时的 rsp/rsi/r13 都可以按顺序访问得到6个参数

<+23>:	mov    %rsp,%r14                //r14=rsp/rsi/r13
<+26>:	mov    $0x0,%r12d               //r12d=0x00
<+32>:	mov    %r13,%rbp                //rbp=r13/rsp/rsi
<+35>:	mov    0x0(%r13),%eax           //eax=r13/rsp/rsi=data[0]
<+39>:	sub    $0x1,%eax                //eax=eax-1
<+42>:	cmp    $0x5,%eax                //eax-0x05
<+45>:	jbe    0x401128     //<=5则跳转+52
<+47>:	callq  0x40143a   //否则bomb
<+52>:	add    $0x1,%r12d               //r12d=0x01
<+56>:	cmp    $0x6,%r12d               //r12d-0x06
<+60>:	je     0x401153     //相等则跳出,猜测r12d拿来计数循环6次
<+62>:	mov    %r12d,%ebx               //ebx=r12d
<+65>:	movslq %ebx,%rax                //rax=ebx
<+68>:	mov    (%rsp,%rax,4),%eax       //eax=rsp+rax*4=rsp+0x04=data[1]
<+71>:	cmp    %eax,0x0(%rbp)           //rbp-eax=data[0]-data[1]
<+74>:	jne    0x401145     //!=则跳转+81
<+76>:	callq  0x40143a   //相等则爆炸
<+81>:	add    $0x1,%ebx                //ebx=ebx+1
<+84>:	cmp    $0x5,%ebx                //ebx-0x05
<+87>:	jle    0x401135     //<=5跳回+65,循环保证后面不与当前重复
<+89>:	add    $0x4,%r13                //r13=r13+0x04
<+93>:	jmp    0x401114     //跳转32,执行data[1]

1、太长写注释里了

2、总结为:输入 6 个不同的数、值小于 6

3、运行完跳入+95

<+95>:	lea    0x18(%rsp),%rsi          //rsi=data[6],没数据
<+100>:	mov    %r14,%rax                //rax=r14=rsi=data[0]
<+103>:	mov    $0x7,%ecx                //ecx=0x07
<+108>:	mov    %ecx,%edx                //edx=ecx=0x07
<+110>:	sub    (%rax),%edx              //edx=edx-rax=0x07-data[0]
<+112>:	mov    %edx,(%rax)              //rax=edx,其实就是data[0]=7-data[0]
<+114>:	add    $0x4,%rax                //rax=rax+0x04=data[1]
<+118>:	cmp    %rsi,%rax                //rax-rsi,判断有没有执行完6个数
<+121>:	jne    0x401160    //如果不相等,跳转+108再执行
<+123>:	mov    $0x0,%esi                 //esi=0x00
<+128>:	jmp    0x401197     //跳转+163

1、注释

2、相当于 data[x] = 7 - data[x],所以此时的 data[x] 变成了 >1

3、顺序执行+123

4、跳转+163

<+130>:	mov    0x8(%rdx),%rdx            //rdx=rdx+0x08,向后一个节点
<+134>:	add    $0x1,%eax                 //eax=eax+0x01=0x02
<+137>:	cmp    %ecx,%eax                 //eax-ecx
<+139>:	jne    0x401176     //!=0跳转+130,循环就是node像后移data[x]
<+141>:	jmp    0x401188     //跳转+148
<+143>:	mov    $0x6032d0,%edx            //edx=$0x6032d0=0x0000014c,是一个链表
<+148>:	mov    %rdx,0x20(%rsp,%rsi,2)    //rsp+rsi*2+0x20(rsp+0+0x20)=某一个节点
<+153>:	add    $0x4,%rsi                 //rsi=rsi+0x04
<+157>:	cmp    $0x18,%rsi                //rsi-0x18
<+161>:	je     0x4011ab     //相等跳出去(那就前一次判断先不进入这边)
<+163>:	mov    (%rsp,%rsi,1),%ecx        //ecx=rsp+rsi*1=data[0]
<+166>:	cmp    $0x1,%ecx                 //ecx-0x01
<+169>:	jle    0x401183     //<=1则跳转+143
<+171>:	mov    $0x1,%eax                 //否则eax=0x01
<+176>:	mov    $0x6032d0,%edx            //edx=$0x6032d0=0x0000014c,是一个链表
<+181>:	jmp    0x401176     //跳转+130

1、注释

2、简化一下:以 data[x] 为顺序,依次去查找 node[data[x]] 存在 rsp+0x20 起始的位置

3、所以目前数据如图:

<+183>:	mov    0x20(%rsp),%rbx            //rbx=node[data[0]]
<+188>:	lea    0x28(%rsp),%rax            //rax=rsp+0x28
<+193>:	lea    0x50(%rsp),%rsi            //rsi=rsp+0x50=结尾
<+198>:	mov    %rbx,%rcx                  //rcx=node[data[0]]
<+201>:	mov    (%rax),%rdx                //rdx=node[data[1]]
<+204>:	mov    %rdx,0x8(%rcx)             //rcx+0x08=rdx
<+208>:	add    $0x8,%rax                  //rax=node[data[1]]+0x08=node[data[2]]
<+212>:	cmp    %rsi,%rax                  //rax-rsi
<+215>:	je     0x4011d2      //=0结束则跳出
<+217>:	mov    %rdx,%rcx                  //rcx=rdx,像后遍历
<+220>:	jmp    0x4011bd      //跳转+201

 1、注释

2、我不太理解这一部分的意义,在我理解 0x20 开始就可以遍历该链表的内容了,这样处理一波以后,似乎还是从 0x20 开始可以遍历?

3、我认为我这部分可能没理解对,注释可能有错

<+222>:	movq   $0x0,0x8(%rdx)            //结尾标志
<+230>:	mov    $0x5,%ebp                 //5次循环
<+235>:	mov    0x8(%rbx),%rax            //rax=node[data[1]]
<+239>:	mov    (%rax),%eax               //eax=node[data[1]]->val
<+241>:	cmp    %eax,(%rbx)               //node[data[0]]-node[data[1]]
<+243>:	jge    0x4011ee     //大于等于则跳转+250
<+245>:	callq  0x40143a    //否则bomb
<+250>:	mov    0x8(%rbx),%rbx            //rbx像后遍历
<+254>:	sub    $0x1,%ebp                 //循环结束一次
<+257>:	jne    0x4011df     //未结束则继续
<+259>:	add    $0x50,%rsp     
<+263>:	pop    %rbx
<+264>:	pop    %rbp
<+265>:	pop    %r12
<+267>:	pop    %r13
<+269>:	pop    %r14
<+271>:	retq   

1、注释

2、此处可以看出了,最后的值要按递减顺序走,node如下:

0x6032d0 :	332	1	6304480	0
0x6032e0 :	168	2	6304496	0
0x6032f0 :	924	3	6304512	0
0x603300 :	691	4	6304528	0
0x603310 :	477	5	6304544	0
0x603320 :	443	6	0	0

1、所以最后需要 node 的顺序是3-4-5-6-1-2

2、倒推 7-data[x] 的大小应该为3-4-5-6-1-2

3、则 data[x] 4-3-2-1-6-5

4、我以为结束了,结果还有隐藏关卡

所以第六题答案为:4 3 2 1 6 5

2.8 反汇编phase_defused

disassenmble phase_defused

<+0>:	sub    $0x78,%rsp                    
<+4>:	mov    %fs:0x28,%rax                                   
<+13>:	mov    %rax,0x68(%rsp)     
<+18>:	xor    %eax,%eax                     //清0eax
<+20>:	cmpl   $0x6,0x202181(%rip)           //判断字符串大小
<+27>:	jne    0x40163f   //!=6,则跳转+123结束
<+29>:	lea    0x10(%rsp),%r8                //r8=rsp+0x10
<+34>:	lea    0xc(%rsp),%rcx                //rcx=rsp+0x0c
<+39>:	lea    0x8(%rsp),%rdx                //rdx=rsp+0x08
<+44>:	mov    $0x402619,%esi                //esi="%d %d %s"
<+49>:	mov    $0x603870,%edi                //edi=""
<+54>:	callq  0x400bf0 <__isoc99_sscanf@plt>//调用sscanf
<+59>:	cmp    $0x3,%eax                     //比较输入是否为3个
<+62>:	jne    0x401635   //=3,则跳转+113
<+64>:	mov    $0x402622,%esi                //esi="DrEvil"
<+69>:	lea    0x10(%rsp),%rdi               //rdi=rsp+0x10,r8目前也是这个
<+74>:	callq  0x401338   //if edi!=esi
<+79>:	test   %eax,%eax                     //不相等为1
<+81>:	jne    0x401635   //不相等则跳转+113
<+83>:	mov    $0x4024f8,%edi                //edi="Curses, .....省略"
<+88>:	callq  0x400b10            //
<+93>:	mov    $0x402520,%edi                //edi="But finding,.....省略"
<+98>:	callq  0x400b10            //
<+103>:	mov    $0x0,%eax                     //eax=0
<+108>:	callq  0x401242        //进入隐藏
<+113>:	mov    $0x402558,%edi
<+118>:	callq  0x400b10 
<+123>:	mov    0x68(%rsp),%rax
<+128>:	xor    %fs:0x28,%rax
<+137>:	je     0x401654 
<+139>:	callq  0x400b30 <__stack_chk_fail@plt>
<+144>:	add    $0x78,%rsp
<+148>:	retq   

1、注释

2、所以目前看是输入 "%d %d %s" 时,其中 "%s" "DrEvil",这种输入格式在第 2 关第 4 关均有

3、打断点 b *0x4015fa(sscanf那一行)

4、r 运行

(gdb) b *0x4015fa
Breakpoint 1 at 0x4015fa
(gdb) r
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That's number 2.  Keep going!
0 207
Halfway there!
7 0
So you got that one.  Try this one.
IONEFG                                             
Good work!  On to the next...
4 3 2 1 6 5Breakpoint 1, 0x00000000004015fa in phase_defused ()
(gdb) x/s 0x603870
0x603870 :	"7 0"

1、依次输入 1-6 题答案

2、可知应该在 "7 0" 后面加 "DrEvil" ,也就是第四题

3、现在,进入 secret_phase

<+0>:	push   %rbx
<+1>:	callq  0x40149e         //
<+6>:	mov    $0xa,%edx                   //edx=0x0a
<+11>:	mov    $0x0,%esi                   //esi=0x00
<+16>:	mov    %rax,%rdi                   //rdi=rax
<+19>:	callq  0x400bd0        //字符串转整数
<+24>:	mov    %rax,%rbx                   //rbx=rax,转换结果
<+27>:	lea    -0x1(%rax),%eax             //eax=rax-0x01
<+30>:	cmp    $0x3e8,%eax                 //eax-0x3e8
<+35>:	jbe    0x40126c   //<=则跳转+42
<+37>:	callq  0x40143a      //>则爆炸
<+42>:	mov    %ebx,%esi                   //esi=ebx,转换结果
<+44>:	mov    $0x6030f0,%edi              //edi=0x6030f0,是36
<+49>:	callq  0x401204              //传给fun7
<+54>:	cmp    $0x2,%eax                   //eax-0x02
<+57>:	je     0x401282   //=2则跳转+64
<+59>:	callq  0x40143a      //否则bomb
<+64>:	mov    $0x402438,%edi            
<+69>:	callq  0x400b10 
<+74>:	callq  0x4015c4 
<+79>:	pop    %rbx
<+80>:	retq   

1、注释

2、所以现在是调用 fun7,输入 0x6030f0 中的数和我们输入的数

3、查看 fun7

<+0>:	sub    $0x8,%rsp                //
<+4>:	test   %rdi,%rdi                //按位与,主要是为了标志位,做循环结束标志
<+7>:	je     0x401238        //0则跳转+52
<+9>:	mov    (%rdi),%edx              //edx=rdi=0x6030f0的值,是一棵树
<+11>:	cmp    %esi,%edx                //edx-esi
<+13>:	jle    0x401220        //<=则跳转+28
<+15>:	mov    0x8(%rdi),%rdi           //后移去左边,为查下一个节点
<+19>:	callq  0x401204           //再来一次
<+24>:	add    %eax,%eax                //eax+=eax
<+26>:	jmp    0x40123d        //跳转+57结束
<+28>:	mov    $0x0,%eax                //eax=0
<+33>:	cmp    %esi,%edx                //edx-esi
<+35>:	je     0x40123d        //=0则跳转+57结束
<+37>:	mov    0x10(%rdi),%rdi          //rdi后移去右边
<+41>:	callq  0x401204           //再来一次
<+46>:	lea    0x1(%rax,%rax,1),%eax    //eax=rax+rax*1+0x01
<+50>:	jmp    0x40123d        //跳转+57结束
<+52>:	mov    $0xffffffff,%eax         //拉满eax
<+57>:	add    $0x8,%rsp                //
<+61>:	retq   

1、注释

2、整段类似一个递归,根据输入值 rsi 去在这棵树中查找

3、从 eax=0 开始,每一次查找后,若向左 eax*=2,若向右 eax=eax*2+1,回到 secret_phase

   0x0000000000401278 <+54>:	cmp    $0x2,%eax0x000000000040127b <+57>:	je     0x401282 0x000000000040127d <+59>:	callq  0x40143a 0x0000000000401282 <+64>:	mov    $0x402438,%edi0x0000000000401287 <+69>:	callq  0x400b10 0x000000000040128c <+74>:	callq  0x4015c4 0x0000000000401291 <+79>:	pop    %rbx0x0000000000401292 <+80>:	retq   

1、可以看出,要求 fun7 的返回值是 ==2 的,所以前文的输入应该是 22

所以隐藏题答案为:22

3、总结

懵懵懂懂,请多指教!


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部