计算机系统基础II实验报告Word格式.docx
- 文档编号:22587357
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:24
- 大小:1.36MB
计算机系统基础II实验报告Word格式.docx
《计算机系统基础II实验报告Word格式.docx》由会员分享,可在线阅读,更多相关《计算机系统基础II实验报告Word格式.docx(24页珍藏版)》请在冰豆网上搜索。
各院部可根据学科特点和实验具体要求增加项目。
填写注意事项
(1)细致观察,及时、准确、如实记录。
(2)准确说明,层次清晰。
(3)尽量采用专用术语来说明事物。
(4)外文、符号、公式要准确,应使用统一规定的名词和符号。
(5)应独立完成实验报告的书写,严禁抄袭、复印,一经发现,以零分论处。
实验报告批改说明
实验报告的批改要及时、认真、仔细,一律用红色笔批改。
实验报告的批改成绩采用百分制,具体评分标准由各院部自行制定。
实验报告装订要求
实验批改完毕后,任课老师将每门课程的每个实验项目的实验报告以自然班为单位、按学号升序排列,装订成册,并附上一份该门课程的实验大纲。
实验项目名称:
缓冲区溢出攻击—基础篇实验学时:
4
同组学生姓名:
无实验地点:
1116
实验日期:
11.26、12.3实验成绩:
批改教师:
批改时间:
一、实验目的和要求
1、初步了解IA-32函数调用规则和栈结构。
2、基本掌握gcc、gdb以及objdump等工具的运用。
二、实验仪器和设备
硬件环境:
IA-32
软件环境:
Linuxubuntu14.04,C语言,gcc,gdb
三、实验内容与过程
1、实验内容
对一个可执行程序“bufbomb”实施一系列缓冲区溢出攻击(bufferoverflowattacks),也就是设法通过造成缓冲区溢出来改变可执行程序的运行内存映像,继而执行一些原来程序中没有的行为。
对目标可执行程序BUFBOMB分别完成5个难度递增的缓冲区溢出攻击。
5个难度级分别命名为Candle(level0)、Sparkler(level1)、Firecracker(level2)、Dynamite(level3)和Nitroglycerin(level4),其中Candle级最简单而Nitroglycerin级最困难。
(本次实验完成前三个难度级别的攻击,即Candle、Sparkler和Firecracker)
2、实验步骤
1)下载实验数据。
实验数据包括三个可执行文件,即bufbomb、makecookie和hex2raw。
2)仔细阅读附录1中的文档,充分深入地了解实验数据、实验环境以及实验工具的使用方法。
3)利用gdb以及objbump工具分析相应的程序代码、内存映像以及相应函数的栈结构。
4)如有必要,编写对应的指令,用gcc将其变换为机器代码。
5)精心设计一些字符串存入一个文本文件(solution.txt)中,然后按如下命令输入给bufbomb,有意造成缓冲区溢出,并使得屏幕上能显示出“NICEJOB!
”。
unix>
catsolution.txt|./hex2raw|./bufbomb-u<
userid>
四、实验结果与分析
本次实验利用getbuf()方程不检查读取string长度的漏洞破坏该方程的返回地址从而达到对主程序造成破坏的目的。
从getbuf()的汇编代码我们可以看到:
位于<
0x8049207>
地址处代码为预读的string在stack创建了0x28(也就是40)个Byte的空间。
具体位置可以通过gdb在下一行设置breakpoint查找%eax的值得到,如下所示:
通过gdb调试得到,getbuf()申请的40字节缓冲区首地址为<
0x556836c8>
。
Level0:
Smoke
在bufbomb的反汇编源代码中找到smoke函数,记下它的起始地址:
攻击字符串的功能是用来覆盖getbuf函数内的数组buf(缓冲区),进而溢出并覆盖ebp和ebp上面的返回地址,所以攻击字符串的大小应该是0x28+4+4=48个字节。
并且其最后4个字节应是smoke函数的地址,正好覆盖ebp上方的正常返回地址。
这样再从getbuf返回时,取出的根据攻击字符串设置的地址,就可实现控制转移。
总共48个字节,并且前面44个字节可以为任意值,对程序的执行没有任何影响,只要最后四个字节正确地设置为smoke的起始地址<
0x08048c28>
即可,对应内存写入288c0408(小端格式)。
栈帧示意图如下图所示。
可以将上述攻击字符串写在攻击字符串文件中,命名为123.txt,之后通过hex2raw处理过滤掉所有的注释,还原成没有任何冗余数据的攻击字符串原始数据而代入bufbomb中使用。
通过Linux终端执行:
显示结果如下:
Level1:
Fizz
level1和level0大同小异,唯一的区别是本次要求跳入函数fizz(int)且该函数有一个参数(要求用所给cookie作argument)。
我们知道在执行完ret指令后栈顶指针%esp会自动增加4以还原栈帧。
通过查找fizz()得知:
fizz()函数的起始地址为<
0x08048c52>
由栈帧图示可知,ebp存放了调用者的旧ebp(saved%ebp),其上一位置ebp+4存放了调用者的返回地址,所以参数的地址应该为ebp+8的位置,我们只需要将自己的cookie放置在该位置即可。
构造攻击文件456.txt其中,<
为fizz函数起始地址,0x49bd5724为自己的cookie,通过参数传递给fizz。
最后结果如下:
Level2:
bang
Level2中除了需要跳转至目标函数bang()地址为<
0x08048cad>
:
我们还需要执行一些自行设计的指令,该任务需要将global_value的值改成我们的cookie,通过objdump-D反汇编可以看到:
global_value的地址是<
0x0804d100>
,目前该位置的初始值为0;
cookie的地址是<
0x0804d108>
,目前该位置的值初始为0,程序运行后会变为cookie的值。
在程序运行时将global_value的值设置为cookie的值。
构造自定义攻击指令bang.s:
先将global_value地址用movl指令变cookie(0x0804d100前不加$表示地址),然后将bang()函数<
写给esp,在执行ret指令时,程序自动跳入bang()函数。
指令gcc-m32-cbang.s
将assemblycode写成machinecode-->
bang.o,再用objdump-dbang.o
读取machinecode如下:
将指令代码抄入攻击文件,除此之外我们还需找inputstring存放的位置作为第一次ret指令的目标位置,经过gdb调试分析getbuf()申请的40字节缓冲区首地址为<
栈帧示意图如下:
构造攻击字符串789.txt如下:
最后执行测试结果如下:
五、实验思考题和实验心得。
1、思考题
1.请绘制出函数getbuf栈结构的示意图。
2、实验心得
本次实验整体难度不大,基本上可以找到他们的共同点:
几个级别实现的攻击都是使得程序跳转到不同于正常返回地址的其他函数中,进而结束整个程序的运行。
只要理解了一个懂得它的原理,开头做出来了,便可以顺藤摸瓜进行下面的实验。
本次实验难点就在不同级别的函数它的攻击指令也不尽相同,需要仔细的弄懂原理,通过这次实验,我对函数调用的实现过程有了深刻的理解。
对gfb、objdump等命令的调用,我对Linux32位系统中函数调用规则和栈结构的理解更加深刻了。
缓冲区溢出攻击—提高篇实验学时:
12.10、12.17实验成绩:
1、加深对IA-32函数调用规则和栈结构的具体理解。
2、熟练掌握gcc、gdb以及objdump等工具的运用。
三、实验过程
实验中你需要对目标可执行程序BUFBOMB分别完成5个难度递增的缓冲区溢出攻击。
(本次实验完成第四个和第五个难度级别的攻击,即Dynamite和Nitroglycerin。
)
2)仔细阅读附录2中的文档,充分深入地了解实验数据、实验环境以及实验工具的使用方法。
4)编写对应的指令,用gcc将其变换为机器代码。
Level3:
bomb
在本任务中getbuf()结束后回到test()原本的位置(即callgetbuf后的下一行),并将你的cookie作为getbuf()的返回值传给test()。
为了使攻击更加具有迷惑性希望旧ebp被复原,确保原程序不会因为外部攻击而出错崩溃,也就是退出攻击后要保证栈空间还原。
要还原栈帧,必须知道在调用getbuf()之前的原始ebp的值,这里使用gdb调试来获取,可以在<
0x08048dc9>
(准备进入getbuf函数)设置断点,然后查看进入getbuf之前的%ebp寄存器值,这里得到的旧的ebp的值为<
0x55683720>
,如下:
构造攻击指令bomb.s如下:
通过movl指令将cookie值传给%eax以返回给test(),然后使得程序跳转到test()中callgetbuf下一条指令正常返回,但是并不在这里处理ebp寄存器问题,而是通过在攻击字符串里面设置ebp寄存器使得其还原为旧ebp。
对其进行编译,然后反汇编得到机器码:
构造攻击字符串101112.txt如下:
Level4:
nitro
本级要使用./bufbomb的-n参数,bufbomb不会再像从前哪样调用test(),而是调用testn(),testn()又调getbufn()。
本级的任务是使getbufn返回cookie给testn()。
bufbomb会连续要我们输入5次字符串,每次都调用getbufn(),每次的栈地址都不一样。
(1)用汇编指令——nop(机械代码:
90)填充我们的Inputstring。
这样一来在一定范围内无论在哪里进入我们的攻击程序执行指令最终都会滑到我们的攻击方程;
(2)虽然ebp的值每次变化,无法直接赋值,但是在getbufn()程序中ebp和esp值差是一定的通过gdp查找我们可以查到这样的关系,比如我这里是相差0x28;
(3)通过空input运行主程序发现五次inputstring的存储位置在0x55682df8到0x55682e48之间,因此如果我们将第一次retaddress定为最高的0x55682e48那么就可以保证五次运行执行命令都不会在运行攻击程序之前遇到除nop(90)之外的其他指令。
bufbomb在5次调用testn()和getbufn()的过程中,两个函数的栈是连续的,在testn()汇编代码开头有
可知%esp=%ebp-4-0x24,即%ebp=%esp+0x28。
其中,getbufn执行ret前的leave指令已经正确地恢复%esp(leave等价于mov%ebp,%esp;
pop%ebp,我们的字符串无法覆盖%ebp,%esp寄存器,%esp是从寄存器%ebp里来的。
构造攻击指令nitro.s如下:
使用gdb调试发现5次getburn循环里面,缓冲区首地址情况如下:
构造攻击字符串131415.txt如下:
.
五、实验心得
在此次实验中,主要完成了第3、第4等级的缓冲区溢出攻击。
前一个实验中的几个级别实现的攻击都是使得程序跳转到不同于正常返回地址的其他函数中,进而结束整个程序的运行,这样的攻击方法我们在学习了以后已经能理解它的原理。
然而,更高明的缓冲区溢出攻击除执行攻击代码来改变程序的寄存器或内存中的值外,仍然使得程序能够返回到原来的调用函数继续执行,这种攻击方式就不同于正常的想法了,有些难理解了。
尤其是最后攻击指令填充的90,很好奇为什么是90,后来通过请教老师才知道90是nop指令的机械代码。
通过objdump、gdb命令的使用,我对Linux32位系统中的函数调用和栈的结构理解更深了。
存储保护实验学时:
12.24、12.29实验成绩:
通过实际程序的执行结果,了解程序执行时访问违例的检测和处理过程。
执行以下程序,通过gdb调试找到发生异常的指令以及发生访问违例的存储单元地址。
主要程序段如下:
intsum(inta[],unsignedlen)
{
inti,sum=0;
for(i=0;
i<
=len–1;
i++)
sum+=a[i];
returnsum;
}
1)使用len=0调用sum函数,分别给出在Windows和Linux系统中的执行结果。
2)在Linux系统中,用gdb调试工具,通过设置正确的断点、显示通用寄存器的内容等手段,确定发生异常的指令,并指出发生的是什么异常,以及发生访问违例的存储单元地址。
3)分析从CPU检测到异常到屏幕中出现“Segmentfault”的整个过程中,CPU和操作系统各做了哪些事情?
Windows系统中,该程序无法运行。
如图:
Linux系统中,该程序运行如下:
提示:
段错误(核心已转储)
查了一下资料,总结了以下几个方面的原因:
1.内存访问出错:
这类问题的典型代表就是数组越界。
2.非法内存访问:
出现这类问题主要是程序试图访问内核段内存而产生的错误。
3.栈溢出:
Linux默认给一个进程分配的栈空间大小为8M。
c++申请变量时,new操作申请的变量在堆中,其他变量一般在存储在栈中。
进行GDB调试:
查表找到如下图所示地址73f和6d9的位置,
eax和esp所在的栈发生溢出。
main函数反汇编代码:
sum函数反汇编代码:
运行结果分析:
函数栈帧结构示意图如下:
本次实验与前两次实验不同,前两次实验大同小异,但是本次实验需要通过实际程序的执行结果,了解程序执行时访问违例的检测和处理过程。
通过反汇编代码一步一步了解运行的情况,通过栈帧示意图,可以直观地看出sum函数被调用过程中的执行情况。
虽然能够做出正确的实验结果,但是还是感觉云里雾里的,以后我会多学习这方面的知识,能够独立思考除一个实验的解决方法,而不是一味的模仿借鉴。
通过这次实验,感觉自己对于计算机系统基础的知识储备还不够,以后会多加学习这些底层的东西。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机系统 基础 II 实验 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)