CSAPP:Bomb_Lab思路+汇编分析

195 阅读12分钟

CSAPP:Bomb_Lab

准备工作

  1. 一些命令

    evince name.pdf //查看PDF文件
    (gdb) disas phase_1//查看汇编
    
  2. 下载脚本:(Ubuntu 22.04)

    wget https://gitee.com/lin-xi-269/csapplab/raw/origin/installAll.sh # 下载脚本
    bash installAll.sh # 运行脚本
    
  3. tmux使用

    tmux new -s name//新建
    tmux ls
    tmux a -t name
    
    tmux attach -t 
    tmux a -t name //简写
    
    tmux kill-session -t name
    
    # 选择需要跳转的session会话
    C + b s
    
    # 断开当前session
    C + b d
    
    # 在当前session中多加一个window
    C + b c
    C + b p//向上切换
    C + b n//向下切换
    
    # 关闭当前session中的当前window
    C + b x
    C + x 关闭当前窗格
    
    # 常用快捷键
    C + b ! 关闭一个session中所有窗口
    C + b %  将当前窗口分成左右两分
    C + b "  将当前窗口分成上下两分
    C + b 方向键 #让光标在不同的窗口中跳转 
    C + b 方向键 #按住C+b不放,同时按住方向键,可以调节光标所在窗口的大小 
    

phase_1

  1. 汇编分析

    000000000400ee0 <phase_1>:
      400ee0:	48 83 ec 08          	sub    $0x8,%rsp	#栈偏移减少:为此函数在栈上开内存
      400ee4:	be 00 24 40 00       	mov    $0x402400,%esi	#将某个神秘的地址存入%esi
      400ee9:	e8 4a 04 00 00       	call   401338 <strings_not_equal>	#调用函数:字符串比较函数
      400eee:	85 c0                	test   %eax,%eax	#检测两个寄存器的值是否相等
      400ef0:	74 05                	je     400ef7 <phase_1+0x17>	#如果相等跳转到400ef7
      400ef2:	e8 43 05 00 00       	call   40143a <explode_bomb>	#不相等调用函数:炸弹爆炸
      400ef7:	48 83 c4 08          	add    $0x8,%rsp	#指针加8,指向下一个指令
      400efb:	c3                   	ret    
    
    
  2. 思路:

    1. 莫名其妙出现的地址0x402400是关键:需要找出此地址中存储的字符串,但如何以字符输出数据是个问题,而且字符串长度不确定。

    2. 推断:%eax应该是作为中间寄存器沟通phase_1和strings_not_equal两个函数。

  3. 解决方案:

    (gdb) x/s 402400
    
    0x402400:	"Border relations with Canada have never been better."//答案
    
  4. 知识获取:

    1. examine 命令(简写是 x )来查看内存地址中的值
      x/nfu addr
      
      n 是一个正整数,表示显示内存的长度,从当前地址向后显示几个地址的内容
      f 表示显示的格式:x、d、u、s等
      u 表示从当前地址往后请求的字节数
      

phase_2

  1. 汇编分析

    0000000000400efc <phase_2>:
       400efc:   55                      push   %rbp
       400efd:   53                      push   %rbx
       400efe:   48 83 ec 28             sub    $0x28,%rsp
       400f02:   48 89 e6                mov    %rsp,%rsi
       400f05:   e8 52 05 00 00          call   40145c <read_six_numbers>	#密码是六个数字
       400f0a:   83 3c 24 01             cmpl   $0x1,(%rsp)	#观察因果关系,所以第一个数字应该是1
       400f0e:   74 20                   je     400f30 <phase_2+0x34>
       400f10:   e8 25 05 00 00          call   40143a <explode_bomb>
       400f15:   eb 19                   jmp    400f30 <phase_2+0x34>
       400f17:   8b 43 fc                mov    -0x4(%rbx),%eax	#将前一个数字读出放入%rax寄存器内
       400f1a:   01 c0                   add    %eax,%eax	#2倍
       400f1c:   39 03                   cmp    %eax,(%rbx)	#判定,如果成功继续循环,证明第二个数是第一个数二倍
       400f1e:   74 05                   je     400f25 <phase_2+0x29>
       400f20:   e8 15 05 00 00          call   40143a <explode_bomb>
       400f25:   48 83 c3 04             add    $0x4,%rbx
       400f29:   48 39 eb                cmp    %rbp,%rbx	#循环条件
       400f2c:   75 e9                   jne    400f17 <phase_2+0x1b>	#循环
       400f2e:   eb 0c                   jmp    400f3c <phase_2+0x40>	#循环终止,因为看到400f3c之后直接pop了
       400f30:   48 8d 5c 24 04          lea    0x4(%rsp),%rbx	#%rbx存储下一个数字
       400f35:   48 8d 6c 24 18          lea    0x18(%rsp),%rbp	#类似于设置循环终止条件,不能超过分配的28字节
       400f3a:   eb db                   jmp    400f17 <phase_2+0x1b>	#循环主体
       400f3c:   48 83 c4 28             add    $0x28,%rsp
       400f40:   5b                      pop    %rbx
       400f41:   5d                      pop    %rbp
       400f42:   c3                      ret
    
  2. 思路:

    1. 首先需要大胆猜出第一个数字是1,其次需要勇敢往下尝试(勇敢地走入循环)。
    2. 对%eax寄存器存储的值要时刻关注。
  3. 答案

    1 2 4 8 16 32
    
  4. 知识获取

    1.    400efc:   55                      push   %rbp为什么要push这两个寄存器
         400efd:   53                      push   %rbx
         
         函数A调用了函数B,寄存器rbx在函数B中被修改了,逻辑上%rbx内容在调用函数B的前后应该保持一致,
      解决这个问题有两个策略,
      (1)在函数A在调用函数B之前提前保存寄存器%rbx的内容,执行完函数B之后再恢复%rbx的内容,这个
         策略就称为调用者保存;
      (2)函数B在使用寄存器%rbx,先保存寄存器%rbx的值,在函数B返回之前,要恢复寄存器%rbx原来存储
         的内容,这种策略被称之为被调用者保存。
      

phase_3

  1. 汇编分析

    0000000000400f43 <phase_3>:
       400f43:   48 83 ec 18             sub    $0x18,%rsp
       400f47:   48 8d 4c 24 0c          lea    0xc(%rsp),%rcx	#神秘数字a
       400f4c:   48 8d 54 24 08          lea    0x8(%rsp),%rdx	#神秘数字b
       400f51:   be cf 25 40 00          mov    $0x4025cf,%esi	#关键!!!
       400f56:   b8 00 00 00 00          mov    $0x0,%eax	#p1
       400f5b:   e8 90 fc ff ff          call   400bf0 <__isoc99_sscanf@plt>	#函数调用
       400f60:   83 f8 01                cmp    $0x1,%ea	#p2:判断输入的值是否大于2
       400f63:   7f 05                   jg     400f6a <phase_3+0x27>
       400f65:   e8 d0 04 00 00          call   40143a <explode_bomb>
       400f6a:   83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)
       400f6f:   77 3c                   ja     400fad <phase_3+0x6a>	#说明a值小于7,否则爆炸
       400f71:   8b 44 24 08             mov    0x8(%rsp),%eax	#将a值存入%rax
       400f75:   ff 24 c5 70 24 40 00    jmp    *0x402470(,%rax,8)	#关键!!!
       400f7c:   b8 cf 00 00 00          mov    $0xcf,%eax
       400f81:   eb 3b                   jmp    400fbe <phase_3+0x7b>
       400f83:   b8 c3 02 00 00          mov    $0x2c3,%eax
       400f88:   eb 34                   jmp    400fbe <phase_3+0x7b>
       400f8a:   b8 00 01 00 00          mov    $0x100,%eax
       400f8f:   eb 2d                   jmp    400fbe <phase_3+0x7b>
       400f91:   b8 85 01 00 00          mov    $0x185,%eax
       400f96:   eb 26                   jmp    400fbe <phase_3+0x7b>
       400f98:   b8 ce 00 00 00          mov    $0xce,%eax
       400f9d:   eb 1f                   jmp    400fbe <phase_3+0x7b>
       400f9f:   b8 aa 02 00 00          mov    $0x2aa,%eax
       400fa4:   eb 18                   jmp    400fbe <phase_3+0x7b>
       400fa6:   b8 47 01 00 00          mov    $0x147,%eax
       400fab:   eb 11                   jmp    400fbe <phase_3+0x7b>
       400fad:   e8 88 04 00 00          call   40143a <explode_bomb>
       400fb2:   b8 00 00 00 00          mov    $0x0,%eax
       400fb7:   eb 05                   jmp    400fbe <phase_3+0x7b>
       400fb9:   b8 37 01 00 00          mov    $0x137,%eax
       400fbe:   3b 44 24 0c             cmp    0xc(%rsp),%eax	#比较b和之前存入的值
       400fc2:   74 05                   je     400fc9 <phase_3+0x86	#跳转
       400fc4:   e8 71 04 00 00          call   40143a <explode_bomb>
       400fc9:   48 83 c4 18             add    $0x18,%rsp
       400fcd:   c3                      ret
    
  2. 思路:(菜鸡思路)

    1. 对于神秘数字a和b:请先看下一条;推测出a和b可能存储的是我们输入的两个数字。

    2. 突破口

         400f51:   be cf 25 40 00          mov    $0x4025cf,%esi
         
         (gdb) x/s 0x4025cf  
         0x4025cf "%d %d"
      

      首先我承认我是有蒙的成分在这里,我想看一下这块内存里存入的是什么,然后运用x命令试了亿下,出现能看懂的结果,再结合call了scanf,推测出我们输入的密码会是两个数字。

    3. p1,p2:看到p2时,觉得很奇怪,如果没有任何操作的情况下,这两条指令后半部分表示的内存是等价的,所以在p1时,%eax肯定写入了什么东西,再结合中间的函数调用,所以推出%eax存了scanf的返回值。更加证明了应该输入两个数字。

    4.    400f75:   ff 24 c5 70 24 40 00    jmp    *0x402470(,%rax,8)
         
         (gdb) x/8xg 0x402470//找出跳转表
         0x402470:	0x0000000000400f7c	0x0000000000400fb9
         0x402480:	0x0000000000400f83	0x0000000000400f8a
         0x402490:	0x0000000000400f91	0x0000000000400f98
         0x4024a0:	0x0000000000400f9f	0x0000000000400fa6
      

      这块真是卡了好久,此命令意思为跳转到(8×%rax+0x402470)处,但是眼瞎的我没注意到这个寄存器的名字是 ax,与上一条中的eax是一样的,所以就清楚了,是将b的值乘以8加上首地址(看到那么多mov、jmp应该很容易理解到这是个switch语句,0x402470处是跳转表),接着x,根据结果进行匹配跳转。

  3. 答案(不唯一)

    1 311
    

phase_4

  1. 汇编分析

       0x000000000040100c <+0>:		sub    $0x18,%rsp
       0x0000000000401010 <+4>:		lea    0xc(%rsp),%rcx
       0x0000000000401015 <+9>:		lea    0x8(%rsp),%rdx
       0x000000000040101a <+14>:	mov    $0x4025cf,%esi	#好熟悉
       0x000000000040101f <+19>:	mov    $0x0,%eax
       0x0000000000401024 <+24>:	call   0x400bf0 <__isoc99_sscanf@plt>
       0x0000000000401029 <+29>:	cmp    $0x2,%eax
       0x000000000040102c <+32>:	jne    0x401035 <phase_4+41>	#输入不等于2个数时跳转到bomb
       0x000000000040102e <+34>:	cmpl   $0xe,0x8(%rsp)
       0x0000000000401033 <+39>:	jbe    0x40103a <phase_4+46>	#a小于等于14跳转,否则bomb
       0x0000000000401035 <+41>:	call   0x40143a <explode_bomb>
       0x000000000040103a <+46>:	mov    $0xe,%edx
       0x000000000040103f <+51>:	mov    $0x0,%esi
       0x0000000000401044 <+56>:	mov    0x8(%rsp),%edi	#a-->%edi
       0x0000000000401048 <+60>:	call   0x400fce <func4>
       0x000000000040104d <+65>:	test   %eax,%eax
       0x000000000040104f <+67>:	jne    0x401058 <phase_4+76>	#%eax等于0则不会爆炸
       0x0000000000401051 <+69>:	cmpl   $0x0,0xc(%rsp)
       0x0000000000401056 <+74>:	je     0x40105d <phase_4+81>	#说明b值为0
       0x0000000000401058 <+76>:	call   0x40143a <explode_bomb>
       0x000000000040105d <+81>:	add    $0x18,%rsp
       0x0000000000401061 <+85>:	ret    
       
       
       0x0000000000400fce <+0>:		sub    $0x8,%rsp
       0x0000000000400fd2 <+4>:		mov    %edx,%eax	#14-->%eax
       0x0000000000400fd4 <+6>:		sub    %esi,%eax	#14-0-->%eax
       0x0000000000400fd6 <+8>:		mov    %eax,%ecx	#14-->%ecx
       0x0000000000400fd8 <+10>:	shr    $0x1f,%ecx	#逻辑右移31位%ecx-->0
       0x0000000000400fdb <+13>:	add    %ecx,%eax	#0+14-->%eax
       0x0000000000400fdd <+15>:	sar    %eax	#算术右移1位%eax-->7
       0x0000000000400fdf <+17>:	lea    (%rax,%rsi,1),%ecx	#7-->%ecx
       0x0000000000400fe2 <+20>:	cmp    %edi,%ecx	#a,7
       0x0000000000400fe4 <+22>:	jle    0x400ff2 <func4+36>	#小于等于则跳转
       0x0000000000400fe6 <+24>:	lea    -0x1(%rcx),%edx	#7-1-->%rcx
       0x0000000000400fe9 <+27>:	call   0x400fce <func4>	#递归调用
       0x0000000000400fee <+32>:	add    %eax,%eax	#2倍
       0x0000000000400ff0 <+34>:	jmp    0x401007 <func4+57>	#跳转到出口
       0x0000000000400ff2 <+36>:	mov    $0x0,%eax	#0-->%eax
       0x0000000000400ff7 <+41>:	cmp    %edi,%ecx
       0x0000000000400ff9 <+43>:	jge    0x401007 <func4+57>	#大于等于则跳转
       0x0000000000400ffb <+45>:	lea    0x1(%rcx),%esi
       0x0000000000400ffe <+48>:	call   0x400fce <func4>
       0x0000000000401003 <+53>:	lea    0x1(%rax,%rax,1),%eax
       0x0000000000401007 <+57>:	add    $0x8,%rsp
       0x000000000040100b <+61>:	ret    
    
    
    1. 思路:解题关键就是理清if-else的关系,而%eax只有为0时才不会bomb,所以结合func4函数的结构反推a的值,当然也可以不用推直接看出来7是答案之一。
    我用一种汇编和c结合出语言解释一下func4函数
    
    if(a <= 7)
    {
    	%eax = 0;
    	if(a >= 7)
    	{
    		return;//直接猜出第一个是7
    	}
    	else
    	{
    		0x1(%rcx),%esi;
    		0x400fce <func4>;
    		0x1(%rax,%rax,1),%eax;
    		return;
    	}
    }
    else
    {
    	-0x1(%rcx),%edx
    	0x400fce <func4>;
    	%eax,%eax
    	return;
    }
    

    由于func4函数没有对b进行任何操作,所以根据代码

       0x0000000000401051 <+69>:	cmpl   $0x0,0xc(%rsp)
       0x0000000000401056 <+74>:	je     0x40105d <phase_4+81> #说明b值为0
       0x0000000000401058 <+76>:	call   0x40143a <explode_bomb>
       0x000000000040105d <+81>:	add    $0x18,%rsp
    
  2. 答案

    7 0
    

phase_5

  1. 汇编分析

        0x0000000000401062 <+0>:		push   %rbx
        0x0000000000401063 <+1>:		sub    $0x20,%rsp
        0x0000000000401067 <+5>:		mov    %rdi,%rbx
        0x000000000040106a <+8>:		mov    %fs:0x28,%rax #fs是一个段寄存器,将fs段中偏移量为0x28的值传入rax中
        0x0000000000401073 <+17>:	mov    %rax,0x18(%rsp)
        0x0000000000401078 <+22>:	xor    %eax,%eax #置0
        0x000000000040107a <+24>:	call   0x40131b <string_length>
        0x000000000040107f <+29>:	cmp    $0x6,%eax #%eax存储字符串长度,且必须等于6
        0x0000000000401082 <+32>:	je     0x4010d2 <phase_5+112>
        0x0000000000401084 <+34>:	call   0x40143a <explode_bomb>
       0x0000000000401089 <+39>:	jmp    0x4010d2 <phase_5+112>
        
        0x000000000040108b <+41>:	movzbl (%rbx,%rax,1),%ecx #经测试,%rbx存储的是输入字符串的地址。%rax
        为0,%ecx存储的是输入第一个字符的ASCII码值
        0x000000000040108f <+45>:	mov    %cl,(%rsp) #cx寄存器的低四位存入memory
        0x0000000000401092 <+48>:	mov    (%rsp),%rdx #存入%rdx
        0x0000000000401096 <+52>:	and    $0xf,%edx #低四位和0xf进行与运算
        0x0000000000401099 <+55>:	movzbl 0x4024b0(%rdx),%edx #关键
        0x00000000004010a0 <+62>:	mov    %dl,0x10(%rsp,%rax,1) #将取出的字符存入栈中
        0x00000000004010a4 <+66>:	add    $0x1,%rax #偏移值加1
        0x00000000004010a8 <+70>:	cmp    $0x6,%rax
        0x00000000004010ac <+74>:	jne    0x40108b <phase_5+41> #不等于6,则一直循环
       
        0x00000000004010ae <+76>:	movb   $0x0,0x16(%rsp)
        0x00000000004010b3 <+81>:	mov    $0x40245e,%esi #关键
        0x00000000004010b8 <+86>:	lea    0x10(%rsp),%rdi #取出相对应的字符存入到%rdi
        0x00000000004010bd <+91>:	call   0x401338 <strings_not_equal>
        0x00000000004010c2 <+96>:	test   %eax,%eax
        0x00000000004010c4 <+98>:	je     0x4010d9 <phase_5+119> #相等则跳转
        0x00000000004010c6 <+100>:	call   0x40143a <explode_bomb>
        0x00000000004010cb <+105>:	nopl   0x0(%rax,%rax,1)
        0x00000000004010d0 <+110>:	jmp    0x4010d9 <phase_5+119>
        0x00000000004010d2 <+112>:	mov    $0x0,%eax
        0x00000000004010d7 <+117>:	jmp    0x40108b <phase_5+41>
        0x00000000004010d9 <+119>:	mov    0x18(%rsp),%rax
        0x00000000004010de <+124>:	xor    %fs:0x28,%rax
        0x00000000004010e7 <+133>:	je     0x4010ee <phase_5+140>
        0x00000000004010e9 <+135>:	call   0x400b30 <__stack_chk_fail@plt>
        0x00000000004010ee <+140>:	add    $0x20,%rsp
        0x00000000004010f2 <+144>:	pop    %rbx
        0x00000000004010f3 <+145>:	ret   
    
  2. 思路

    (gdb) x/s 0x4024b0
    0x4024b0 <array.3449>:"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"字符串1
    
    
    (gdb) x/s 0x40245e
    0x40245e:	"flyers"//字符串2
    
    这道题的意思是输入六个字符,将对应的ASCII码的二进制低四位取成一个数字作为一个偏移量,再根据各个偏移量在字符串1中找出对应的字符,找出来的字符应该是字符串2.
    
    flyers  --> 9 15 14 5 6 7(对应字符串1的位置)
    
    ch[1] & 0xf = 9
    ch[2] & 0xf = 15
    ....
    ch[6] & 0xf = 7
    
    9 --> 1001 --> 0100 1001 --> I <-- ch[1]
    ........(其实只要是后四位是1001就可以,但是为了方便,将前四位选择0100,来控制对应的字符是英文字母)
    
  3. 答案(不唯一)

    IONEFG
    

phase_6

  1. 汇编分析(测试数字1 2 3 4 5 6)

       0x00000000004010f4 <+0>:		push   %r14
       0x00000000004010f6 <+2>:		push   %r13
       0x00000000004010f8 <+4>:		push   %r12
       0x00000000004010fa <+6>:		push   %rbp
       0x00000000004010fb <+7>:		push   %rbx
       0x00000000004010fc <+8>:		sub    $0x50,%rsp	
       0x0000000000401100 <+12>:	mov    %rsp,%r13	#rsp --> r13
       0x0000000000401103 <+15>:	mov    %rsp,%rsi	#rsp --> rsi
       0x0000000000401106 <+18>:	call   0x40145c <read_six_numbers>	#6个数字
       0x000000000040110b <+23>:	mov    %rsp,%r14	#rsp --> r14
       0x000000000040110e <+26>:	mov    $0x0,%r12d	#0 --> r12d
       ------------------------------------------------------------------------------
       0x0000000000401114 <+32>:	mov    %r13,%rbp	#rsp --> r13 --> rbp -- num[1]
       0x0000000000401117 <+35>:	mov    0x0(%r13),%eax	#经检查eax存储的是输入是数字
       0x000000000040111b <+39>:	sub    $0x1,%eax	#num[1] - 1
       0x000000000040111e <+42>:	cmp    $0x5,%eax	#num[1] - 1 <= 5  
       0x0000000000401121 <+45>:	jbe    0x401128 <phase_6+52>
       0x0000000000401123 <+47>:	call   0x40143a <explode_bomb>
       0x0000000000401128 <+52>:	add    $0x1,%r12d	#r12d:0 --> 1
       0x000000000040112c <+56>:	cmp    $0x6,%r12d	
       0x0000000000401130 <+60>:	je     0x401153 <phase_6+95>	#等于6则跳转
       0x0000000000401132 <+62>:	mov    %r12d,%ebx	#r12d --> ebx -- 1
       -----------------------------------------------------------------------------
       0x0000000000401135 <+65>:	movslq %ebx,%rax	#ebx --> rax -- 1
       0x0000000000401138 <+68>:	mov    (%rsp,%rax,4),%eax	#(sp + 1×4) --> eax -- num[2]
       0x000000000040113b <+71>:	cmp    %eax,0x0(%rbp)	
       0x000000000040113e <+74>:	jne    0x401145 <phase_6+81>	#num[1] ≠ num[2] 则跳转  
       0x0000000000401140 <+76>:	call   0x40143a <explode_bomb>
       0x0000000000401145 <+81>:	add    $0x1,%ebx	#1 + ebx -- 1 + 1 -- 2
       0x0000000000401148 <+84>:	cmp    $0x5,%ebx	
       0x000000000040114b <+87>:	jle    0x401135 <phase_6+65>	#ebx ≠ 5则跳转
       -----------------------------------------------------------------------------
       0x000000000040114d <+89>:	add    $0x4,%r13	#r13 + 4
       0x0000000000401151 <+93>:	jmp    0x401114 <phase_6+32>	#循环
       -----------------------------------------------------------------------------
       0x0000000000401153 <+95>:	lea    0x18(%rsp),%rsi	#rsi指向栈的某一位置	
       0x0000000000401158 <+100>:	mov    %r14,%rax	#r14 --> rax
       0x000000000040115b <+103>:	mov    $0x7,%ecx	#7 --> ecx
       0x0000000000401160 <+108>:	mov    %ecx,%edx	#ecx --> edx --7
       0x0000000000401162 <+110>:	sub    (%rax),%edx	#7 - (%rax)
       0x0000000000401164 <+112>:	mov    %edx,(%rax)	#edx --> (rax)
       0x0000000000401166 <+114>:	add    $0x4,%rax	#rax + 4 --指向下一个数字
       0x000000000040116a <+118>:	cmp    %rsi,%rax	#循环终止条件
       0x000000000040116d <+121>:	jne    0x401160 <phase_6+108>	#不等则跳转
       ----------------------------------------------------------------------------
       0x000000000040116f <+123>:	mov    $0x0,%esi	#置0
       0x0000000000401174 <+128>:	jmp    0x401197 <phase_6+163>
       ----------------------------------------------------------------------------
       0x0000000000401176 <+130>:	mov    0x8(%rdx),%rdx	#将下一节点的指针存入rdx
       0x000000000040117a <+134>:	add    $0x1,%eax
       0x000000000040117d <+137>:	cmp    %ecx,%eax
       0x000000000040117f <+139>:	jne    0x401176 <phase_6+130>	#不等则跳转
       ---------------------------------------------------------------------------
       0x0000000000401181 <+141>:	jmp    0x401188 <phase_6+148>	#开始重复进行
       0x0000000000401183 <+143>:	mov    $0x6032d0,%edx	#edx存储链表首地址 
       0x0000000000401188 <+148>:	mov    %rdx,0x20(%rsp,%rsi,2)	#rdx --> (rsp+rsi*2)+32
       0x000000000040118d <+153>:	add    $0x4,%rsi	#rsi + 4
       0x0000000000401191 <+157>:	cmp    $0x18,%rsi
       0x0000000000401195 <+161>:	je     0x4011ab <phase_6+183>	#rsi = 24时跳转
       0x0000000000401197 <+163>:	mov    (%rsp,%rsi,1),%ecx	#将rsp指向的值传给ecx
       0x000000000040119a <+166>:	cmp    $0x1,%ecx	
       0x000000000040119d <+169>:	jle    0x401183 <phase_6+143>	#ecx小于等于1则跳转
       0x000000000040119f <+171>:	mov    $0x1,%eax 	#当大于1时,1 --> eax
       0x00000000004011a4 <+176>:	mov    $0x6032d0,%edx	#链表首地址存入edx
       0x00000000004011a9 <+181>:	jmp    0x401176 <phase_6+130>
       
       #将第{7-num[i]}个节点的地址存入到0x20(%rsp+%rsi*2)栈中,中间会为指针空出位置
       ------------------------------------------------------------------------------
       0x00000000004011ab <+183>:	mov    0x20(%rsp),%rbx	#rbx约定为初节点
       0x00000000004011b0 <+188>:	lea    0x28(%rsp),%rax	#rax约定为下一个节点
       0x00000000004011b5 <+193>:	lea    0x50(%rsp),%rsi	#循环结束条件
       0x00000000004011ba <+198>:	mov    %rbx,%rcx	
       -----------------------------------------------------------------------------
       0x00000000004011bd <+201>:	mov    (%rax),%rdx	#下一个节点的值放入rdx
       0x00000000004011c0 <+204>:	mov    %rdx,0x8(%rcx)	#rcx指向下一个节点
       0x00000000004011c4 <+208>:	add    $0x8,%rax	#下一个数据
       0x00000000004011c8 <+212>:	cmp    %rsi,%rax	#判断循环是否结束
       0x00000000004011cb <+215>:	je     0x4011d2 <phase_6+222>
       0x00000000004011cd <+217>:	mov    %rdx,%rcx	#rcx后移
       0x00000000004011d0 <+220>:	jmp    0x4011bd <phase_6+201>
       -----------------------------------------------------------------------------
       0x00000000004011d2 <+222>:	movq   $0x0,0x8(%rdx)	#尾节点中的指针指向NULL
       0x00000000004011da <+230>:	mov    $0x5,%ebp	
       ----------------------------------------------------------------------------
       0x00000000004011df <+235>:	mov    0x8(%rbx),%rax	#将rax指向rbx下一个链表结点
       0x00000000004011e3 <+239>:	mov    (%rax),%eax
       0x00000000004011e5 <+241>:	cmp    %eax,(%rbx)	#比较每个节点中value的大小
       0x00000000004011e7 <+243>:	jge    0x4011ee <phase_6+250>	#前大于后则跳转,否则bomb
       0x00000000004011e9 <+245>:	call   0x40143a <explode_bomb>	
       0x00000000004011ee <+250>:	mov    0x8(%rbx),%rbx	#rbx向后移动,为了使它降序排列
       0x00000000004011f2 <+254>:	sub    $0x1,%ebp	
       0x00000000004011f5 <+257>:	jne    0x4011df <phase_6+235>	#循环
       -------------------------------------------------------------------------------
       0x00000000004011f7 <+259>:	add    $0x50,%rsp
       0x00000000004011fb <+263>:	pop    %rbx
       0x00000000004011fc <+264>:	pop    %rbp
       0x00000000004011fd <+265>:	pop    %r12
       0x00000000004011ff <+267>:	pop    %r13
       0x0000000000401201 <+269>:	pop    %r14
       0x0000000000401203 <+271>:	ret    
       
       
       条件统计:
       num[1] - 1 <= 5
       num[1] ≠ num[2]
    
    
  2. 思路

    (gdb) x/20 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
    
    (gdb) x/20 6304480
    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//尾节点
    
    我们看到0x6032d0,标记出node,所以想到了这是个链表,而相邻节点差16字节,所以时前8字节存储value,后八字节存储*next
    

    这个程序干了什么呢?

    1. 存储了6个数字,且每个数字大于0小于6
    2. 将6个数字变成7-num[i]
    3. 将第(7-num[i])个链表元素根据相对位置存入栈中
    4. 将节点链接起来,单向链表
    5. 检测数值是否符合降序
    
  3. 答案

    根据链表的前四字节存储的值,我们降序排序
    node[3]>node[4]>node[5]>node[6]>node[1]>node[2]
    
    3 4 5 6 1 2
    
    又因为上面的值为(7-num[i])
    
    4 3 2 1 6 5(最终答案)