CSAPP-Lab2

Posted by Leo on 2023-09-23
Estimated Reading Time 7 Minutes
Words 1.6k In Total

实验概览

BombLab提供给我们两个文件,一个是编译不了的C文件bomb.c,一个是可执行文件bomb。当运行bomb文件时,它会要求输内容,如果其中的任何一句是错的,炸弹就会“爆炸”。我们必须利用反汇编工具逆向分析这个文件,并找到这6个字符串,从而“拆除”炸弹。

使用objdump -d bomb > bomb.asm命令反汇编bomb

汇编基础

  • eax寄存器常用来保存函数的返回值

  • test指令在两个操作数的对应位之间进行 AND操作,并根据运算结果设置符号标志位、零标志位和奇偶标志位,但test指令不修改目标操作数,test指令可以同时检查多个位

    假设想要知道 AL 寄存器的位 0 和位 3 是否置 1,可以使用如下指令:

    1
    test al, 00001001b ;测试位 0 和位 3

    只有当所有测试位都清 0 时,零标志位ZF才置 1

    1
    2
    3
    4
    5
    6
    7
    0  0  1  0  0  1  0  1    <- 输入值
    0 0 0 0 1 0 0 1 <- 测试值
    0 0 0 0 0 0 0 1 <- 结果:ZF=0

    0 0 1 0 0 1 0 0 <- 输入值
    0 0 0 0 1 0 0 1 <- 测试值
    0 0 0 0 0 0 0 0 <- 结果:ZF=1

    test %eax,%eax指令可以用来检查eax的值是否为零

  • x86架构中,eax 是32位的寄存器,其中包含了 axahal 三个子寄存器。其中,aleax 的低8位,ah 是中间的8位,axeax 的低16位

phase_1

对汇编代码进行分析:

1
2
3
4
5
6
7
8
400ee0:	48 83 ec 08          	sub    $0x8,%rsp	// 为函数分配栈帧
400ee4: be 00 24 40 00 mov $0x402400,%esi // 设置函数strings_not_equal的传入参数,0x402400
400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal>
400eee: 85 c0 test %eax,%eax
400ef0: 74 05 je 400ef7 <phase_1+0x17> // 函数返回值若为0,拆除成功;不为0,则bomb!
400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>
400ef7: 48 83 c4 08 add $0x8,%rsp
400efb: c3 retq

<strings_not_equal>函数的汇编代码如下:(需要返回0)

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
401338:	41 54                	push   %r12
40133a: 55 push %rbp
40133b: 53 push %rbx
40133c: 48 89 fb mov %rdi,%rbx
40133f: 48 89 f5 mov %rsi,%rbp
401342: e8 d4 ff ff ff callq 40131b <string_length> // 求出第一个字符串的长度并传给$r12d
401347: 41 89 c4 mov %eax,%r12d
40134a: 48 89 ef mov %rbp,%rdi
40134d: e8 c9 ff ff ff callq 40131b <string_length> // 求出第一个字符串的长度并与上一个字符串比较
401352: ba 01 00 00 00 mov $0x1,%edx
401357: 41 39 c4 cmp %eax,%r12d
40135a: 75 3f jne 40139b <strings_not_equal+0x63> // 将1作为返回值返回
40135c: 0f b6 03 movzbl (%rbx),%eax //rbx的低一字节传给eax
40135f: 84 c0 test %al,%al // 相当于要一个字节一个字节地比较
401361: 74 25 je 401388 <strings_not_equal+0x50> //将0作为返回值返回
401363: 3a 45 00 cmp 0x0(%rbp),%al
401366: 74 0a je 401372 <strings_not_equal+0x3a> //跳转到0x401372,去比较下一个字节
401368: eb 25 jmp 40138f <strings_not_equal+0x57> //将1作为返回值返回

/* 循环开始 */
40136a: 3a 45 00 cmp 0x0(%rbp),%al
40136d: 0f 1f 00 nopl (%rax)
401370: 75 24 jne 401396 <strings_not_equal+0x5e> //如果不相等将1作为返回值返回
401372: 48 83 c3 01 add $0x1,%rbx //每一次地址加1,相当于比较下一个字节
401376: 48 83 c5 01 add $0x1,%rbp
40137a: 0f b6 03 movzbl (%rbx),%eax
40137d: 84 c0 test %al,%al
40137f: 75 e9 jne 40136a <strings_not_equal+0x32> //如果$al不等于0,即还没有比较完

401381: ba 00 00 00 00 mov $0x0,%edx
401386: eb 13 jmp 40139b <strings_not_equal+0x63> //将0作为返回值返回
401388: ba 00 00 00 00 mov $0x0,%edx
40138d: eb 0c jmp 40139b <strings_not_equal+0x63> //将0作为返回值返回
40138f: ba 01 00 00 00 mov $0x1,%edx
401394: eb 05 jmp 40139b <strings_not_equal+0x63> //将1作为返回值返回
401396: ba 01 00 00 00 mov $0x1,%edx
40139b: 89 d0 mov %edx,%eax
40139d: 5b pop %rbx
40139e: 5d pop %rbp
40139f: 41 5c pop %r12
4013a1: c3 retq

要判断的是输入字符串是否与0x402400处存储的字符串相同,可以使用print (char*)0x402400x/s 0x402400来查看,得到key

1
Border relations with Canada have never been better.

phase_2

对汇编代码进行分析

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
400efc:	55                   	push   %rbp	  // 将被调用者保存寄存器的值入栈
400efd: 53 push %rbx
400efe: 48 83 ec 28 sub $0x28,%rsp

400f02: 48 89 e6 mov %rsp,%rsi // 分配栈帧并调用<read_six_numbers>读入整数
400f05: e8 52 05 00 00 callq 40145c <read_six_numbers>

400f0a: 83 3c 24 01 cmpl $0x1,(%rsp) // 比较%rsp与1是否相等,不相等则引爆。可知第一个数为 1
400f0e: 74 20 je 400f30 <phase_2+0x34>
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
400f1a: 01 c0 add %eax,%eax
400f1c: 39 03 cmp %eax,(%rbx)
400f1e: 74 05 je 400f25 <phase_2+0x29> //如果相等,进行下一步比较
400f20: e8 15 05 00 00 callq 40143a <explode_bomb> // 如果不等就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> //如果相等,函数成功返回

400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
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 retq

<read_six_numbers>的汇编分析如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
40145c:	48 83 ec 18          	sub    $0x18,%rsp
401460: 48 89 f2 mov %rsi,%rdx
401463: 48 8d 4e 04 lea 0x4(%rsi),%rcx
401467: 48 8d 46 14 lea 0x14(%rsi),%rax
40146b: 48 89 44 24 08 mov %rax,0x8(%rsp)
401470: 48 8d 46 10 lea 0x10(%rsi),%rax
401474: 48 89 04 24 mov %rax,(%rsp)
401478: 4c 8d 4e 0c lea 0xc(%rsi),%r9
40147c: 4c 8d 46 08 lea 0x8(%rsi),%r8

401480: be c3 25 40 00 mov $0x4025c3,%esi // 调用scanf()函数读取6个整数
401485: b8 00 00 00 00 mov $0x0,%eax
40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt>
40148f: 83 f8 05 cmp $0x5,%eax
401492: 7f 05 jg 401499 <read_six_numbers+0x3d>
401494: e8 a1 ff ff ff callq 40143a <explode_bomb>
401499: 48 83 c4 18 add $0x18,%rsp
40149d: c3 retq

为了验证是读取6个整数,使用print (char*)0x4025c3,输出%d %d %d %d %d %d,猜想正确

<phase_2>剩余代码的循环规律是,每个数都要与上一个数的2倍相等,从而可以得到key

1
1 2 4 8 16 32

phase_3

phase_4

phase_5

phase_6


本着互联网开源的性质,欢迎分享这篇文章,以帮助到更多的人,谢谢!