CSAPP-Lab02 Bomb Lab 详细解析

本文详细介绍了CSAPP的Bomb Lab实验,包括phase_1到phase_6的反汇编分析和解密过程。通过分析代码,找出每个阶段的关键输入以解除炸弹。实验涉及到逆向工程、函数调用、参数传递和内存操作,锻炼了对汇编语言和程序逻辑的理解。
摘要由CSDN通过智能技术生成

实验概览

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

这个实验看起来就非常有趣!

运行一下bomb文件:

image-20220223193259282

提示我们输入内容,先随便输入试试!

image-20220224170832003

BOOM! ,炸弹果然爆炸了!接下来就要进行紧张刺激的拆弹环节了。

实验过程

bomb.c代码分析

image-20220225221607368

每一个phase的结构都是相同的,这里仅以phase_1为例。

前两行将我们的输入传入phase_1函数中,如果函数能成功返回,则接下来调用phase_defused函数,从字面意思理解,此时炸弹就拆除成功了。

那么炸弹什么时候爆炸呢,当然就是函数无法返回的时候了,猜测phase_1会调用一个中断程序,直接退出了程序。

所以我们的任务就是分析每一个phase_x函数,使用正确的输入,使得函数能够成功返回。

phase_1

反汇编 phase_1

使用gdbdisassemble命令反汇编phase_1

Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>:     sub    $0x8,%rsp
   0x0000000000400ee4 <+4>:     mov    $0x402400,%esi
   0x0000000000400ee9 <+9>:     callq  0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:    test   %eax,%eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 <phase_1+23>
   0x0000000000400ef2 <+18>:    callq  0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:    add    $0x8,%rsp
   0x0000000000400efb <+27>:    retq
End of assembler dump.
  • 第2行,为函数分配栈帧
  • 第3行,设置函数strings_not_equal传入参数
  • 第4行,调用函数strings_not_equal,从字面意思理解,猜想如果传入字符串不同,则返回0
  • 第5、6行,函数strings_not_equal的返回值储存在%eax中,判断其是否为0,若为0,则跳至第8行,函数返回,炸弹拆除成功;若不为0,则跳至第7行
  • 第7行,调用explode_bomb函数,从字面意思理解,炸弹爆炸了。

于是,只需利用x/s指令查看0x402400位置对应内存存的字符串即可:

image-20220224170749197

这句话就是phase_1

key

Border relations with Canada have never been better.

image-20220224171003127

成功!

phase_2

剩下部分的phase调用与phase_1都十分类似,直接反汇编即可

反汇编phase_2

全部代码暂不放出,后面分析时再贴上,方便查看

先看前几行

   0x0000000000400efc <+0>:     push   %rbp
   0x0000000000400efd <+1>:     push   %rbx
   0x0000000000400efe <+2>:     sub    $0x28,%rsp
  • 第1,2行,将被调用者保存寄存器的值入栈
  • 第3行,分配栈帧
   0x0000000000400f02 <+6>:     mov    %rsp,%rsi
   0x0000000000400f05 <+9>:     callq  0x40145c <read_six_numbers>
  • 第5,6行,将栈顶指针%rsp传给%rsi,并作为参数调用函数read_six_numbers。从字面意思理解,本题是要我们输入6个数字。这里mov %rsp,%rsi的目的是保存caller中栈顶的位置,方便在read_six_numbers中进行改值。我们不妨反汇编read_six_numbers

此时,栈的情况为:

image-20220224200313575

反汇编read_six_numbers
Dump of assembler code for function read_six_numbers:
   0x000000000040145c <+0>:     sub    $0x18,%rsp
   0x0000000000401460 <+4>:     mov    %rsi,%rdx
   0x0000000000401463 <+7>:     lea    0x4(%rsi),%rcx
   0x0000000000401467 <+11>:    lea    0x14(%rsi),%rax
   0x000000000040146b <+15>:    mov    %rax,0x8(%rsp)
   0x0000000000401470 <+20>:    lea    0x10(%rsi),%rax
   0x0000000000401474 <+24>:    mov    %rax,(%rsp)
   0x0000000000401478 <+28>:    lea    0xc(%rsi),%r9
   0x000000000040147c <+32>:    lea    0x8(%rsi),%r8
   0x0000000000401480 <+36>:    mov    $0x4025c3,%esi
   0x0000000000401485 <+41>:    mov    $0x0,%eax
   0x000000000040148a <+46>:    callq  0x400bf0 <__isoc99_sscanf@plt>
   0x000000000040148f <+51>:    cmp    $0x5,%eax
   0x0000000000401492 <+54>:    jg     0x401499 <read_six_numbers+61>
   0x0000000000401494 <+56>:    callq  0x40143a <explode_bomb>
   0x0000000000401499 <+61>:    add    $0x18,%rsp
   0x000000000040149d <+65>:    retq
End of assembler dump.

截至第10行,寄存器及栈存储内容的指向如图所示:

image-20220224215510737

在这个函数中,要做到传6个参数,用来存储6个输入的数字。很明显,这里传入了6个指针,其中4个存在寄存器上,另外2个存在栈上。由于phase_2函数中的栈指针rsp与这个函数中的rsi相等,所以把所有参数存在rsi之前的位置的目的是在返回phase_2函数后,能够直接利用phase_2函数的栈指针来连续地访问这6个数字。

注意到M[%rsp+0x4]没有用来传参数,这是为什么呢?

因为通过栈传递参数时,所有的数据大小都向8的倍数对齐。

下面的问题就是如何确定这6个数字的先后位置,传递参数的寄存器使用顺序如下:

image-20220224221138386

所以,我们应该输入的6个数字所在的位置就分别是:R[%rsp] R[%rsp+0x8] %rsi %rsi+0x4 %rsi+0x8 %rsi+0xc

返回phase_2函数后,利用栈顶指针调用就是: %rsp %rsp+0x4 %rsp+0x8 %rsp+0xc %rsp+0x10 %rsp+0x14

回到 phase_2
Dump of assembler code for function phase_2:
   0x0000000000400efc <+0>:     push   %rbp
   0x0000000000400efd <+1>:     push   %rbx
   0x0000000000400efe <+2>:     sub    $0x28,%rsp
   0x0000000000400f02 <+6>:     mov    %rsp,%rsi
   0x0000000000400f05 <+9>:     callq  0x40145c <read_six_numbers>
   0x0000000000400f0a <+14>:    cmpl   $0x1,(%rsp)
   0x0000000000400f0e <+18>:    je     0x400f30 <phase_2+52>
   0x0000000000400f10 <+20>:    callq  0x40143a <explode_bomb>
   0x0000000000400f15 <+25>:    jmp    0x400f30 <phase_2+52>
   0x0000000000400f17 <+27>:    mov    -0x4(%rbx),%eax
   0x0000000000400f1a <+30>:    add    %eax,%eax
   0x0000000000400f1c <+32>:    cmp    %eax,(%rbx)
   0x0000000000400f1e <+34>:    je     0x400f25 <phase_2+41>
   0x0000000000400f20 <+36>:    callq  0x40143a <explode_bomb>
   0x0000000000400f25 <+41>:    add    $0x4,%rbx
   0x0000000000400f29 <+45>:    cmp    %rbp,%rbx
   0x0000000000400f2c <+48>:    jne    0x400f17 <phase_2+27>
   0x0000000000400f2e <+50>:    jmp    0x400f3c <phase_2+64>
   0x0000000000400f30 <+52>:    lea    0x4(%rsp),%rbx
   0x0000000000400f35 <+57>:    lea    0x18(%rsp),%rbp
   0x0000000000400f3a <+62>:    jmp    0x400f17 <phase_2+27>
   0x0000000000400f3c <+64>:    add    $0x28,%rsp
   0x0000000000400f40 <+68>:    pop    %rbx
   0x0000000000400f41 <+69>:    pop    %rbp
   0x0000000000400f42 <+70>:    retq
End of assembler dump.
  • 第7,8,9行,比较(%rsp)与1是否相等,不相等则引爆。可知第一个数为 1
  • 看第20行,第2个数存在0x(%rsp)中,设为num_2,则(%rbx)=num_2。跳到第11行,这一行将第一个数赋值给%eax,12,13行是将其翻倍再进行同样的比较。可知第二个数为2
  • 跳到第16行,得到了第三个数的地址,第17行把我迷惑了很久,rbprbx肯定是不相等的,不知道这样设置的意义。继续跳到第17行,进入循环。
  • 这里循环的规律是,每个数都要与上一个数的2倍相等,从而可以得到剩下的4个数分别为:4,8,16,32

key

1 2 4 8 16 32

image-20220224234129047

成功!

phase_3

反汇编 phase_3

Dump of assembler code for function phase_3:
   0x0000000000400f43 <+0>:     sub    $0x18,%rsp
   0x0000000000400f47 <+4>:     lea    0xc(%rsp),%rcx
   0x0000000000400f4c <+9>:     lea    0x8(%rsp),%rdx
   0x0000000000400f51 <+14>:    mov    $0x4025cf,%esi
   0x0000000000400f56 <+19>:    mov    $0x0,%eax
   0x0000000000400f5b <+24>:    callq  0x400bf0 <__isoc99_sscanf@plt>
   0x0000000000400f60 <+29>:    cmp    $0x1,%eax
   0x0000000000400f63 <+32>:    jg     0x400f6a <phase_3+39>
   0x0000000000400f65 <+34>:    callq  0x40143a <explode_bomb>
   0x0000000000400f6a <+39>:    cmpl   $0x7,0x8(%rsp)
   0x0000000000400f6f <+44>:    ja     0x400fad <phase_3+106>
   0x0000000000400f71 <+46>:    mov    0x8(%rsp),%eax
   0x0000000000400f75 <+50>:    jmpq   *0x402470(,%rax,8)
   0x0000000000400f7c <+57>:    mov    $0xcf,%eax
   0x0000000000400f81 <+62>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f83 <+64>:    mov    $0x2c3,%eax
   0x0000000000400f88 <+69>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f8a <+71>:    mov    $0x100,%eax
   0x0000000000400f8f <+76>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f91 <+78>:    mov    $0x185,%eax
   0x0000000000400f96 <+83>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f98 <+85>:    mov    $0xce,%eax
   0x0000000000400f9d <+90>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400f9f <+92>:    mov    $0x2aa,%eax
   0x0000000000400fa4 <+97>:    jmp    0x400fbe <phase_3+123>
   0x0000000000400fa6 <+99>:    mov    $0x147,%eax
   0x0000000000400fab <+104>:   jmp    0x400fbe <phase_3+123>
   0x0000000000400fad <+106>:   callq  0x40143a <explode_bomb>
   0x0000000000400fb2 <+111>:   mov    $0x0,%eax
   0x0000000000400fb7 <+116>:   jmp    0x400fbe <phase_3+123>
   0x0000000000400fb9 <+118>:   mov    $0x137,%eax
   0x0000000000400fbe <+123>:   cmp    0xc(%rsp),%eax
   0x0000000000400fc2 <+127>:   je     0x400fc9 <phase_3+134>
   0x0000000000400fc4 <+129>:   callq  0x40143a <explode_bomb>
   0x0000000000400fc9 <+134>:   add    $0x18,%rsp
   0x0000000000400fcd <+138>:   retq
End of assembler dump.

这道题与上道题非常类似。

  • 首先看第5行,查看0x4025cf位置的内容。可以知道,要求传入2个数字

image-20220225143138464

  • 由上道题的启法,第2,3,4行就指明了两个数字的位置分别在栈空间%rsp+0x8%rsp+0xc
  • 第8,9,10行属于程序健壮性的考虑,判断是否输入了两个数字,否则直接引爆
  • 第11,12行,说明了第一个数字应该小于等于7
  • 第14行,要求跳到内存0x402470(,%rax,8)里面存的位置。rax指向的内存此时存的就是第1个数,我们只知道这个数时小于等于7的,这里随便假设其为 1 试试!那么接下来就要跳到内存0x402478中的地址
  • 查看内存0x402478中的内容:

image-20220225144723573

  • 所以,下面就跳到0x0000000000400fb9对应代码,也就是第32行,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deconx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值