【计算机系统基础bomb lab】CSAPP实验:Bomb Lab

CSAPP 实验:Bomb Lab

实验内容简述

  • 作为实验目标的二进制炸弹 “Bomb Lab” Linux可执行程序包含了多个阶段(或关卡),在每个阶段程序要求输入一-个特定字符串,如果输入满足程序代码所定义的要求,该阶段的炸弹就被拆除了,否则程序输出 “炸弹爆炸BOOM!!!” 的提示并转到下一阶段再次等待对应的输入-实验的目标是设法得出解除尽可能多阶段的字符串。
  • 为完成二进制炸弹拆除任务,需要通过反汇编并分析可执行炸弹文件程序的机器代码或使用 gdb 调试器跟踪机器代码的执行,从中理解关键机器指令的行为和作用,进而设法推断拆除炸弹所需的目标字符串。

实验环境

64 位 linux 操作系统

实验过程:phase 1

  • 将可执行文件bomb 反汇编

    objdump -d bomb > bomb.asm
    
  • 查看源代码

    image-20220727104850796

    可以了解到 phase_1 是调用函数名

  • bomb.asm 里搜索 phase_1,阅读源码含义

    image-20220727105926060

phase 1 调试过程

  • 使用 gdb 调试,将断点设置在 phase_1 ,即 0x400ee0。运行后随便输入后查看 0x402400 的内容

    (gdb) b *0x400ee0
    Breakpoint 1 at 0x400ee0
    (gdb) r
    Starting program: /mnt/d/OneDrive/csapp/bomb/bomb 
    Welcome to my fiendish little bomb. You have 6 phases with
    which to blow yourself up. Have a nice day!
    dsasd 
    
    Breakpoint 1, 0x0000000000400ee0 in phase_1 ()
    (gdb) i r rip
    rip            0x400ee0            0x400ee0 <phase_1>
    (gdb) si
    0x0000000000400ee4 in phase_1 ()
    (gdb) si
    0x0000000000400ee9 in phase_1 ()
    (gdb) x/s 0x402400
    0x402400:       "Border relations with Canada have never been better."
    

    image-20220727111507095

  • 可以从上面了解到字符串的答案就是: Border relations with Canada have never been better.

实验过程:phase 2

  • 查看 phase 2 汇编代码

    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       	callq  40145c <read_six_numbers>;读取六个数字
      400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp);拿第一个数字与 1 进行比较
      400f0e:	74 20                	je     400f30 <phase_2+0x34>;如果相等就跳转到 400f30
      400f10:	e8 25 05 00 00       	callq  40143a <explode_bomb>;否则,爆炸
      400f15:	eb 19                	jmp    400f30 <phase_2+0x34>
      400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax ;将第一个数字赋给 eax
      400f1a:	01 c0                	add    %eax,%eax;将第一个数字*2
      400f1c:	39 03                	cmp    %eax,(%rbx);将当前数字(eax) 与后一个数字 (rbx) 比较
      400f1e:	74 05                	je     400f25 <phase_2+0x29>;如果相等,就跳转到400f25
      400f20:	e8 15 05 00 00       	callq  40143a <explode_bomb>;否则爆炸
      400f25:	48 83 c3 04          	add    $0x4,%rbx;循环迭代条件
      400f29:	48 39 eb             	cmp    %rbp,%rbx;rbp 是栈底,也就是数组最后一个元素,作为循环判断的最后一个条件
      400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>;如果没遍历到最后一个数字,就跳转到循环内400f17
      400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>;循环结束,跳转到最后函数结束后的处理400f3c
      400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx ;将第二个数赋值给 rbx
      400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp ;设置栈底,就是最后一个数字(0x18 == 24,输入的是6个数,所以是最后一个数)
      400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>;跳到 400f17 进入循环开始的地方
      ----------------------分割线----------------------------------------;之后都是函数结束后的处理
      400f3c:	48 83 c4 28          	add    $0x28,%rsp
      400f40:	5b                   	pop    %rbx
      400f41:	5d                   	pop    %rbp
      400f42:	c3                   	retq  
    

phase 2 调试过程

  • 设置断点

    (gdb) b phase_2
    Breakpoint 1 at 0x400efc
    
  • 运行并输入phase 1 的答案与 phase 2 推测出的答案

    image-20220730105854670

  • 一直单步汇编运行,执行到 400f0a: cmpl $0x1,(%rsp); 此步说明第一个数字必须为1

    image-20220730111649035

  • 比较第一个数字是否为 1

    (gdb) x/wd $rsp
    0x7ffffffedd70: 1
    

    可以看到,rsp 的值为1 ,就是我们输入的第一个值:1

    由此,通过 je 400f30 可知,两数相等,故跳转到 400f30

    image-20220730111959643

  • 通过单步汇编调试,查看rsp 的值

    (gdb) si
    0x0000000000400f30 in phase_2 ()
    (gdb) si
    0x0000000000400f35 in phase_2 ()
    

    image-20220730112217810

    由此可以得出,rbx 此时存放的是第二个数字 2rbp 作为栈底,是最后一个数字的结尾,存放的是 4199473 这个数字。

  • 继续单步汇编调试,进入循环400f17

    image-20220730112624184

    此时执行完 400f17:mov -0x4(%rbx),%eax eax` 的值为 1。如下图

    image-20220730113150925

    继续单步调试,执行到 add %eax,%eax ,对 eax进行 乘 2 的操作。 此时 eax 为2 ,与我们输入的第二个数( rbx 存放) 相等

    image-20220730113939792

    image-20220730114119156

  • 继续单步汇编调试,跳转到 400f25:add $0x4,%rbx

    image-20220730114459317

    image-20220730114515282

    执行完 add $0x4,%rbx ,则选择了数组的下一个数字,判断循环是否是否结束。

  • 之后一直执行到结束。

    image-20220730135934202

  • 所以答案为:1 2 4 8 16 32

实验过程:phase 3

  • 查看 phase_3 汇编代码:
0000000000400f43 <phase_3>:
  400f43:	48 83 ec 18          	sub    $0x18,%rsp
  400f47:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx ;第二个参数
  400f4c:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx ;第一个参数
  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi ;系统自带字符串"%d %d",2个参数
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  ;----------------------------------------------------------------
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  400f60:	83 f8 01             	cmp    $0x1,%eax ;eax 与 1 比较。返回的是输入的参数个数
  400f63:	7f 05                	jg     400f6a <phase_3+0x27> ;如果大于 1,跳转400f6a
  400f65:	e8 d0 04 00 00       	callq  40143a <explode_bomb>
  400f6a:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp) ;比较 7 与 第一个参数大小
  400f6f:	77 3c                	ja     400fad <phase_3+0x6a> ;如果第一个参数大于7,爆炸
  400f71:	8b 44 24 08          	mov    0x8(%rsp),%eax ;把第一个参数赋给 eax
  400f75:	ff 24 c5 70 24 40 00 	jmpq   *0x402470(,%rax,8) ;跳转到 rax*8 + *0x402470
  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       	callq  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 ;eax 为311(十进制)
  400fbe:	3b 44 24 0c          	cmp    0xc(%rsp),%eax ;比较第二个参数与 eax
  400fc2:	74 05                	je     400fc9 <phase_3+0x86>;如果成功,拆弹成功
  400fc4:	e8 71 04 00 00       	callq  40143a <explode_bomb>
  ;----------------------------------------------------------------
  400fc9:	48 83 c4 18          	add    $0x18,%rsp
  400fcd:	c3                   	retq   

分析:

我这个都是自己调试出来看到参数的,最开始第一个参数与第二个参数理解有误。结果最开始输入的竟然是第二个参数

首先看到了调用函数是 __isoc99_sscanf 可以从中得知,返回的 eax 为输入格式的个数,而最开始 0x4025cf 的字符串就是 %d %d,可以了解到参数个数为 2 。

之后让第一个参数与 7 比较,可以猜到第一个参数是一个选择做一个选择,选择是下面7个跳转(类似于 switch)。

最后可以在 400f75:jmpq *0x402470(,%rax,8) 观测,程序的跳转地址情况。

phase 3 调试过程

  • 设置断点并运行

    此时的 ans.txt如下:

    Border relations with Canada have never been better.
    1 2 4 8 16 32
    1 311
    
    

    image-20220730172753721

  • 单步汇编调试,直到执行完 400f5b:callq 400bf0 <__isoc99_sscanf@plt>

    image-20220730203508519

  • 单步汇编调试,执行到 400f75:jmpq *0x402470(,%rax,8),观察对应 0x402470 开始的 8 个单元对应的值。

    image-20220731104055183

    rax 保存的是第一个参数的值,我们输入的是 1,所以计算机结果是 0x402470 + 1 * 80x402478 单元对应的值 0x400fb9

  • 单步汇编调试,验证进入的单元。

    image-20220731104919753

  • 要使第一个第二个参数与 0x137相等,即十进制 311,最后拆除炸弹。

    image-20220731105331630

实验过程:phase 4

0000000000400fce <func4>:
  400fce:	48 83 ec 08          	sub    $0x8,%rsp
  400fd2:	89 d0                	mov    %edx,%eax ;eax = 14 (phase_4 输入的第三个参数)
  400fd4:	29 f0                	sub    %esi,%eax ;eax = 14 - 0 = 14 (第二个参数减去第三个参数)
  400fd6:	89 c1                	mov    %eax,%ecx ;ecx = 14
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx;逻辑右移31 位,ecx 为0
  400fdb:	01 c8                	add    %ecx,%eax ;eax = 14
  400fdd:	d1 f8                	sar    %eax ;算术右移1位,即÷2  eax = 7
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx ;ecx = 7
  400fe2:	39 f9                	cmp    %edi,%ecx ;比较第一传入参数与 ecx = 7
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24> ;如果小于等于7,跳转400ff2
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx ;
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax ;eax = 0
  400ff7:	39 f9                	cmp    %edi,%ecx ;比较 7 与第一个传入参数的大小
  400ff9:	7d 0c                	jge    401007 <func4+0x39>;如果第一个传入参数的大小大于等于7就正常返回
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401007:	48 83 c4 08          	add    $0x8,%rsp
  40100b:	c3                   	retq    
  
000000000040100c <phase_4>:
  40100c:	48 83 ec 18          	sub    $0x18,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx;第二个参数
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx;第一个参数
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi;"%d %d"
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  ;------------------------------------------------------------------------------------------
  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax;输入的参数个数是不是两个
  40102c:	75 07                	jne    401035 <phase_4+0x29>;不是,爆炸
  40102e:	83 7c 24 08 0e       	cmpl   $0xe,0x8(%rsp);将第一个参数和 0xe 比较
  401033:	76 05                	jbe    40103a <phase_4+0x2e>;如果小于等于,就继续
  401035:	e8 00 04 00 00       	callq  40143a <explode_bomb>;否则爆炸
  40103a:	ba 0e 00 00 00       	mov    $0xe,%edx;调用函数第三个传入的实参,14
  40103f:	be 00 00 00 00       	mov    $0x0,%esi;调用函数第二个传入实参,0
  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi;调用函数第一个传入实参,也是输入的第一个参数
  401048:	e8 81 ff ff ff       	callq  400fce <func4>
  40104d:	85 c0                	test   %eax,%eax ;递归返回值为0
  40104f:	75 07                	jne    401058 <phase_4+0x4c>;否则爆炸
  401051:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp) ;经过func4 递归后,输入的第二个参数应为0 
  401056:	74 05                	je     40105d <phase_4+0x51>;第二个参数不为0就爆炸
  401058:	e8 dd 03 00 00       	callq  40143a <explode_bomb>
  ;------------------------------------------------------------------------------------------
  40105d:	48 83 c4 18          	add    $0x18,%rsp
  401061:	c3                   	retq   

分析:

首先从callq 400bf0 <__isoc99_sscanf@plt> 可以知道又是调用sscanf,上面的内容就是输入的参数。 401010:lea 0xc(%rsp),%rcx401015:lea 0x8(%rsp),%rdx 可以得知,这是传入的第二个和第一个参数,传入的是两个参数。

之后从 40103a:mov $0xe,%edx 可以得知,接下来这三行都是传递实参,为调用 func4 做准备。 func4 被调用的过程可以分析出第一个数字小于等于7,之后完成以后回到 phase_4401051:cmpl $0x0,0xc(%rsp) 可以得知第二个参数为 0。故测试以下 7 0

phase 4 调试过程

  • 设置断点,并运行至 phase_4

    此时的 ans.txt如下:

    Border relations with Canada have never been better.
    1 2 4 8 16 32
    1 311
    7 0
    
    

    image-20220802151932815

  • 执行到调用 func4 的位置,中间确认输入参数

    image-20220803145124535

  • 重点是 func4 的实现,这个过程需要的确定各个寄存器的值是否符合预期

    image-20220803150218152

  • 最后拆弹成功

    image-20220803150307235

实验过程:phase 5

0000000000401062 <phase_5>:
  401062:	53                   	push   %rbx
  401063:	48 83 ec 20          	sub    $0x20,%rsp
  401067:	48 89 fb             	mov    %rdi,%rbx ;第一个参数 -> rbx
  40106a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax ;接下来4行汇编是栈哨兵的检查(栈的保护机制,在编译时加上 -fno-stack-protector 就会被取消)
  401071:	00 00 
  401073:	48 89 44 24 18       	mov    %rax,0x18(%rsp) ;将哨兵的值赋值到栈里
  401078:	31 c0                	xor    %eax,%eax ;如果 eax 不为0,则说明栈被破坏
  ;---------------------------------------------------------------------------------
  40107a:	e8 9c 02 00 00       	callq  40131b <string_length> ;判断字符串长度
  40107f:	83 f8 06             	cmp    $0x6,%eax ;字符串长度必须为6
  401082:	74 4e                	je     4010d2 <phase_5+0x70>
  401084:	e8 b1 03 00 00       	callq  40143a <explode_bomb>
  401089:	eb 47                	jmp    4010d2 <phase_5+0x70>
  40108b:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx ;ecx = Mem[rbx + rax(0) * 1] 此时ecx 指向字符串第一个字符a
  40108f:	88 0c 24             	mov    %cl,(%rsp) ;取字符串的低8位值入栈
  
  401092:	48 8b 14 24          	mov    (%rsp),%rdx ;输入字符串作为值(具体的ascii),之后在一长串字符串将输入字符串的值作为偏移量
  401096:	83 e2 0f             	and    $0xf,%edx ;与1111 取与运算后作为偏移量,也就是取低4位
  401099:	0f b6 92 b0 24 40 00 	movzbl 0x4024b0(%rdx),%edx ;edx = 'a' 0x4024b0 = "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
  ;分别取第10位 f(I:74->0100 1001), 第 16 位 l(O:79->0100 1111), 第 15 位 y(N:78->0100 1110),第 6 位 e(E:69->0100 0101),第 7 位 r(F:70->0100 0110),第 8 位 s(G:71->0100 0111)
  4010a0:	88 54 04 10          	mov    %dl,0x10(%rsp,%rax,1) ;rax = 0
  4010a4:	48 83 c0 01          	add    $0x1,%rax ;rax = 1
  4010a8:	48 83 f8 06          	cmp    $0x6,%rax ;循环终止的判断条件
  4010ac:	75 dd                	jne    40108b <phase_5+0x29>
  4010ae:	c6 44 24 16 00       	movb   $0x0,0x16(%rsp)
  4010b3:	be 5e 24 40 00       	mov    $0x40245e,%esi ;第二个传入参数 0x40245e = "flyers"
  4010b8:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi ;第一个传入参数,rdi 0x10(%rsp)是保存的我们输入的地址,上面的操作就是将每个字符串赋值到0x10(%rsp)起始的地址单元里面
  4010bd:	e8 76 02 00 00       	callq  401338 <strings_not_equal> ;要使得二者相等
  4010c2:	85 c0                	test   %eax,%eax
  4010c4:	74 13                	je     4010d9 <phase_5+0x77> ;相等就结束
  4010c6:	e8 6f 03 00 00       	callq  40143a <explode_bomb>
  4010cb:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  4010d0:	eb 07                	jmp    4010d9 <phase_5+0x77>
  4010d2:	b8 00 00 00 00       	mov    $0x0,%eax ;初始化 eax 为0 
  4010d7:	eb b2                	jmp    40108b <phase_5+0x29>
  ;---------------------------------------------------------------------------------
  4010d9:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  4010de:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4010e5:	00 00 
  4010e7:	74 05                	je     4010ee <phase_5+0x8c>
  4010e9:	e8 42 fa ff ff       	callq  400b30 <__stack_chk_fail@plt>
  4010ee:	48 83 c4 20          	add    $0x20,%rsp
  4010f2:	5b                   	pop    %rbx
  4010f3:	c3                   	retq   

分析:

首先能够判断是要输入 6 个字符串,然后随便输入6个字符进行调试,建议使用规律不同的字符串,这样能够知道传递的参数位置。我使用的是 abcdef

接着当代码运行到 40108b:movzbl (%rbx,%rax,1),%ecx 以后,表示程序进入到循环体内,最后退出的条件是 rax == 6 ,而 rax 的初始值为 0, 这个意思就是遍历完我们输入的字符串,循环体内的意思是取我们输入字符的值的低四位的值,我们输入的是字符,也就是该字符对应 ascii 码的低四位。然后利用这个值作为一个索引,去 0x4024b0 这个长的字符串中寻找 flyers 对应的下标,注意我注释里面添加说明的是第几位,但是具体下标要-1操作。

当代码运行到 4010b3:mov $0x40245e,%esi 的时候,可以看到这个就是在传递参数了,作为第二个实参,是系统赋予的,要将这个字符串flyers0x10(%rsp) 的值(也就是上面提及到的低四位ascii码作为索引取出来的字符)进行比较,必须要二者相等。

综上,得出更新的ans.txt

Border relations with Canada have never been better.
1 2 4 8 16 32
1 311
7 0
IONEFG

phase 5 调试过程

  • 设置断点在 phase_5 并运行

    image-20220804164357374

  • 运行到进入循环体 40108b:movzbl (%rbx,%rax,1),%ecx

    image-20220804165103007

    可以看到movzbl (%rbx,%rax,1),%ecx,注意 rbx 最开始就用存储输入的字符串,此时rax作为循环体初始变量 为 0。

  • 执行到 401096 以后,完成了取第一个值的低四位的目的,此时再查看取到值是否为 I 的低四位 ascii 码的值 9

    image-20220804165345097

    可以看到值为 9,证明计算没错,之后可以直接运行 n,直到结束。

  • 运行 n,直接验证是否正确

    image-20220804165447748

实验过程:phase 6

实在是太长了,暂时放弃😞

00000000004010f4 <phase_6>:
  4010f4:	41 56                	push   %r14
  4010f6:	41 55                	push   %r13
  4010f8:	41 54                	push   %r12
  4010fa:	55                   	push   %rbp
  4010fb:	53                   	push   %rbx
  4010fc:	48 83 ec 50          	sub    $0x50,%rsp
  401100:	49 89 e5             	mov    %rsp,%r13
  401103:	48 89 e6             	mov    %rsp,%rsi
  401106:	e8 51 03 00 00       	callq  40145c <read_six_numbers>;读取六个数
  ;------------------------------------------------------------------------------------
  40110b:	49 89 e6             	mov    %rsp,%r14 ;r14 最后一个数地址
  40110e:	41 bc 00 00 00 00    	mov    $0x0,%r12d 
  401114:	4c 89 ed             	mov    %r13,%rbp
  401117:	41 8b 45 00          	mov    0x0(%r13),%eax ;第一个数字
  40111b:	83 e8 01             	sub    $0x1,%eax ; eax是返回的值的大小
  40111e:	83 f8 05             	cmp    $0x5,%eax ; 第一个数字小于等于5就继续
  401121:	76 05                	jbe    401128 <phase_6+0x34> 
  401123:	e8 12 03 00 00       	callq  40143a <explode_bomb> 
  401128:	41 83 c4 01          	add    $0x1,%r12d ; 循环迭代器 i
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d ; 循环体,条件为6
  401130:	74 21                	je     401153 <phase_6+0x5f> 
  401132:	44 89 e3             	mov    %r12d,%ebx
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  40113b:	39 45 00             	cmp    %eax,0x0(%rbp)
  40113e:	75 05                	jne    401145 <phase_6+0x51>
  401140:	e8 f5 02 00 00       	callq  40143a <explode_bomb>
  401145:	83 c3 01             	add    $0x1,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>
  40114d:	49 83 c5 04          	add    $0x4,%r13
  401151:	eb c1                	jmp    401114 <phase_6+0x20>
  ; ---------------------------------------------------------------------
  ; 循环分析比较麻烦,401151会跳转到401114这个是最外层,完成了%r13 + 0x4。即arr++
  ; %13初始的时候是数组首地址。
  ;  按照思路逻辑如下
  ;  for( i=0;i<6;i++ ){
  ;      if(arr[i] - 1 > 5) bomb()
  ;      for(j=i+1;j<=5;j++){
  ;          if(arr[j] == arr[i]) bomb()
  ;      }
  ;  }
  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi 
  401158:	4c 89 f0             	mov    %r14,%rax
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx
  401160:	89 ca                	mov    %ecx,%edx
  401162:	2b 10                	sub    (%rax),%edx
  401164:	89 10                	mov    %edx,(%rax)
  401166:	48 83 c0 04          	add    $0x4,%rax
  40116a:	48 39 f0             	cmp    %rsi,%rax
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>
; -----------------------------------------------------------------
; rsi的值为rsp+0x18 = rsp+0x4*6即数组的结束位置。
; %rax = %r14往前看,是输入的数组首地址。
; 
; for(int i=0;i<6;i++){
;     arr[i] = 7 - arr[i];
; }
  40116f:	be 00 00 00 00       	mov    $0x0,%esi
  401174:	eb 21                	jmp    401197 <phase_6+0xa3>
  401176:	48 8b 52 08          	mov    0x8(%rdx),%rdx
  40117a:	83 c0 01             	add    $0x1,%eax
  40117d:	39 c8                	cmp    %ecx,%eax
  40117f:	75 f5                	jne    401176 <phase_6+0x82>
  401181:	eb 05                	jmp    401188 <phase_6+0x94>

  401183:	ba d0 32 60 00       	mov    $0x6032d0,%edx

  401188:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:	48 83 c6 04          	add    $0x4,%rsi
  401191:	48 83 fe 18          	cmp    $0x18,%rsi
  401195:	74 14                	je     4011ab <phase_6+0xb7>

  401197:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx
  40119a:	83 f9 01             	cmp    $0x1,%ecx
  40119d:	7e e4                	jle    401183 <phase_6+0x8f>
  40119f:	b8 01 00 00 00       	mov    $0x1,%eax
  4011a4:	ba d0 32 60 00       	mov    $0x6032d0,%edx
  4011a9:	eb cb                	jmp    401176 <phase_6+0x82>
  ; --------------------------------------------------------------------------
  ; 借助流程图分析我们得到如下逻辑伪代码
  ; for(int i=0;i<6;i++){
  ;     int cnt = arr[i];
  ;     int add = 0x6032d0;
  ;     for(int j=1;j<arr[i];j++){
  ;         add = *(add+8);
  ;     *(rsp + 2*i + 0x20) = add;  // 8 字节 
  ; }
  ; 查看下*(add+8)中的数据
  ; (gdb) x 0x6032d0+0x8
  ; 0x6032d8 <node1+8>:   0x006032e0
  ; (gdb) x 0x6032e0+0x8 
  ; 0x6032e8 <node2+8>:   0x006032f0
  ; (gdb) x 0x6032f0+0x8
  ; 0x6032f8 <node3+8>:   0x00603300
  ; (gdb) x 0x603300+0x8
  ; 0x603308 <node4+8>:   0x00603310
  ; (gdb) x 0x603310+0x8
  ; 0x603318 <node5+8>:   0x00603320
  4011ab:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx
  4011b0:	48 8d 44 24 28       	lea    0x28(%rsp),%rax
  4011b5:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi
  4011ba:	48 89 d9             	mov    %rbx,%rcx
  4011bd:	48 8b 10             	mov    (%rax),%rdx
  4011c0:	48 89 51 08          	mov    %rdx,0x8(%rcx)
  4011c4:	48 83 c0 08          	add    $0x8,%rax
  4011c8:	48 39 f0             	cmp    %rsi,%rax
  4011cb:	74 05                	je     4011d2 <phase_6+0xde>
  4011cd:	48 89 d1             	mov    %rdx,%rcx
  4011d0:	eb eb                	jmp    4011bd <phase_6+0xc9>
  ;   --------------------------------------------------------------- 
  ; narr 数组存放数据范围上面分析为 0x6032d0 - 0x603320 
  ; int *narr = {};
  ; for(int i=1;i<6;i++){
  ;     *(narr[i-1]+0x8) = narr[i]
  ; }
  ; 将narr[i-1]+0x8内存地址数据存放为narr[i]
  4011d2:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)
  4011d9:	00 
  4011da:	bd 05 00 00 00       	mov    $0x5,%ebp
  4011df:	48 8b 43 08          	mov    0x8(%rbx),%rax
  4011e3:	8b 00                	mov    (%rax),%eax
  4011e5:	39 03                	cmp    %eax,(%rbx)
  4011e7:	7d 05                	jge    4011ee <phase_6+0xfa>
  4011e9:	e8 4c 02 00 00       	callq  40143a <explode_bomb> 
  4011ee:	48 8b 5b 08          	mov    0x8(%rbx),%rbx 
  4011f2:	83 ed 01             	sub    $0x1,%ebp
  4011f5:	75 e8                	jne    4011df <phase_6+0xeb>
  ;----------------------------------------------------------------------------------------
; eax    :  *(narr[0]+0x8) => narr[1] => *(narr[1])
; (%rbx) :  *(narr[0])
; for(int i=1;i<=5;i++){
;     if( *(narr[i-1]) < *(narr[i]) ) bomb()        
; }
  4011f7:	48 83 c4 50          	add    $0x50,%rsp
  4011fb:	5b                   	pop    %rbx
  4011fc:	5d                   	pop    %rbp
  4011fd:	41 5c                	pop    %r12
  4011ff:	41 5d                	pop    %r13
  401201:	41 5e                	pop    %r14
  401203:	c3                   	retq   

一些其他收获

  • 下载一些 cmucode

    wget -r -np -nH --cut-dirs=3 -R index.html 网站地址
    

    e.g.

    wget -r -np -nH --cut-dirs=3 -R index.html https://www.cs.cmu.edu/~213/code/06-machine-control/
    
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值