拆炸弹实验报告.docx

上传人:b****7 文档编号:9402337 上传时间:2023-02-04 格式:DOCX 页数:18 大小:200.63KB
下载 相关 举报
拆炸弹实验报告.docx_第1页
第1页 / 共18页
拆炸弹实验报告.docx_第2页
第2页 / 共18页
拆炸弹实验报告.docx_第3页
第3页 / 共18页
拆炸弹实验报告.docx_第4页
第4页 / 共18页
拆炸弹实验报告.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

拆炸弹实验报告.docx

《拆炸弹实验报告.docx》由会员分享,可在线阅读,更多相关《拆炸弹实验报告.docx(18页珍藏版)》请在冰豆网上搜索。

拆炸弹实验报告.docx

拆炸弹实验报告

拆炸弹实验报告

 

课程实验报告

 

课程名称:

计算机组成与结构

实验名称:

拆炸弹

专业班级:

姓名:

学号:

完成时间:

(一)实验目的:

程序运行中有6个关卡(6个phase),每个phase需要用户在终端上输入特定的字符或者数字才能通关,否则会引爆炸弹!

那么如何才能知道输入什么内容呢?

这需要你使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。

然后分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符通关。

(二)实验环境:

虚拟机ubuntu系统下32位操作系统,终端,gdb工具。

(三)实验目的和操作:

拆炸弹准备操作:

查看给出的bomb.c中的代码,得知控制检测密码正误的6个函数分别为:

phase_1,phase_2,phase_3,phase_4,phase_5,phase_6。

使用gbd工具对可执行文件bomb进行反汇编:

打开bomb可执行文件所在的文件夹输入反汇编命令objdump-dbomb后,出现了大量汇编代码,在终端窗口可以看到很多行的汇编代码。

也可以使用汇编指令objdump-dbomb>1.txt将汇编代码输出到服务器上一个自动生成的叫1.txt的文件中。

开始拆炸弹:

:

的反汇编代码如下:

0x08048f61<+0>:

push%ebp

0x08048f62<+1>:

mov%esp,%ebp

0x08048f64<+3>:

sub$0x18,%esp

0x08048f67<+6>:

movl0x804a15c,0x4(%esp)//sp寄存器地址指向$0x804a15c

0x08048f6f<+14>:

mov0x8(%ebp),%eax将$0x804a15c的数据移给eax寄存器

0x08048f72<+17>:

mov%eax,(%esp)//函数条用的准备过程

0x08048f75<+20>:

callx8048fab

0x08048f7a<+25>:

test%eax,%eax//与这一行比较用户输入和$0x804a15c中的值

0x08048f7c<+27>:

je0x8048f83

0x08048f7e<+29>:

callx80490d1

0x08048f83<+34>:

leave

0x08048f84<+35>:

ret

通过分析代码可知:

phase_1的密码是固定储存在$0x804a15c中的。

令$0x804a15c中的数据与用户输入的数据比较,若相同则跳过explode_bomb,避开炸弹。

用命令x/s0x804a15c查看其中的数据如下:

输入WehavetostandwithourNorthKoreanallies.

结果为:

结果正确。

 

反汇编代码如下:

0x08048d6a<+0>:

push%ebp

0x08048d6b<+1>:

mov%esp,%ebp

0x08048d6d<+3>:

push%esi

0x08048d6e<+4>:

push%ebx

0x08048d6f<+5>:

sub$0x30,%esp

0x08048d72<+8>:

lea-0x20(%ebp),%eax

0x08048d75<+11>:

mov%eax,0x4(%esp)

0x08048d79<+15>:

mov0x8(%ebp),%eax

0x08048d7c<+18>:

mov%eax,(%esp)

0x08048d7f<+21>:

call0x804910b读取六个数字

0x08048d84<+26>:

cmpl$0x0,-0x20(%ebp)0和第一个数字比较,不相等则爆炸。

0x08048d88<+30>:

jne0x8048d90

0x08048d8a<+32>:

cmpl$0x1,-0x1c(%ebp)1和第二个数字比较,相等则跳过爆炸。

0x08048d8e<+36>:

je0x8048d95

0x08048d90<+38>:

call0x80490d1

0x08048d95<+43>:

lea-0x18(%ebp),%ebxebx指向第三个数字。

0x08048d98<+46>:

lea-0x8(%ebp),%esiesi指向第六个数字再向后移一位的地址。

0x08048d9b<+49>:

mov-0x4(%ebx),%eaxebx向前第一位的数字赋给eax。

0x08048d9e<+52>:

add-0x8(%ebx),%eaxeax再加上ebx向前第二位的数字。

0x08048da1<+55>:

cmp%eax,(%ebx)比较ebx前两位的和与ebx指向的数字。

0x08048da3<+57>:

je0x8048daa相等则跳过爆炸(explode_bomb)

0x08048da5<+59>:

call0x80490d1

0x08048daa<+64>:

add$0x4,%ebxebx地址向后移动一位(四个字节)。

0x08048dad<+67>:

cmp%esi,%ebx如果还未超过第六位数字,则跳转0x8048d9行。

0x08048daf<+69>:

jne0x8048d9b

0x08048db1<+71>:

add$0x30,%esp

0x08048db4<+74>:

pop%ebx

0x08048db5<+75>:

pop%esi

0x08048db6<+76>:

pop%ebp

0x08048db7<+77>:

ret

从上面的代码分析可知:

phase_2的密码需要输入六位数字,并且第一个是0,第二个是1,然后执行到0x8048d9b这一行代码发现往下运行会出现一个循环,两条重要指令是imull-0x4(%esi,%edx,4),%eax和cmp%eax,(%esi,%edx,4),其中%eax和%edx在每次循环中加1直到寄存器中值超过6,程序执行完毕。

在循环中执行的是一个数等于前两个数之和,寄存器ebx每次循环将向前第一位的数字赋给寄存器eax。

从而实现了计算前6位的斐波那契数列的值为:

011235。

执行结果如下:

 

反汇编代码如下:

0x08048ea1<+0>:

push%ebp

0x08048ea2<+1>:

mov%esp,%ebp

0x08048ea4<+3>:

sub$0x28,%esp

0x08048ea7<+6>:

lea-0x10(%ebp),%eax

0x08048eaa<+9>:

mov%eax,0xc(%esp)此处为第二个数字。

0x08048eae<+13>:

lea-0xc(%ebp),%eax

0x08048eb1<+16>:

mov%eax,0x8(%esp)此处为第一个数字。

0x08048eb5<+20>:

movl$0x804a23e,0x4(%esp)用x/s0x804a23e命令查看$0x804a23e为

0x08048ebd<+28>:

mov0x8(%ebp),%eax%d%d,即要输入两个整数,上面已经指出。

0x08048ec0<+31>:

mov%eax,(%esp)

0x08048ec3<+34>:

call0x8048840<__isoc99_sscanf@plt>

0x08048ec8<+39>:

cmp$0x1,%eax以上两行即要求输入至少两组数据,否则引爆。

0x08048ecb<+42>:

jg0x8048ed2

0x08048ecd<+44>:

call0x80490d1

0x08048ed2<+49>:

cmpl$0x7,-0xc(%ebp)第一个数大于7引爆,即第一个数小于等于7。

0x08048ed6<+53>:

ja0x8048f43

0x08048ed8<+55>:

mov-0xc(%ebp),%eax

0x08048edb<+58>:

jmp*0x804a1a0(,%eax,4)跳转至0x804a1a0+eax*4(第一个数)内数据所

0x08048ee2<+65>:

mov$0x0,%eax指的行数。

0x08048ee7<+70>:

jmp0x8048f3c

0x08048ee9<+72>:

mov$0x0,%eax

0x08048eee<+77>:

xchg%ax,%ax

0x08048ef0<+79>:

jmp0x8048f37

0x08048ef2<+81>:

mov$0x0,%eax

0x08048ef7<+86>:

jmp0x8048f32

0x08048ef9<+88>:

mov$0x0,%eax

0x08048efe<+93>:

xchg%ax,%ax

0x08048f00<+95>:

jmp0x8048f2d

0x08048f02<+97>:

mov$0x0,%eax

0x08048f07<+102>:

jmp0x8048f28

0x08048f09<+104>:

mov$0x0,%eax

0x08048f0e<+109>:

xchg%ax,%ax

0x08048f10<+111>:

jmp0x8048f23

0x08048f12<+113>:

mov$0x314,%eax当第一个数为0时跳转到此处,第二个数x=788。

0x08048f17<+118>:

jmp0x8048f1e跳转到0x8048f1e。

0x08048f19<+120>:

mov$0x0,%eax

0x08048f1e<+125>:

sub$0x35a,%eaxx=x-858

0x08048f23<+130>:

add$0x2ef,%eaxx=x+751

0x08048f28<+135>:

sub$0x216,%eaxx=x-534

0x08048f2d<+140>:

add$0x216,%eaxx=x+534

0x08048f32<+145>:

sub$0x216,%eaxx=x-534

0x08048f37<+150>:

add$0x216,%eaxx=x+534

0x08048f3c<+155>:

sub$0x216,%eaxx=x-534

0x08048f41<+160>:

jmp0x8048f4d跳转到0x8048f4d行。

0x08048f43<+162>:

call0x80490d1

0x08048f48<+167>:

mov$0x0,%eax

0x08048f4d<+172>:

cmpl$0x5,-0xc(%ebp)第一个数大于5引爆,即第一个数小于等于5。

0x08048f51<+176>:

jg0x8048f58

0x08048f53<+178>:

cmp-0x10(%ebp),%eax第一个数是0时,算得x=147,即第二个数

0x08048f56<+181>:

je0x8048f5d为147。

0x08048f58<+183>:

call0x80490d1

0x08048f5d<+188>:

leave

0x08048f5e<+189>:

xchg%ax,%ax

0x08048f60<+191>:

ret

从以上分析可知:

再往下然后看到jmp

输入指令x/s0x8049abb,得到0x8049abb:

"%d%d",显示出应该输入两个数字。

如果输入不满足两个数,则会引爆炸弹,并且第二个与第一个数的值相关。

第一个值得范围为0---5的整数,当第一个数输入的不是0---5的整数,也会引爆炸弹。

输入的第一个数存入在寄存器eax中,并且根据跳转指令jmp*0x804a1a0(,%eax,4)选择将要跳转的位置,执行相应的代码计算出第二个需要输入的值。

1)当第一个数输入的是0,eax寄存器中对应的值为0,则跳转到指令*0x804a1a0

用指令查看*0x804a1a0的值为:

发现*0x804a1a0对应的值为0x8048f12,找到0x08048f12对应的代码执行发现第二个数计算得结果为:

x=0x(314-35a–2ef–216+216-216+216-216+)=147

2)当输入的第一个数是1时,同理用指令查看*(0x804a1a0+4)的值为

则代码从0x08048f19对应的代码执行第二个数计算得结果为:

x=0x(-35a–2ef–216+216-216+216-216+)=-641

3)同理输入2,3,4,5对应的第二个数字为:

217,534,0,-534

结果打印为:

 

反汇编代码如下:

0x08048e2e<+0>:

push%ebp

0x08048e2f<+1>:

mov%esp,%ebp

0x08048e31<+3>:

sub$0x28,%esp

0x08048e34<+6>:

lea-0x10(%ebp),%eax

0x08048e37<+9>:

mov%eax,0xc(%esp)此处第二段数字。

0x08048e3b<+13>:

lea-0xc(%ebp),%eax

0x08048e3e<+16>:

mov%eax,0x8(%esp)此处第一段数字。

0x08048e42<+20>:

movl$0x804a23e,0x4(%esp)$0x804a23e内为%d%d,即输入两个整数。

0x08048e4a<+28>:

mov0x8(%ebp),%eax

0x08048e4d<+31>:

mov%eax,(%esp)

0x08048e50<+34>:

call0x8048840<__isoc99_sscanf@plt>

0x08048e55<+39>:

cmp$0x2,%eax以上两行要求之前输入的为两个数据,否则引爆。

0x08048e58<+42>:

jne0x8048e66

0x08048e5a<+44>:

mov-0xc(%ebp),%eax

0x08048e5d<+47>:

test%eax,%eax第一段数据大于等于0,否则引爆。

0x08048e5f<+49>:

js0x8048e66

0x08048e61<+51>:

cmp$0xe,%eax第一段数据小于等于14时跳过引爆。

0x08048e64<+54>:

jle0x8048e6b

0x08048e66<+56>:

call0x80490d1

0x08048e6b<+61>:

movl$0xe,0x8(%esp)

0x08048e73<+69>:

movl$0x0,0x4(%esp)

0x08048e7b<+77>:

mov-0xc(%ebp),%eax

0x08048e7e<+80>:

mov%eax,(%esp)

0x08048e81<+83>:

call0x8048b60这几行为运行一个递归函数func4来确定第一

0x08048e86<+88>:

cmp$0x1,%eax段数据的值。

0x08048e89<+91>:

jne0x8048e91

0x08048e8b<+93>:

cmpl$0x1,-0x10(%ebp)第二个数据等于1则跳过爆炸。

0x08048e8f<+97>:

je0x8048e9d

0x08048e91<+99>:

lea0x0(%esi,%eiz,1),%esi

0x08048e98<+106>:

call0x80490d1

0x08048e9d<+111>:

leave

0x08048e9e<+112>:

xchg%ax,%ax

0x08048ea0<+114>:

ret

以上对代码的分析可以看出,第二个数据确定为1。

第一个数据范围为大于等于0,小于14,并且由一个递归函数func4又一次缩小了范围。

但因为这个递归函数太过繁杂,而第一个数据范围又不大,直接将第一个数据从0尝试到13,得到了三个数字8、9、11符合要求。

因此密码有三组:

81,91,111。

 

反汇编代码如下:

0x08048db8<+0>:

push%ebp

0x08048db9<+1>:

mov%esp,%ebp

0x08048dbb<+3>:

push%esi

0x08048dbc<+4>:

push%ebx

0x08048dbd<+5>:

sub$0x20,%esp

0x08048dc0<+8>:

lea-0x10(%ebp),%eax

0x08048dc3<+11>:

mov%eax,0xc(%esp)此处为第二个数。

0x08048dc7<+15>:

lea-0xc(%ebp),%eax

0x08048dca<+18>:

mov%eax,0x8(%esp)此处为第一个数。

0x08048dce<+22>:

movl$0x804a23e,0x4(%esp)$0x804a23e内为%d%d,即输入两个整数。

0x08048dd6<+30>:

mov0x8(%ebp),%eax

0x08048dd9<+33>:

mov%eax,(%esp)

0x08048ddc<+36>:

call0x8048840<__isoc99_sscanf@plt>

0x08048de1<+41>:

cmp$0x1,%eax以上两行保证输入数据多于1组,否则引爆。

0x08048de4<+44>:

jg0x8048deb

0x08048de6<+46>:

call0x80490d1

0x08048deb<+51>:

mov-0xc(%ebp),%eax

0x08048dee<+54>:

and$0xf,%eax按位与,即保留第一个数的后四位。

0x08048df1<+57>:

mov%eax,-0xc(%ebp)

0x08048df4<+60>:

cmp$0xf,%eax第一个数二进制后四位不能为(1111)2,否则引爆。

0x08048df7<+63>:

je0x8048e22

0x08048df9<+65>:

mov$0x0,%ecx

0x08048dfe<+70>:

mov$0x0,%edx

0x08048e03<+75>:

mov$0x804a1c0,%ebx$0x804a1c0指向的是一个数组,下面分析。

0x08048e08<+80>:

add$0x1,%edx

0x08048e0b<+83>:

mov(%ebx,%eax,4),%eax

0x08048e0e<+86>:

add%eax,%ecx

0x08048e10<+88>:

cmp$0xf,%eax

0x08048e13<+91>:

jne0x8048e08以上五行为一个for循环语句,

0x08048e15<+93>:

mov%eax,-0xc(%ebp)

0x08048e18<+96>:

cmp$0xf,%edx上述的for循环要循环15次。

0x08048e1b<+99>:

jne0x8048e22

0x08048e1d<+101>:

cmp%ecx,-0x10(%ebp)确定第二个数的值,下面分析。

0x08048e20<+104>:

je0x8048e27

0x08048e22<+106>:

call0x80490d1

0x08048e27<+111>:

add$0x20,%esp

0x08048e2a<+114>:

pop%ebx

0x08048e2b<+115>:

pop%esi

0x08048e2c<+116>:

pop%ebp

0x08048e2d<+117>:

ret

从代码的分析中可知:

需要输入两个数,并且第一个数的后四位不能为1111,若为1111则引爆炸弹。

在程序中我们会遇到一个给定值0x804a1c0。

我们可以查看其值为:

查看16个值,因为发现后面的循环中需要循环遍历使用16个数。

其中最难懂的代码就是0x08048e0b<+83>:

mov(%ebx,%eax,4),%eax这一行代码,ebx对应的是0x804a1c0对应的首地址。

这句话的意思解释为C语言的意思就是n=a[n]。

寄存器ecx保存的是计算得sum的总值。

这段代码翻译成c语言类似于:

sum=0;

for(i=1;n=15;i++)

{

n=a[n];

sum+=n;

}

其中第一次n取的值应为用户输入的第一个数二进制下的后四位。

之后每次都等于a[n],sum为除去第一次之外所有n取值的和。

采用逆推的方法来求出n第一次取的值。

序号

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

数组

10

2

14

7

8

12

15

11

0

4

1

13

3

9

6

5

for循环当n为15时终止,因此最后一个n为15,对应序号为上一个n,即6。

同理,可以得到,n从第一个到最后一个为:

5123711139480101214615。

sum=15*16/2-5=115。

即用户输入的第二个数为115。

用户输入第一个数二进制下的后四位为0101(即第一个n=5),

由于第一位只要满足输入的数的后四位不为1111,第

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1