CSAPP实验2:Bomb Lab

这是《深入理解计算机系统(第3版)》的配套实验,实验相关的代码和说明可以从官网下载。
选择BombLab作为开始,是因为做PWN的时候屡屡因为GDB使用不熟练而无从下手(对,哪怕有WP还是搞不定)。吐槽一下,如果有GDB的文档就能熟练使用,就好像拿到一本汽车的使用说明书就能考过驾照一样。所以选择了通过CSAPP的实验加强对GDB的使用。

环境与工具

  • Ubuntu 16.04
  • 安装了GDB的插件peda

phase_1

首先在phase_1处下一个断点:

b phase_1

看一下phase_1的反汇编代码:

gdb-peda$ disas phase_1
Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>:     sub    rsp,0x8
   0x0000000000400ee4 <+4>:     mov    esi,0x402400                     #用于和输入做比较的字符串地址
   0x0000000000400ee9 <+9>:     call   0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   eax,eax                          #<strings_not_equal>的返回值为0
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
   0x0000000000400ef2 <+18>:    call   0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    rsp,0x8
   0x0000000000400efb <+27>:    ret    
End of assembler dump.

<+4>的一行,esi寄存器存入了一个地址,该地址中是用于在中比较的字符串。用GDB的x命令查看一下:

gdb-peda$ x/s 0x402400
0x402400:   "Border relations with Canada have never been better."

新建一个./input.txt,第一行输入:

Border relations with Canada have never been better.

在gdb中设置从该文件输入:

gdb-peda$ set args ./input.txt

重新运行

gdb-peda$ r
Starting program: /mnt/hgfs/pwn/csapp/bombLab/bomb ./input.txt 
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?

phase_1的Bomb拆除!

phase_2

看一下代码:

gdb-peda$ disas phase_2
Dump of assembler code for function phase_2:
   0x0000000000400efc <+0>:     push   rbp
   0x0000000000400efd <+1>:     push   rbx
   0x0000000000400efe <+2>:     sub    rsp,0x28                         #rsp是存储6个数字的栈顶
   0x0000000000400f02 <+6>:     mov    rsi,rsp
   0x0000000000400f05 <+9>:     call   0x40145c <read_six_numbers>      #读入6个数字
   0x0000000000400f0a <+14>:    cmp    DWORD PTR [rsp],0x1              #第一个数字为1
   0x0000000000400f0e <+18>:    je     0x400f30 <phase_2+52>
   0x0000000000400f10 <+20>:    call   0x40143a <explode_bomb>
   0x0000000000400f15 <+25>:    jmp    0x400f30 <phase_2+52>
   0x0000000000400f17 <+27>:    mov    eax,DWORD PTR [rbx-0x4]          #循环体:开始
   0x0000000000400f1a <+30>:    add    eax,eax                          #将上一个数字乘2
   0x0000000000400f1c <+32>:    cmp    DWORD PTR [rbx],eax
   0x0000000000400f1e <+34>:    je     0x400f25 <phase_2+41>
   0x0000000000400f20 <+36>:    call   0x40143a <explode_bomb>
   0x0000000000400f25 <+41>:    add    rbx,0x4                          #rbx加4,取下一个数字
   0x0000000000400f29 <+45>:    cmp    rbx,rbp                          #判断是否已经将6个数字做比较
   0x0000000000400f2c <+48>:    jne    0x400f17 <phase_2+27>            #循环体:结束
   0x0000000000400f2e <+50>:    jmp    0x400f3c <phase_2+64>
   0x0000000000400f30 <+52>:    lea    rbx,[rsp+0x4]
   0x0000000000400f35 <+57>:    lea    rbp,[rsp+0x18]                   #rbp留出6个数字的空间
   0x0000000000400f3a <+62>:    jmp    0x400f17 <phase_2+27>
   0x0000000000400f3c <+64>:    add    rsp,0x28                         #退出phase_2
   0x0000000000400f40 <+68>:    pop    rbx
   0x0000000000400f41 <+69>:    pop    rbp
   0x0000000000400f42 <+70>:    ret    
End of assembler dump.

在./input.txt的第2行输入:

1 2 4 8 16 32

重新运行

gdb-peda$ r
Starting program: /mnt/hgfs/pwn/csapp/bombLab/bomb ./input.txt 
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
That's number 2.  Keep going!

phase_2的Bomb拆除!

phase_3

gdb-peda$ disas phase_3
Dump of assembler code for function phase_3:
   0x0000000000400f43 <+0>:     sub    rsp,0x18
   0x0000000000400f47 <+4>:     lea    rcx,[rsp+0xc]                        #存放读取的第二个数字
   0x0000000000400f4c <+9>:     lea    rdx,[rsp+0x8]                        #存放读取的第一个数字
   0x0000000000400f51 <+14>:    mov    esi,0x4025cf                         #0x4025cf:  "%d %d"
   0x0000000000400f56 <+19>:    mov    eax,0x0
   0x0000000000400f5b <+24>:    call   0x400bf0 <__isoc99_sscanf@plt>
   0x0000000000400f60 <+29>:    cmp    eax,0x1
   0x0000000000400f63 <+32>:    jg     0x400f6a <phase_3+39>                #读取数字的个数大于1
   0x0000000000400f65 <+34>:    call   0x40143a <explode_bomb>
   0x0000000000400f6a <+39>:    cmp    DWORD PTR [rsp+0x8],0x7              #DWORD,双字节32bit=4B
   0x0000000000400f6f <+44>:    ja     0x400fad <phase_3+106>               #[rsp+0x8] <= 0x7
   0x0000000000400f71 <+46>:    mov    eax,DWORD PTR [rsp+0x8]
   0x0000000000400f75 <+50>:    jmp    QWORD PTR [rax*8+0x402470]           #跳转分支:开始
   0x0000000000400f7c <+57>:    mov    eax,0xcf                             #rax==0
   0x0000000000400f81 <+62>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f83 <+64>:    mov    eax,0x2c3                            #rax==2
   0x0000000000400f88 <+69>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f8a <+71>:    mov    eax,0x100                            #rax==3
   0x0000000000400f8f <+76>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f91 <+78>:    mov    eax,0x185                            #rax==4
   0x0000000000400f96 <+83>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f98 <+85>:    mov    eax,0xce                             #rax==5
   0x0000000000400f9d <+90>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f9f <+92>:    mov    eax,0x2aa                            #rax==6
   0x0000000000400fa4 <+97>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400fa6 <+99>:    mov    eax,0x147                            #rax==7
   0x0000000000400fab <+104>:   jmp    0x400fbe <phase_3+123>
   0x0000000000400fad <+106>:   call   0x40143a <explode_bomb>
   0x0000000000400fb2 <+111>:   mov    eax,0x0
   0x0000000000400fb7 <+116>:   jmp    0x400fbe <phase_3+123>               
   0x0000000000400fb9 <+118>:   mov    eax,0x137                            #rax==1
   0x0000000000400fbe <+123>:   cmp    eax,DWORD PTR [rsp+0xc]              #eax与[rsp+0xc]做比较
   0x0000000000400fc2 <+127>:   je     0x400fc9 <phase_3+134>               #相等则不会引爆炸弹
   0x0000000000400fc4 <+129>:   call   0x40143a <explode_bomb>
   0x0000000000400fc9 <+134>:   add    rsp,0x18
   0x0000000000400fcd <+138>:   ret    
End of assembler dump.

分析如下:

<+14>:sscanf的转换说明,"%d %d",说明读取的是两个整数
<+32>:判断读取的数字个数是否大于1
<+44>:读取的第1个数字小于等于7
<+50>:根据第一个数字做跳转,类似switch语句,作为判断第二个数字的依据

答案不唯一,注意要把16进制转为10进制:

0 0xcf
1 0x137
2 0x2c3
3 0x100
4 0x185
5 0xce
6 0x2aa
7 0x147

phase_4

gdb-peda$ disas phase_4
Dump of assembler code for function phase_4:
   0x000000000040100c <+0>:     sub    rsp,0x18
   0x0000000000401010 <+4>:     lea    rcx,[rsp+0xc]
   0x0000000000401015 <+9>:     lea    rdx,[rsp+0x8]
   0x000000000040101a <+14>:    mov    esi,0x4025cf                         #0x4025cf:  "%d %d"
   0x000000000040101f <+19>:    mov    eax,0x0
   0x0000000000401024 <+24>:    call   0x400bf0 <__isoc99_sscanf@plt>
   0x0000000000401029 <+29>:    cmp    eax,0x2                              #读入两个数字num_1和num_2
   0x000000000040102c <+32>:    jne    0x401035 <phase_4+41>
   0x000000000040102e <+34>:    cmp    DWORD PTR [rsp+0x8],0xe              #num_1 <= 14
   0x0000000000401033 <+39>:    jbe    0x40103a <phase_4+46>
   0x0000000000401035 <+41>:    call   0x40143a <explode_bomb>
   0x000000000040103a <+46>:    mov    edx,0xe
   0x000000000040103f <+51>:    mov    esi,0x0
   0x0000000000401044 <+56>:    mov    edi,DWORD PTR [rsp+0x8]
   0x0000000000401048 <+60>:    call   0x400fce <func4>
   0x000000000040104d <+65>:    test   eax,eax                              #<func4>的返回值为0
   0x000000000040104f <+67>:    jne    0x401058 <phase_4+76>
   0x0000000000401051 <+69>:    cmp    DWORD PTR [rsp+0xc],0x0              #num_2 == 0
   0x0000000000401056 <+74>:    je     0x40105d <phase_4+81>
   0x0000000000401058 <+76>:    call   0x40143a <explode_bomb>
   0x000000000040105d <+81>:    add    rsp,0x18
   0x0000000000401061 <+85>:    ret    
End of assembler dump.

phase_4要输入两个数字,其中num_1 <= 15,而num_2 == 0。中间还有进行处理,返回值必须为0。接下来查看:

gdb-peda$ disas func4 
Dump of assembler code for function func4:
   0x0000000000400fce <+0>:     sub    rsp,0x8
   0x0000000000400fd2 <+4>:     mov    eax,edx
   0x0000000000400fd4 <+6>:     sub    eax,esi
   0x0000000000400fd6 <+8>:     mov    ecx,eax
   0x0000000000400fd8 <+10>:    shr    ecx,0x1f                             #shr:逻辑右移,最高位用0补充
   0x0000000000400fdb <+13>:    add    eax,ecx
   0x0000000000400fdd <+15>:    sar    eax,1                                #sar:算数右移,最高位用符号位来补足
   0x0000000000400fdf <+17>:    lea    ecx,[rax+rsi*1]                      #ecx=7
   0x0000000000400fe2 <+20>:    cmp    ecx,edi                              #ecx=7 <= edi
   0x0000000000400fe4 <+22>:    jle    0x400ff2 <func4+36>                  #跳过递归
   0x0000000000400fe6 <+24>:    lea    edx,[rcx-0x1]
   0x0000000000400fe9 <+27>:    call   0x400fce <func4>                     #递归调用
   0x0000000000400fee <+32>:    add    eax,eax
   0x0000000000400ff0 <+34>:    jmp    0x401007 <func4+57>
   0x0000000000400ff2 <+36>:    mov    eax,0x0
   0x0000000000400ff7 <+41>:    cmp    ecx,edi                              #ecx=7 >= edi
   0x0000000000400ff9 <+43>:    jge    0x401007 <func4+57>
   0x0000000000400ffb <+45>:    lea    esi,[rcx+0x1]
   0x0000000000400ffe <+48>:    call   0x400fce <func4>                     #递归调用
   0x0000000000401003 <+53>:    lea    eax,[rax+rax*1+0x1]
   0x0000000000401007 <+57>:    add    rsp,0x8
   0x000000000040100b <+61>:    ret    
End of assembler dump.

简单的思路是这样:

<+17>:得到的结果是ecx=7
<+20>:ecx=7 <= edi才能跳转
<+41>:ecx=7 >= edi才能跳转

尝试了用6,发现几次递归之后,返回eax=1,所以本着直接解决问题的想法,输入以下数字通关:

0 7

phase_5

gdb-peda$ disas phase_5
Dump of assembler code for function phase_5:
   0x0000000000401062 <+0>:     push   rbx
   0x0000000000401063 <+1>:     sub    rsp,0x20
   0x0000000000401067 <+5>:     mov    rbx,rdi                              #rbx存放输入字符串
   0x000000000040106a <+8>:     mov    rax,QWORD PTR fs:0x28                #canary值
   0x0000000000401073 <+17>:    mov    QWORD PTR [rsp+0x18],rax             #置于rsp+24的位置
   0x0000000000401078 <+22>:    xor    eax,eax
   0x000000000040107a <+24>:    call   0x40131b <string_length>
   0x000000000040107f <+29>:    cmp    eax,0x6                              #字符串长度为6
   0x0000000000401082 <+32>:    je     0x4010d2 <phase_5+112>
   0x0000000000401084 <+34>:    call   0x40143a <explode_bomb>
   0x0000000000401089 <+39>:    jmp    0x4010d2 <phase_5+112>
   0x000000000040108b <+41>:    movzx  ecx,BYTE PTR [rbx+rax*1]             #循环起点:从输入字符串中逐个取字符
   0x000000000040108f <+45>:    mov    BYTE PTR [rsp],cl                    #cl为8位寄存器
   0x0000000000401092 <+48>:    mov    rdx,QWORD PTR [rsp]
   0x0000000000401096 <+52>:    and    edx,0xf                              #rdx:保留字符的低4位(0xf = 1111b),高位都置零
   0x0000000000401099 <+55>:    movzx  edx,BYTE PTR [rdx+0x4024b0]          #0x4024b0 <array.3449>: "maduiersnfotvbyl..."取16位即可
   0x00000000004010a0 <+62>:    mov    BYTE PTR [rsp+rax*1+0x10],dl         #新字符串存在[rsp+0x10]位置。<+86>可见。
   0x00000000004010a4 <+66>:    add    rax,0x1                              #rax递增,用于计数
   0x00000000004010a8 <+70>:    cmp    rax,0x6                              #结束循环的条件:rax==6
   0x00000000004010ac <+74>:    jne    0x40108b <phase_5+41>                #循环判断
   0x00000000004010ae <+76>:    mov    BYTE PTR [rsp+0x16],0x0              #rsp+24的位置存入空字符'\0'作为结束
   0x00000000004010b3 <+81>:    mov    esi,0x40245e                         #esi:0x40245e:  "flyers"
   0x00000000004010b8 <+86>:    lea    rdi,[rsp+0x10]                       #rdi:循环处理后得到的字符串        
   0x00000000004010bd <+91>:    call   0x401338 <strings_not_equal>         #用于比较字符串
   0x00000000004010c2 <+96>:    test   eax,eax
   0x00000000004010c4 <+98>:    je     0x4010d9 <phase_5+119>               #字符串相等即可通过phase_5
   0x00000000004010c6 <+100>:   call   0x40143a <explode_bomb>
   0x00000000004010cb <+105>:   nop    DWORD PTR [rax+rax*1+0x0]
   0x00000000004010d0 <+110>:   jmp    0x4010d9 <phase_5+119>
   0x00000000004010d2 <+112>:   mov    eax,0x0
   0x00000000004010d7 <+117>:   jmp    0x40108b <phase_5+41>
   0x00000000004010d9 <+119>:   mov    rax,QWORD PTR [rsp+0x18]
   0x00000000004010de <+124>:   xor    rax,QWORD PTR fs:0x28
   0x00000000004010e7 <+133>:   je     0x4010ee <phase_5+140>
   0x00000000004010e9 <+135>:   call   0x400b30 <__stack_chk_fail@plt>
   0x00000000004010ee <+140>:   add    rsp,0x20
   0x00000000004010f2 <+144>:   pop    rbx
   0x00000000004010f3 <+145>:   ret    
End of assembler dump.

从<+41>和<+52>可知,输入的字符串被逐个处理为只保留低4位的数字(0~15),然后从0x4024b0位置的字符串中取出相应位置的字符,存入新的字符串中。<+76>给字符串加入’\0’作为结束。

<+91>:把新生成的字符串和”flyers”做比较,相同则可以通过phase_5。

要从”maduiersnfotvbyl”中取出”flyers”,那么输入的字符串中,各个字符的ascii码末位,应该分别对应”9FE567”,查看ascii码可知有多种答案。在此列出一种:

ionefg

phase_6

gdb-peda$ disas phase_6
Dump of assembler code for function phase_6:
   0x00000000004010f4 <+0>:     push   r14
   0x00000000004010f6 <+2>:     push   r13
   0x00000000004010f8 <+4>:     push   r12
   0x00000000004010fa <+6>:     push   rbp
   0x00000000004010fb <+7>:     push   rbx
   0x00000000004010fc <+8>:     sub    rsp,0x50
   0x0000000000401100 <+12>:    mov    r13,rsp
   0x0000000000401103 <+15>:    mov    rsi,rsp
   0x0000000000401106 <+18>:    call   0x40145c       #读入6个数字
   0x000000000040110b <+23>:    mov    r14,rsp
   0x000000000040110e <+26>:    mov    r12d,0x0
   0x0000000000401114 <+32>:    mov    rbp,r13                          #循环:起点
   0x0000000000401117 <+35>:    mov    eax,DWORD PTR [r13+0x0]          #从r13读入num_x
   0x000000000040111b <+39>:    sub    eax,0x1
   0x000000000040111e <+42>:    cmp    eax,0x5                          #num_x <= 6
   0x0000000000401121 <+45>:    jbe    0x401128 52>            #jbe:无符号(都为正数)不小于则跳转
   0x0000000000401123 <+47>:    call   0x40143a 
   0x0000000000401128 <+52>:    add    r12d,0x1
   0x000000000040112c <+56>:    cmp    r12d,0x6                         #r12d用于计数
   0x0000000000401130 <+60>:    je     0x401153 95>
   0x0000000000401132 <+62>:    mov    ebx,r12d
   0x0000000000401135 <+65>:    movsxd rax,ebx                          #movs,带符号扩展。从双字到四字。
   0x0000000000401138 <+68>:    mov    eax,DWORD PTR [rsp+rax*4]        #用rax作为计数,获取下一个数
   0x000000000040113b <+71>:    cmp    DWORD PTR [rbp+0x0],eax
   0x000000000040113e <+74>:    jne    0x401145 81>            #eax中的数字不能与rbp+0x0中的数字相同
   0x0000000000401140 <+76>:    call   0x40143a 
   0x0000000000401145 <+81>:    add    ebx,0x1
   0x0000000000401148 <+84>:    cmp    ebx,0x5                          #ebx用于计数
   0x000000000040114b <+87>:    jle    0x401135 65>            #循环1:判断后续数字是否和当前数字相同
   0x000000000040114d <+89>:    add    r13,0x4                          #r13 += 0x4
   0x0000000000401151 <+93>:    jmp    0x401114 32>            #循环2:逐个检验num_1~num_6,目标是6个数字都不同

通过上面的操作,可知6个数字为1~6且各不相等。操作之后,6个数字都存在栈里,从%rsp ~ %rsp+0x14。

   0x0000000000401153 <+95>:    lea    rsi,[rsp+0x18]                   #
   0x0000000000401158 <+100>:   mov    rax,r14                          #rax = rsp
   0x000000000040115b <+103>:   mov    ecx,0x7
   0x0000000000401160 <+108>:   mov    edx,ecx                          #循环点;edx = 7
   0x0000000000401162 <+110>:   sub    edx,DWORD PTR [rax]              #edx -= [rax]
   0x0000000000401164 <+112>:   mov    DWORD PTR [rax],edx              #[rax] = 7-[rax]
   0x0000000000401166 <+114>:   add    rax,0x4                          #rax移位
   0x000000000040116a <+118>:   cmp    rax,rsi
   0x000000000040116d <+121>:   jne    0x401160 108>           #循环判断

将6个数字都做了7-num_x的操作。

   0x000000000040116f <+123>:   mov    esi,0x0                          #esi = 0
   0x0000000000401174 <+128>:   jmp    0x401197 <phase_6+163>
   0x0000000000401176 <+130>:   mov    rdx,QWORD PTR [rdx+0x8]          #循环点
   0x000000000040117a <+134>:   add    eax,0x1
   0x000000000040117d <+137>:   cmp    eax,ecx
   0x000000000040117f <+139>:   jne    0x401176 <phase_6+130>           #判断:eax=7
   0x0000000000401181 <+141>:   jmp    0x401188 <phase_6+148>
   0x0000000000401183 <+143>:   mov    edx,0x6032d0                     #num_x == 1时
   0x0000000000401188 <+148>:   mov    QWORD PTR [rsp+rsi*2+0x20],rdx   #将0x6032d0放在栈里
   0x000000000040118d <+153>:   add    rsi,0x4
   0x0000000000401191 <+157>:   cmp    rsi,0x18
   0x0000000000401195 <+161>:   je     0x4011ab <phase_6+183>           #对6个数做完操作后,跳出循环
   0x0000000000401197 <+163>:   mov    ecx,DWORD PTR [rsp+rsi*1]        #ecx = num_x
   0x000000000040119a <+166>:   cmp    ecx,0x1
   0x000000000040119d <+169>:   jle    0x401183 <phase_6+143>           #num_x为1时跳转
   0x000000000040119f <+171>:   mov    eax,0x1
   0x00000000004011a4 <+176>:   mov    edx,0x6032d0
   0x00000000004011a9 <+181>:   jmp    0x401176 <phase_6+130>           #循环跳转

这段依次读入6个数字:首先把num_x和1做对比,如果num_x == 1的话就把指针0x6032d0放到栈里。如果num_x != 1,放入栈中的是其他指针。处理后的这些指针放在

gdb-peda$ x/12g 0x6032d0
0x6032d0 <node1>:   0x000000010000014c  0x00000000006032e0
0x6032e0 <node2>:   0x00000002000000a8  0x00000000006032f0
0x6032f0 <node3>:   0x000000030000039c  0x0000000000603300
0x603300 <node4>:   0x00000004000002b3  0x0000000000603310
0x603310 <node5>:   0x00000005000001dd  0x0000000000603320
0x603320 <node6>:   0x00000006000001bb  0x0000000000000000

这是一个结构体,类似于

struct {
    int value;
    int order;
    node* next;
} node;

接下来是关键的部分,按照栈上存放指针的顺序,把

   0x00000000004011ab <+183>:   mov    rbx,QWORD PTR [rsp+0x20]         #rbx取[rsp+0x20],作为基址
   0x00000000004011b0 <+188>:   lea    rax,[rsp+0x28]
   0x00000000004011b5 <+193>:   lea    rsi,[rsp+0x50]                   #rsi取[rsp+0x50],作为终点
   0x00000000004011ba <+198>:   mov    rcx,rbx                          #rcx取栈中的一个地址
   0x00000000004011bd <+201>:   mov    rdx,QWORD PTR [rax]              #rdx取栈中的第二个地址;依此类推,每次更新,都取rcx的后一个地址
   0x00000000004011c0 <+204>:   mov    QWORD PTR [rcx+0x8],rdx
   0x00000000004011c4 <+208>:   add    rax,0x8
   0x00000000004011c8 <+212>:   cmp    rax,rsi
   0x00000000004011cb <+215>:   je     0x4011d2 <phase_6+222>
   0x00000000004011cd <+217>:   mov    rcx,rdx                          #更新rcx
   0x00000000004011d0 <+220>:   jmp    0x4011bd <phase_6+201>

循环2对栈上的6个指针,取指针的值进行比较。从[rsp+20]到[rsp+0x48]的,6个指针对应的值必须是从大到小排列的。

   0x00000000004011d2 <+222>:   mov    QWORD PTR [rdx+0x8],0x0
   0x00000000004011da <+230>:   mov    ebp,0x5                          #ebp用于计数
   0x00000000004011df <+235>:   mov    rax,QWORD PTR [rbx+0x8]          #更新rax,取rbx的后一个指针
   0x00000000004011e3 <+239>:   mov    eax,DWORD PTR [rax]              #eax存放rbx的后一个指针的值
   0x00000000004011e5 <+241>:   cmp    DWORD PTR [rbx],eax              #rbx中的指针取值,要大于后一个指针取值
   0x00000000004011e7 <+243>:   jge    0x4011ee 250>
   0x00000000004011e9 <+245>:   call   0x40143a 
   0x00000000004011ee <+250>:   mov    rbx,QWORD PTR [rbx+0x8]          #更新rbx
   0x00000000004011f2 <+254>:   sub    ebp,0x1
   0x00000000004011f5 <+257>:   jne    0x4011df 235>           #循环点
   0x00000000004011f7 <+259>:   add    rsp,0x50
   0x00000000004011fb <+263>:   pop    rbx
   0x00000000004011fc <+264>:   pop    rbp
   0x00000000004011fd <+265>:   pop    r12
   0x00000000004011ff <+267>:   pop    r13
   0x0000000000401201 <+269>:   pop    r14
   0x0000000000401203 <+271>:   ret    
End of assembler dump.

根据6个指针的地址取值情况:

db-peda$ x/24dw 0x6032d0
0x6032d0 <node1>:   332 1   6304480 0
0x6032e0 <node2>:   168 2   6304496 0
0x6032f0 <node3>:   924 3   6304512 0
0x603300 <node4>:   691 4   6304528 0
0x603310 <node5>:   477 5   6304544 0
0x603320 <node6>:   443 6   0   0

从大到小应该为:3,4,5,6,1,2。考虑到7-num_x的操作,num_x的输入顺序为4,3,2,1,6,5。

参考资料

  • CS:APP配套实验2:Bomb Lab笔记
  • 不周山之读厚 CSAPP】II Bomb Lab
  • Beej’s Quick Guide to GDB
  • Beej的GDB快速指南

你可能感兴趣的:(CSAPP实验)