bomblab实验入门以及栈帧结构

bomblab实验入门以及栈帧结构

一、实验内容

1、熟悉linux系统下操作过程,对文件进行查看
2、熟悉bomblab代码,分析整个程序是如何运行的
3、深入研究每一个“炸弹”,熟练使用反汇编工具对各个阶段进行分析
4、理解IA32栈帧结构里寄存器是如何工作的
4、熟悉IA32栈帧结构,理解函数调用中栈帧有何变化

二、相关知识

1、程序在计算机中的存储
程序在计算机以二进制形式存储在内存中,我们通过下面汇编代码可以略做分析:

黄色框处0x080489b5地址开始存储右边黄色框内容,由于机器从高位增长,接下来5个16进制数据每个占据一个内存地址,如下图所示:

我们在p/x 0x080489b5时,机器为小端存储,从上往下读出来为:

其他存储方式类似。
2、linux下寄存器简介
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。x86指令及定义八个32位元寄存器的集合,但一个实作x86指令集的CPU可以包含比八个更多的寄存器。常用有以下几类寄存器:
4个数据寄存器(EAX、EBX、ECX和EDX)
2个变址寄存器(ESI和EDI)
2个指针寄存器(ESP和EBP)
6个段寄存器(ES、CS、SS、DS、FS和GS)
1个指令指针寄存器(EIP)
1个标志寄存器(EFlags)
3、linux下寄存器详解
4个数据寄存器(EAX、EBX、ECX和EDX)对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX: BH-BL、CX:CH-CL、DX:DH-DL),每个寄存器都有自己的名称,可独立存取。
(1)寄存器EAX通常称为累加器(Accumulator)用累加器进行的操作可能需要更少时间。可用于乘、除、输入/输出等操作,使用频率很高;
(2)寄存器EBX称为基地址寄存器(Base Register它可作为存储器指针来使用;
(3)寄存器ECX称为计数寄存器(Count Register) 在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;
(4)寄存器EDX称为数据寄存器(Data Register)在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址
2个变址和指针寄存器(ESI和EDI)其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。寄存器ESI、EDI、SI 和DI称为变址寄存器(IndexRegister),它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。
2个指针寄存器(ESP和EBP)其低16位对应先前CPU中的BP和SP,对低16位数据的存取,不影响高16位的数据。32位CPU有2个32位通用寄存器EBP和ESP。它们主要用于访问堆栈内的存储单元。寄存器EBP、ESP、BP和SP称为指针寄存器(Pointer Register),主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。指针寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
EBP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据ESP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶
其他寄存器不常用不再详解,寄存器存储字段如下:

4、汇编语言
汇编语言涉及内容实在太多,具体内容在《深入理解计算机系统》第3章:程序的机器级表示一章中,下面实验过程中会对汇编语言进行解释。
5、IA32栈帧结构

函数调用时会在栈帧中开辟一块内存区域,分为调用者栈结构和被调用者栈结构,%ebp指针寄存上方存放该函数的返回地址,接着%esp开辟被调用栈帧结构,内部存储函数调用所需的各种信息(参数、返回地址、局部变量等)。%esp向栈增长方向增加。

二、实验步骤

1、main函数查看分析
(1)用vim打开bomb.c文件,查看主函数:

(2)主函数分析:

显然头文件”support.h”和”phases.h”都没有给出,当然给出了也就没意思了。main函数前规定读入的文件,main函数控制文件的读入,规定一次只能读入一个文件,并且对文件有保存效果,避免重复输入。initialize_bomb()载入各个阶段的炸弹,然后读取输入文件,匹配phase_?函数,判断是否输入正确,由phase_defused()函数控制。
(3)对整个函数反汇编:

代码太长,不再进行展示。通过看各个函数的反汇编代码来找到对应的提示、输入对应的数据,然后过关,这就是我们这个实验需要完成的任务。

2、第一关phase_1()解析
(1)phase_1()反汇编查看:
我们现在开始动手拆除炸弹,由于main函数中没有给出phase函数的代码,我们可以通过查看其反汇编代码理解phase函数都做了些什么,下面是phase_1反汇编代码:

代码不长,很容易理解,下面是对代码的解释:

(2)猜测
其中函数调用了strings_not_equal函数,根据函数名猜测该函数应该是判断两个字符串是否相等,那上面movl $0x804a15c,0x4(%esp)一句显然就是某个字符串的首地址,下面我们验证下我们的猜测:

发现的确是一个字符串的首地址。那么根据猜想,另外一个参数自然是你输入的字符串的首地址了,们同样地去验证一下。注意这里是把0x8(%ebp)存的值作为地址,所以我们需要查看寄存器%ebp的值。
(3)设置断点查看
这里设置一下断点然后查看即可,如下:

运行时候输入测试字符串jiujiujiu,查看%ebp的值为:

我们打印出地址0x804c3e0处的值:

发现果然为我们输入的字符串,所以上述猜想正确。
(4)strings_not_equal函数查看:
下面对strings_not_equal反汇编函数查看:

简单对函数进行解释,函数读取上述两个地址处存储的字符串,先调用string_length函数(函数反汇编代码如下):

显然string_length函数循环读取一个字符串的字符数量,最终返回一个表示传入字符串长度的数字存放在%eax寄存器中。
让我们再次着眼strings_not_equal函数,函数先比较两个字符串长度是否相等,不相等%eax返回1,并结束函数,如上述蓝圈处。
接着进行循环判断,对两个字符串每一对应位字符进行比较,不相等%eax返回1,并结束函数。最后判断结束,将%eax置0,上图红圈处。
(5)结论:
所以到现在我们可以确定,第一关就是让我们输入和0x804a15c处存储一样的字符串,否则就爆炸,输入该字符串,问题解决!

(6)phase_1函数栈帧结构:

将输入参数拷贝到被调用者栈帧结构内,进行比较
3、第二关phase_2()解析
(1)phase_2()反汇编查看:
通过第一关后,根据经验,我们进行第二关反汇编代码查看,下面是phase_2反汇编代码:

我们用栈帧结构直接解释这段汇编代码比较方便,在这之前,我们先看看read_six_number干了什么。
(2)read_six_numbers函数反汇编查看

简单的对该函数进行解释,函数栈帧结构搭建之后,先将0x14(%eax)处对应存放的内容放在%0x1c(%esp)处,接着是0x10(%eax)存放在0x18(%esp)处,一直放置6个内容,最后调用系统函数isoc99_sscanf限制输入的为整形数字,红圈内限制了输入的数字为6个,否则直接爆炸。
(3)返回看phase_2函数
由此可见read_six_numbers规定了我们的输入应该为6个数字,那么这6个数字到底是什么呢?现在给出phase_2函数的栈帧结构:

显然我们先将参数1对应处存放的数组读入到被调用者栈帧结构中,并挨个存放在如上述对应数组位置,好了,现在输入数组的存放位置知道了,那输入的数组到底是什么呢?下面有几个关键的地方给了我们信息:
1)
2)
这两个地方告诉我们一个非常明显的信息,-0x20(%ebp)和-0x1c(%ebp)处所放置的数字一定为0和1,否则就直接爆炸,所以我们的a[0]=0,a[1]=1。那后面的数字如何判断?
3)接下来进入了一个循环,我们先看循环的终止条件:cmp %esi,%ebx。当两个寄存器的值不相等时继续循环。再看他们的初值及变化:%ebx的初值为-0x18(%ebp),%esi的初值为-0x8(%ebp),每次循环%ebx的值+4。这样一来的话该循环总共会进行4次。对于每次循环的操作都是将当前(%ebx)的低两个地址储存的数据之和与地址(%ebx)储存的数据进行比较不相等则爆炸。
也就是说,我们的ebx寄存器第一次存储的是a[2]的地址,然后-0x4(%ebx)和-0x8(%ebx)正好对应的是a[1]和a[0],也就是判断a[2]=a[0]+a[1],之后每次ebx+4,正好对应的是a[3]=a[2]+a[1],不断循环,直到最后一个数字a[5]=a[4]+a[3],显然这是一个斐波那契数列。
(4)最终解决
这里对read_six_numbers进行一下确认,设置一下断点然后查看即可,输入2,1,4,5,6,3如下:

运行时候输入密码为:0,1,1,2,3,5

三、遇到的问题及解决方法

1、使用gdb没有权限运行函数

解决方法:导致该问题的原因是gdb权限不够,使用如下命令行对gdb进行权限管理即可:

三、实验心得体会

实际上之前也做过一个类似拆炸弹的题目,但是考的是缓冲区溢出问题,今天第一次做,实际上考量的还是我们对于汇编代码的认知,函数没有给但是可以从汇编语言中将函数进行一步一步的还原。其实在做第一个实验的时候,很容易由子函数的名字联想到其功能,然后直接查看0x804a15c处的字符串就行了,但是为了验证和把基础打牢,还是要把整个汇编代码弄懂。理解这个实验到底是要教会我什么东西。记得高中时候老师说过,做题目也好做实验也好,要理解出题人的目的、手段等,才是真的学会了。还有4个炸弹和隐藏关,加油!

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值