ImageVerifierCode 换一换
格式:DOCX , 页数:40 ,大小:453.34KB ,
资源ID:962483      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-962483.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(中山大学计算机组成原理实验bomblab.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

中山大学计算机组成原理实验bomblab.docx

1、中山大学计算机组成原理实验bomblab 计算机组成原理实验实验报告(实验一)学院名称:数据科学与计算机学院专业(班级):学生姓名:学号时间:2019年10月8日成绩:实验一: X86汇编基础二进制炸弹 一. 实验目的(1) 初步认识 X86 汇编语言;(2) 掌握阅读程序反汇编代码的方法,了解程序在机器上运行的实质;(3) 熟悉 Linux 环境、掌握调试器 gdb 和反汇编工具 objdump 的使用。二. 实验内容使用课程知识拆除一个“Binary Bomb”(,简称炸弹)来增强对程序的机器级表示、汇编语言、调试器和逆向工程等理解。二进制炸弹是一个 Linux 可执行 C 程序,包含ph

2、ase_1phase_6 共 6 个阶段和一个隐藏阶段 secret_phase。你将获得一个唯一且每位同学差异化的炸弹程序。炸弹运行各阶段要求输入一个字符串,若输入符合程序预期,该阶段炸弹被“拆除”,否则“爆炸”。实验目标是你需要拆除尽可能多的炸弹。每个炸弹阶段考察机器级语言程序不同方面,难度递增。阶段 1:字符串比较阶段 2:循环阶段 3:条件/分支:含 switch 语句阶段 4:递归调用和栈阶段 5:指针阶段 6:链表/指针/结构隐藏阶段,第4阶段的之后附加一特定字符串后才会出现拆弹技术:为了完成二进制炸弹拆除任务,你需要1.使用 gdb 调试器和 objdump 反汇编工具;2.单步

3、跟踪调试每一阶段的机器代码3.理解汇编语言代码的行为或作用4.进而设法“推断”出拆除炸弹所需的目标字符串。5.需要在每一阶段的开始代码前和引爆炸弹的函数前设置断点,便于调试。三. 实验器材PC机一台,装有Linux操作系统的虚拟机一套。四. 实验过程与结果说明:根据需要书写相关内容,如:程序流程图、设计的思想与方法、分析、实验步骤和实验结果及分析等。4.1 第一关在刚接触这一大堆汇编代码时,我是迷茫的。好在pdf上给出了第一关的解决方法,而且第一关的难度也并不大。Phase_1函数一开始进行栈指针修改,后面我们知道这是函数调用时分配栈空间的必经之路。然后函数压栈两个数据,执行一个函数并进行一个

4、判断,最后返回。观察到strings_not_equal函数的调用,它判断栈顶的前两个元素。如果它们相等,就修改eax为0;如此,紧随其后的jne就不会触发,也就不会导致的调用。栈顶的两个元素分别为我们的输入,和$0x804a21c内存处的数据。用gdb查看,可知它是字符串,为只要让它们相等即可,所以我们本关的答案毫无疑问就是I can see Russia from my house!4.2 第二关第二关脱离了指导开始独立作业,我再一次迷茫了。第二关的代码数量突然陡增,同样先观察代码;首先仍然是准备工作,然后程序调用了一个叫做的函数,我们找到这个函数一探究竟。可以看到函数用scanf函数读取

5、用户输入的六个数据,地址间间隔为4;再深究可以在gdb中找到格式化字符为%d整形,所以本关应该是要求我们输入6个整数型。我们知道0x8(%ebp)是我们的输入,那么就是把这个输入变成六个整形放入-0x24(%ebp)中,可以假设这里是一个整形数组arr。再向下看,函数进行一次判断也就是arr05时就触发爆炸。我们知道了输入的第一个数不能大于5.再继续,下面进入一个循环语句。Ebx应该是循环的控制单位,每次循环自增1,等于6时跳出循环。eax保存一个变址寻址的结果,然后进行eax位左移,并把它与当前寻址结果的前一个地址进行比较,不相等就触发爆炸。如果循环顺利执行完毕,本关就被破解。至此逻辑已经很

6、明确了,我们可以把它翻译成C代码。if (arr05) explode_bomb();for (int i=1;i!=6;i+)int tmp = arri-1;tmpi;if (tmp!=arri) explode_bomb();End就这样,假设我们的arr0是1,则第一次左移1位,第二次左移2位循环5次,我们就得到arr数组应该装着的6个整形数字。Step 1: 1Step 2: 2Step 3: 8Step 4: 64Step 5: 1024Step 6: 32768所以本关的答案是1 2 8 64 1024 327684.3 第三关顺利完成第二关终于提升了我的一点信心,再看第三关就没

7、那么可怕(不)一开始函数压栈4个数值,然后调用scanf函数,可以推断它们都是scanf的参数。-0x10(%ebp)和-0x14(%ebp)都是明确的地址,0x8(%ebp)是我们的输入,这个0x804a46d就显得很可疑,gdb一看就知道它是格式化字符串。那么本关就是让我们输入两个整形,它们分别存储在-0x14(%ebp)和-0x10(%ebp)两个位置。scanf函数的返回值放在eax中,它的返回值是2(接受两个参数),我们设-0x14(%ebp)和-0x10(%ebp)的两个参数为a和b。紧跟其后的是判断语句cmpl $0x7,-0x14(%ebp) ja 8048ca8 /爆炸限制了

8、a的取值,a必须小于等于7.又由于ja比较无符号数,ja还要大于等于0 下面的语句是解决本题的关键性语句jmp *0x804a26c(,%eax,4)一个基址寻址,*0x804a26c里面的东西是什么?可能是一个跳转表,用gdb查看之。果然如此,如此一来,我们的输入a(07)就会导致8种跳转。这应该是一个switch语句!再往下就是一些算术操作,对不同的a输入会有不同的算术。唯一的生死点是一个判断语句cmpl,它限制了a的取值为0=a=5.最后让eax,也就是算术结果和第二个输入b相等即可;我们也不需要通读代码来计算输入,只需要当程序执行到这句时,用gdb查看一下eax的值,就能拿到我们的第二

9、个输入b。本题应该有a为0,1,2,3,4,5六组答案,我们只取一种a = 0的情况,这时计算得到的b是-117.第三关的答案就是0 -117!4.4 第四关第四关与前面的不同在于它多了一个函数。先观察phase_4主体,发现和第三关的输入方式一样,都是两个整形a和b。这次我们观察到a的输入范围被限制到了0=aeba时:这时把eax,edx,ebx-1递归传入func4,返回func4(eax,edx,ebx-1)。判断2:ebxeba时:这时把eax,ebx+1,原始的ecx递归传入func4,返回func4(eax,ebx+1,ecx+edx)乍一看这个函数很难知道它想用递归实现什么,但是

10、用高级语言复现这个函数是很简单的,我们可以用python实现该函数,并逐一尝试输入a为014的情况。Func4执行完毕后,返回值在eax中,随后执行最后的步骤判断返回值和输入b是否为0x1f(31),这样我们的输入a必须让函数返回31,b必须是31.使用python模拟该程序的运行,结果如下。可见输入为13时,func4返回31.即a = 13,b = 31就是我们要的答案。第四关答案为13 31!4.5 第五关我们已经掌握了一些套路,接下来的关卡虽然难度大了,但并没有前几关那么棘手了。一开始还是观察输入格式,发现并没有scanf的格式化输入,可以判断本关输入是一个字符串;程序一开始有mov

11、0x8(%ebp),%ebx push %ebx call 8049029 cmp $0x6,%eax jne 8048dee 把我们的输入字符串放入一个string_length函数中,通过阅读这个函数发现它会返回字符串长度,保存在eax中。然后eax与6作比较,不相等则爆炸,于是我们判断本关是要求我们输入一个6长度字符串。紧随其后的是一段循环语句8048da2: b8 00 00 00 00 mov $0x0,%eax8048da7: 0f b6 14 03 movzbl (%ebx,%eax,1),%edx 8048dab: 83 e2 0f and $0xf,%edx 8048dae:

12、 0f b6 92 8c a2 04 08 movzbl 0x804a28c(%edx),%edx 8048db5: 88 54 05 ed mov %dl,-0x13(%ebp,%eax,1) 8048db9: 83 c0 01 add $0x1,%eax 8048dbc: 83 f8 06 cmp $0x6,%eax 8048dbf: 75 e6 jne 8048da7 Ebx是输入的字符串,设为str,eax应该是for循环的控制单位,也做下标使用,设为i。程序每次循环读取stri的值,然后用一个and 0xf取其后四位。随后有一个基址寻址0x804a28c(%edx),不知道这块内存存

13、储着什么,打开看一看。是一串字符串,设它为s,那么这句就是取sstri&0xf;后面还把它放入了-0x13(%ebp,%eax,1)这段地址中,如此一来我们就可以翻译这段代码为C代码:for (int i=0;i!=6;i+)char tmp = sstri&0xf;arri = tmp;再往后就是一个函数的调用8048dc8: 68 62 a2 04 08 push $0x804a262 8048dcd: 8d 45 ed lea -0x13(%ebp),%eax 8048dd0: 50 push %eax 8048dd1: e8 75 02 00 00 call 804904b 8048d

14、d6: 83 c4 10 add $0x10,%esp 8048dd9: 85 c0 test %eax,%eax 8048ddb: 75 18 jne 8048df5 函数比较-0x13(%ebp),也就是上面的arr,和0x804a262内存处的字符串。打开0x804a262看看里面是什么.一个单词bruins,要让arr和它相等,就要从s中分别找到这六个字母的下标,然后用把这些下标作为输入的六个字符的后四位来形成我们需要的目的字符串。寻找下标和转为字符串的工作可以用高级语言实现,下面是python实现过程。于是我们就得到了一种可能的答案MFCDHG。即第五关的答案为MFCDHG。4.6

15、第六关还是从输入数据格式入手,发现和第二关的处理输入的部分相同,都是借助函数,把输入用scanf截获为六个整数型。它们保存在-0x3c(%ebp)处的一个序列,设为arr。紧随其后的是一个嵌套的二重循环语句第一层循环先拿出arri,然后做一个判断8048e28: 8b 44 b5 c4 mov -0x3c(%ebp,%esi,4),%eax 8048e2c: 83 e8 01 sub $0x1,%eax 8048e2f: 83 f8 05 cmp $0x5,%eax 8048e32: 77 0c ja 8048e40 /爆炸就是判断arri是否小于等于6,因为使用了无符号数判断ja,还要满足a

16、rri=0。后面有一个小循环,取当前的i并加1,然后增长到5,设这个变量为ii,则8048e53: 39 44 b5 c0 cmp %eax,-0x40(%ebp,%esi,4) 8048e57: 75 ee jne 8048e47 8048e59: e8 21 04 00 00 call 804927f 判断语句让arrii = arri-1时触发炸弹。把这段语句翻译为C代码如下:for (int i=0;i!=6;)if (arri-15) Explode_bomb();i +;for (int ii = i;ii=5;ii+) if (arrii=arri-1) Explode_bomb

17、();也就是arr中的元素必须是06的数字,而且不能重复。下面的一段程序又是一个二重循环8048e60: 8b 52 08 mov 0x8(%edx),%edx 8048e63: 83 c0 01 add $0x1,%eax 8048e66: 39 c8 cmp %ecx,%eax 8048e68: 75 f6 jne 8048e60 8048e6a: 89 54 b5 dc mov %edx,-0x24(%ebp,%esi,4) 8048e6e: 83 c3 01 add $0x1,%ebx 8048e71: 83 fb 06 cmp $0x6,%ebx 8048e74: 74 1e je

18、8048e94 8048e76: 89 de mov %ebx,%esi 8048e78: 8b 4c 9d c4 mov -0x3c(%ebp,%ebx,4),%ecx 8048e7c: b8 01 00 00 00 mov $0x1,%eax 8048e81: ba 54 c1 04 08 mov $0x804c154,%edx 8048e86: 83 f9 01 cmp $0x1,%ecx 8048e89: 7f d5 jg 8048e60 8048e8b: eb dd jmp 8048e6a 这段代码是循环寻找0x804c154+arri*8的地址,然后把这块地址放到-0x24(%eb

19、p,%esi,4)中,它应该是储存指针的数组,至于这是指向什么的指针,我们可以在gdb中找到0x804c154看一看。一个叫做node的结构体,那么数组-0x24(%ebp)就是node* nodes 类型。再观察结构体的内部数据,由三部分组成,value,number和next,这是我们熟悉的链表结构,C语言代码如下:Struct nodeInt val;Int num;Node* next;如此一来上面的步骤就说得通了,翻译成C代码(0x804c154用L表示)For (int i = 0;i!=6;i+)Int c = arri, a = 1;Node* d = L;If (c1)For

20、 (;a!=c;a+)d = d-next;Nodesi = d;很显然这段代码就是按照我们输入arr中的六个数,以L为链表头搜索链表的第arri个结点。并把链表结点保存在nodesi中。再下面的一段程序,很显然是按照nodes的顺序重新串接链表的一系列操作。最后一段判断程序,遍历链表并比较链表前一个元素和后一个元素8048ebc: be 05 00 00 00 mov $0x5,%esi 8048ec1: eb 08 jmp 8048ecb 8048ec3: 8b 5b 08 mov 0x8(%ebx),%ebx 8048ec6: 83 ee 01 sub $0x1,%esi 8048ec9

21、: 74 10 je 8048edb 8048ecb: 8b 43 08 mov 0x8(%ebx),%eax 8048ece: 8b 00 mov (%eax),%eax 8048ed0: 39 03 cmp %eax,(%ebx) 8048ed2: 7d ef jge 8048ec3 8048ed4: e8 a6 03 00 00 call 804927f 8048ed9: eb e8 jmp 8048ec3 Eax是ebx的后一个链表结点,必须满足ebxeax才能不触发炸弹,也就是整个链表的值必须是降序的。这样这一关的用意就很明显了,就是要我们输入6个数字,这六个数字就是重排后链表结点的

22、顺序;我们要保证这个顺序是降序的,就要按照合适的顺序输入1 2 3 4 5 6.排序的工作可以借助高级语言完成,python的实现如下。即本关答案为2 6 5 4 3 14.7 隐藏关我们惊喜地发现事情还没有结束!在phase_6之后还有一段,它要怎么触发呢?我们在源码中搜索它,发现它出现在下面的位置。在函数中,而这个函数是每次拆弹成功后才被调用的。读代码可以发现这里先调用scanf,要我们输入一段字符串;然后调用,当相等时才能调用函数。可是每一关最后都调用这个函数,这个输入应该出现在哪里呢?找到scanf的输入参数查看其中的格式化字符如下:是跟在两个整数后面的一段字符串!要输入两个整数的是第

23、三关和第四关,而第三关已经有了输入数量的限制,所以触发关卡是要在第四关后面多输入一串特殊字符串。后面把输入字符串和0x804a4d0进行比较,打开0x804a4d0查看,它就是特殊字符串。进关条件就是在第四关输入13 31 SecretSYSU我们进入了关卡,下面浏览这一关的代码。可以看见函数一开始调用了read_line,把输入放在eax中。然后是函数的调用,strtol(%eax, NULL, 10)。也就是我们输入的字符串应该是10进制数,它会被转换成一个长整形。紧随其后有一条判断8048f62: 8d 40 ff lea -0x1(%eax),%eax8048f65: 83 c4 10

24、 add $0x10,%esp8048f68: 3d e8 03 00 00 cmp $0x3e8,%eax8048f6d: 77 35 ja 8048fa4 判断(%eax-1)0x3e8时触发爆炸,限制了我们的输入范围。之后是fun7的调用,参数分别为我们的输入和$0x804c0a0,查看内容可知为24.执行fun7(0x804c0a0,input),后面可以看到如果返回值为3就完成本关。查看fun7函数,通读可知是一个if -else if -else语句。8048efa: 8b 55 08 mov 0x8(%ebp),%edx8048efd: 8b 4d 0c mov 0xc(%ebp

25、),%ecx8048f00: 85 d2 test %edx,%edx8048f02: 74 3c je 8048f40 从栈中获取参数,设两个参数为int* p, int x首先判断p=NULL,如果相等就ret并返回-1.8048f40: b8 ff ff ff ff mov $0xffffffff,%eax 8048f45: eb cc jmp 8048f13 然后是分支判断语句8048f04: 8b 1a mov (%edx),%ebx8048f06: 39 cb cmp %ecx,%ebx8048f08: 7f 0e jg 8048f18 8048f0a: b8 00 00 00 0

26、0 mov $0x0,%eax8048f0f: 39 cb cmp %ecx,%ebx8048f11: 75 18 jne 8048f2b 8048f13: 8b 5d fc mov -0x4(%ebp),%ebx8048f16: c9 leave 8048f17: c3 ret当*pecx时,返回fun7(*(a + 4), b)*2当*p=ecx时,返回0Else,返回fun7(*(a + 8), b)*2+1用C语言描述为int fun7(int *a, int b) if (a = NULL) return -1; int ret = 0; if (*a - b 0) ret = fu

27、n7(*(a + 4), b); ret *= 2 else if (*a - b = 0) return 0; else ret = fun7(*(a + 8), b); ret = ret * 2 + 1; return ret;涉及到内存0x804c0a0连续的块中的内容,查看之。很难一眼看出答案,所以不妨借助高级语言进行模拟。对内存的访问可以借助高级语言的哈希表实现,比如这里我使用python的字典,它的灵活性让哈希表可以用地址的数值模拟访问。这样借助mem函数和memory哈希表,对定义好的地址有确定的返回值,未定义的地址有内容为0.再寻求返回值为3的情况,找到输入b=107时可以达

28、成。所以这隐藏关的答案也被我们找到,是107.怎么感觉隐藏关的难度并没有phase6大五. 实验心得虽然说本实验中,7个关卡的难度是不断增加的,但从我个人的体验上,解决问题的难度却是不断减小的。这应该是因为在实验过程中,我不断在学习新的调试工具,不断提升对汇编码的熟悉度,以及不断增强对逆向过程的理解。这个实验的核心就是逆向工程,七个关卡依次是C语言中的函数调用、循环和数组、switch语句、递归、寻址方式、多重循环及结构体,和隐藏关卡的综合题。由于我并没有任何汇编和x86基础,在实验的开始,我几乎没法理解汇编代码在做些什么。然而借助帮助手册和搜索引擎,我逐渐开始能够理解汇编代码的含义和工作方式。应该说“看不懂汇编代码”是实验中我面临的第

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2