lab2操作系统和原理详解

CMU LAB2 解题详解

    1. phase_1

学生输入一个字符串,phase_1进行比较,如果与内部的字符串一致,则该阶段通过,否则炸弹爆炸。

phase_1比较简单,主要用于学生熟悉解题步骤、函数栈帧的构成以及汇编语言。

对于本文档分析的炸弹,字符串为:“Border relations with Canada have never been better.”。

直接根据xshell找到phase所在的位置

分析如下

1、第378行:sub $0x1c, %esp,将函数栈空间扩展了0x1c字节(28个字节)

2、第379行:将0x804a49c放置到了esp+4的地方。

3、第381/382行:将input的内容放置到了esp的地方。注:20(%esp)正好是栈中存放input的内容。

4、第383行:调用strings_not_equal函数。

5、显然,第379行以及第381/382行是在为调用strings_not_equal函数准备参数。在调用strings_not_equal函数之前(即382行执行之后,383行执行之前),函数栈帧变成如下:

6、第384行:test %eax %eax,是对eax寄存器里的内容(string_not_equal函数的返回内容)进行位与操作,如果为0,则置zf标志(零标志)为1,相同为0不同为1;

7、第385行:是一个je指令,je指令判断zf标志(零标志)为1时(也即strings_not_equal函数返回的是0的情况下),跳转到phase_2 + 0x20的地方,即0x8048c20的地方,说明炸弹拆除成功。否则,call 804944b <explode_bomb>,顾名思义,是爆炸炸弹,即拆除炸弹失败。

8、从上面的分析来看,上图中显示的栈帧中,esp的内容是输入的字符串的首地址,而esp + 4的内容是0x804a49c,应该是在程序中保存的被比较的字符串(即拆弹字符串)的首地址,而按照strings_not_equal的名字来看,如果是不等,则返回1,等则返回0。如果等,代表输入的拆弹字符串是正确的。

 

 

 

 

 

 

 

 

 

 

 

 

 

执行第801 - 804行之后,函数栈帧为:

 

 

1、第805行,将esp + 0x14的内容(input(输入字符串首地址))送入到了ebx寄存器,第806行,将esp + 0x18的内容(0x804a49c)送入到了esi寄存器。验证了我们前面所介绍的0x804a49c地址所在的地方应该是拆弹字符串所在的首地址。

2、807-809行:求input字符串的长度,结果送入到edi寄存器。

3、810-811行:求0x804a49c字符串的长度,结果保存在eax寄存器中。

4、812行:将1送入edx,通过后面的分析,可以知道edx存放的是返回结果,也即默认返回结果为1,即不等。

5、813-814行:比较edi和eax的内容,即input字符串与0x804a3fc为首地址的字符串长度进行比较,如果不等,则跳转到strings_not_equal + 0x63的地方:0x804916a + 0x63 = 0x80491cd(此地的指令是将edx的内容送入到eax,并返回,注意第812行,edx的内容被赋值为1),也即返回1,代表两个字符串不等

 

 

 

 

 

 

objdump --start-address=0x804a3fc -s bomb

得到所需要的字符串Border relations with Canada have never been better.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  1. phase_

phase_2要求输入包含6个整数的字符串。phase_2函数从中读取6个整数,并判断其正确性,如果不正确,则炸弹爆炸。phase_2主要考察学生对C语言循环的机器级表示的掌握程度。

观察框架源文件bomb.c:

从上可以看出:

1、首先调用了read_line()函数,用于输入炸弹秘钥,输入放置在char* input中。

2、调用phase_2函数,输入参数即为input,可以初步判断,phase_2函数将输入的input字符串作为参数。

因此下一步的主要任务是从asm.txt中查找在哪个地方调用了readline函数以及phase_2函数。

    1. 寻找并分析调用phase_2函数的代码

打开asm.txt,寻找phase_2函数。

 

 

 

 

分析上面的代码:

1、390 ~ 392行:进行一些压栈,并扩展了函数栈帧。

2、第394-395行:lea 0x18(%esp) %eax、mov %eax 4(%esp),将esp + 18指向的栈的内容的地址放置到esp+4指向的地方。简单的说,当前esp + 4指针指向的空间的内容为esp + 18。(实际上,根据后面的分析,可以知道esp + 4的内容,放的是num[0]的地址esp + 18

3、第396行:将0x40(%esp)的内容放置到esp指向的栈。0x40(%esp)里面的内容实际上就是input字符串首地址。

4、第397行:调用了read_six_numbers函数(顾名思义,从字符串中解析出六个整数),可以猜测实际上第394行到第396行,是在为read_six_numbers函数准备参数。

5、在调用read_six_numbers之前,函数栈帧为:

7、上图所示的函数栈帧中,从esp + 18 ~ esp+2c,共6个栈空间,标记为保存6个整数,实际上从当前的地方并不能完全看出来,可以有些猜测,到后来阅读read_six_numbers时,证实了当前的猜测是正确的。

8、依据以上的分析,read_six_numbers函数的定义:void read_six_numbers(char* input, num);其中第二个参数,是num数组的地址。在后面,会剖析read_six_numbers函数,来证实以上的猜测,下面的分析以以上的栈帧图为基础。

9、第399行:cmp $0x0, 0x18(%esp),0x18(%esp)中是num[0],该语句判断num[0]是否应等于0,如果等,则跳转到phase_2 + 0x27,如果不等,则call explode_bomb(第401行),从此处,可以猜测:num[0]  = 0

10、第401行:cmp $0x1, 0x1c(%esp),0x1c(%esp)中是num[1],该语句判断num[1]是否应等于1,如果等,则跳转到phase_2 + 0x46,如果不等,则call explode_bomb(第401行),从此处,可以猜测:num[0]  = 1

 

11、第412行(8048c62(phase_2 + 0x3e)),将0x20 + esp --> ebx寄存器,即将num[2]的地址送入到ebx寄存器,第413行,将0x30 + esp -->esi,0x30(%esp)是num[5]上面的栈空间,将该栈空间的地址送入到esi。

12、第415行:跳转到8048c4b(即第403行)。

13、第405行:将-0x8(%ebx)的内容送入到eax,-0x8(%ebx)的内容实际上指的是0x18(%esp),也即num[0]送入到eax。

14.第406行 add   -0x4(%ebx),%eax 也就是把ebx-4的位置也就是num[1]和num[2]相加

15 第407行 再把寄存器ebx和eax进行比较也就时num[2]和num[1]+num[0]作比较,如果num[2]!=num[1]+num[0] 则引爆炸弹,所以得到伪代码

1)num[0] = 0,num[1]=1;

2)num[i] = num[i-1]+num[i-2]。(i > 0)

因此,phase_2炸弹秘钥应该是:0 1 1 2 3 5

 

以上所有的分析是建立在六个输入数字是放置在esp + 0x18开始的地址中的前提下的。为确认这一个问题,下面对read_six_numbers函数进行详细分析。

1、第1035行:扩展栈帧,增加了44。

2、第1036行:将0x34(%esp)的内容送到eax,0x34(%esp)的内容正好是num[0]的地址,也即num的首地址,也即eax内容为num[0]的地址。(参见后面的栈帧图)

3、第1037行:将eax + 0x14的地址(即为eax + 0x14)送到edx,eax+0x14正好是num[5]的地址。(参见后面栈帧图)

4、第1038行:将edx的内容送到esp + 0x1c的地方,即将num[5]的地址送到esp+0x1c的地方;

5、第1039行 ~1047行:

1)num[4]地址,送到esp + 0x18

2)num[3]地址,送到esp + 0x14

3)num[2]地址,送到esp + 0x10

4)num[1]地址,送到esp + 0xc

6、第1047行:num[0]地址,送到esp + 8

7、第1048行:0x804a725送入到esp + 4的地方

8、第1050/1051行:0x30(%esp)内容送入到esp,0x30(%esp)内容为input输入首地址。

9、第1052行:调用scanf函数,用于从input中读入6个整数。可以认为前面都是在为scanf函数调用准备参数,包括第1048行,0x804a725实际上是指向一个字符串的首地址,这个字符串为“%d %d %d %d %d %d”(这点将在后面分析

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值