飞道的博客

作业_二进制炸弹_讲解

514人阅读  评论(0)

简单的前言

最近的作业有个二进制炸弹问题,具体点说就是使用汇编语言完成一些小问题,形式比较有趣,一起看看吧。

题目描述

  • 实验目的
    通过对一个二进制可执行程序(称为“二进制炸弹”)的理解和逆向工程,加深对对程序的机器级表示、汇编语言、调试器和逆向工程等方面知识的理解和掌握。

  • 实验内容
    作为实验目标的二进制炸弹“binary bombs” Linux可执行程序包含了多个阶段(或关卡),在每个阶段程序要求你输入一个特定字符串,如果输入满足程序代码所定义的要求,该阶段的炸弹就被拆除了,否则程序输出“炸弹爆炸BOOM!!! ”的提示并转到下一阶段再次等待对应的输入 ——实验的目标是设法得出解除尽可能多阶段的字符串。
    为完成二进制炸弹拆除任务,需要通过反汇编和理解可执行炸弹文件程序或使用gdb调试器跟踪每一阶段的机器代码,从中理解关键机器指令的行为和作用,进而设法推断拆除炸弹所需的目标字符串。

  • 实验环境:Linux 32-bit,C/汇编语言

一般来说,正在看本文的你肯定装好了虚拟机,和能运行32位程序的Linux系统,好了话不多说,系好安全带,准备出发。

环境准备

  1. 将炸弹数据包bomblab.tar(或解压缩后的文件夹)拷贝到虚拟机目录中,并使用图形化界面或者cmd进入炸弹压缩包所在目录(不会真有人不用图形界面直接肝黑白屏的代码吧,不会吧不会吧),
学生实验数据包:bomblab.tar(随不同学号有所不同)
解压命令:tar xvf bomblab.tar
数据包中包含下面文件:
bomb:二进制可执行炸弹程序
bomb.c:bomb程序的main函数
一些工具
objdump:反汇编二进制炸弹程序,获得其中汇编指令供分析
objdump -d bomb     	输出bomb程序的反汇编结果
objdump -t bomb		打印bomb程序的符号表,其中包含bomb中所有函数、全局变量的名称和存储地址

而你需要的是,按以下步骤进行

1、先解压
2、objdump -d bomb > bomb.s    获得bomb程序的反汇编结果并保存于文本文件bomb.s中供分析

好了,现在多了一个小朋友,叫bomb.s 可以直接双击打开

打开以后就是代码,看不懂没关系,接下来的日子你不得不看的懂这些优美的代码(hhh)。

打开以后先来看看,按ctrl+f进行搜索,找到第一个炸弹phase_0

·

~~~好了,本期教程到此结束,剩下的内容自己看看代码就会了~

·
·
不闹了严肃点,我们继续前进。

二进制炸弹目标程序

包含了7个阶段以及1个隐藏阶段,分别集中考察对以下二进制程序表示各方面的理解和掌握:

  • 阶段0:字符串比较
    阶段1:浮点表示
    阶段2:循环
    阶段3:条件/分支
    阶段4:递归调用和栈
    阶段5:指针
    阶段6:链表/指针/结构
    隐藏阶段:只有给本文点赞以后才会出现(作为最后一个阶段)

接下来我们采用葫芦娃救爷爷模式(一个一个解决),马上开始,没上厕所的赶快去,喝水的喝水,犯困的抽自己两下,活动活动脖子,精神点【doge】.

实验阶段0 - 字符串比较

08049465 <phase_0>:
 8049465:	55                   	push   %ebp
 8049466:	89 e5                	mov    %esp,%ebp
 8049468:	83 ec 08             	sub    $0x8,%esp
 804946b:	83 ec 08             	sub    $0x8,%esp
 804946e:	68 d8 b1 04 08       	push   $0x804b1d8
 8049473:	ff 75 08             	pushl  0x8(%ebp)
 8049476:	e8 05 08 00 00       	call   8049c80 <strings_not_equal>
 804947b:	83 c4 10             	add    $0x10,%esp
 804947e:	85 c0                	test   %eax,%eax
 8049480:	74 0c                	je     804948e <phase_0+0x29>
 8049482:	e8 61 0a 00 00       	call   8049ee8 <explode_bomb>
 8049487:	b8 00 00 00 00       	mov    $0x0,%eax
 804948c:	eb 05                	jmp    8049493 <phase_0+0x2e>
 804948e:	b8 01 00 00 00       	mov    $0x1,%eax
 8049493:	c9                   	leave  
 8049494:	c3                   	ret    

这一题比较简单,因为课程文档里有详细讲解。简单说下吧。

  • 右键打开终端,输入 gdb bomb
  • 然后打断点 输入 b phase_0
  • 之后执行 输入 r
    如图所示

    看到了前两句欢迎语句,是不是很开心呢。have a nice day 哦

以看到,第11行代码会调用 <explode_bomb> ,也就是引爆炸弹,这不是我们所想要的,因此我们要避免程序运行到这一行。观察程序的结构,程序在第8行调用 strings_not_equal ,比较了 %eax和 %eax中的内容,而在这之前,程序push了 $0x804b1d8处的数据移动寄存器中,并可以猜到,地址$0x804b1d8处的数据是程序内置的正确答案,正是我们输入的字符串。
所以现在的问题是:如何获取地址$0x804b1d8处的数据内容?为此,我们需要运行程序,并且在合适的位置停下,这样你就可以查看答案了。
所以这么操作:

先随便输入几个字符,然后回车,
程序停在了断点处,然后用x/s 地址
(温馨小贴士,亲这边建议您右键单击复制粘贴呢哦,终端里不能ctrl+CV呢哦)
回车,出现了一串字符,为答案,复制保存即可。

先创建个文件保存答案

  • 方法:输入 gedit 文件名字,就可以创建成功啦。

继续。
重新打开终端,验证一下。
这次断点打在phase_1 别忘了。
还有那个运行改成r code 就可以直接运行读入文本里的答案了。
仔细点慢慢来。

欢迎语句下多了一行文字,大概意思就是答案正确,你好棒棒。
go on

实验阶段1 - 浮点表示

好了,经过第0个题,我们已经熟悉了很多,接着看看。

因为时间问题。不写太详细了,只写一下最快速的解题方法。而且对于汇编语言这一块,笔者水平确实有限,刚好能做题,具体知识原理还在摸爬滚打,如感觉光解题不讲知识点没营养,点个赞就可以关闭本文章了【坏笑】。

第1题代码

08049495 <phase_1>:
 8049495:	55                   	push   %ebp
 8049496:	89 e5                	mov    %esp,%ebp
 8049498:	83 ec 18             	sub    $0x18,%esp
 804949b:	c7 45 f4 9b 3a c7 17 	movl   $0x17c73a9b,-0xc(%ebp)
 80494a2:	db 45 f4             	fildl  -0xc(%ebp)
 80494a5:	d9 5d f0             	fstps  -0x10(%ebp)
 80494a8:	8d 45 e8             	lea    -0x18(%ebp),%eax
 80494ab:	50                   	push   %eax
 80494ac:	8d 45 ec             	lea    -0x14(%ebp),%eax
 80494af:	50                   	push   %eax
 80494b0:	68 ff b1 04 08       	push   $0x804b1ff
 80494b5:	ff 75 08             	pushl  0x8(%ebp)
 80494b8:	e8 13 fc ff ff       	call   80490d0 <__isoc99_sscanf@plt>
 80494bd:	83 c4 10             	add    $0x10,%esp
 80494c0:	83 f8 02             	cmp    $0x2,%eax
 80494c3:	74 0c                	je     80494d1 <phase_1+0x3c>
 80494c5:	e8 1e 0a 00 00       	call   8049ee8 <explode_bomb>
 80494ca:	b8 00 00 00 00       	mov    $0x0,%eax
 80494cf:	eb 34                	jmp    8049505 <phase_1+0x70>
 80494d1:	8d 45 f0             	lea    -0x10(%ebp),%eax
 80494d4:	83 c0 02             	add    $0x2,%eax
 80494d7:	0f b7 00             	movzwl (%eax),%eax
 80494da:	0f bf d0             	movswl %ax,%edx
 80494dd:	8b 45 ec             	mov    -0x14(%ebp),%eax
 80494e0:	39 c2                	cmp    %eax,%edx
 80494e2:	75 10                	jne    80494f4 <phase_1+0x5f>
 80494e4:	8d 45 f0             	lea    -0x10(%ebp),%eax
 80494e7:	0f b7 00             	movzwl (%eax),%eax
 80494ea:	0f bf d0             	movswl %ax,%edx
 80494ed:	8b 45 e8             	mov    -0x18(%ebp),%eax
 80494f0:	39 c2                	cmp    %eax,%edx
 80494f2:	74 0c                	je     8049500 <phase_1+0x6b>
 80494f4:	e8 ef 09 00 00       	call   8049ee8 <explode_bomb>
 80494f9:	b8 00 00 00 00       	mov    $0x0,%eax
 80494fe:	eb 05                	jmp    8049505 <phase_1+0x70>
 8049500:	b8 01 00 00 00       	mov    $0x1,%eax
 8049505:	c9                   	leave  
 8049506:	c3                   	ret    

啊呀,这么多字啊,好烦啊,喝口奶茶压压惊。

好了,只讲快速解题步骤,如图。

随便输入几个字符,回车
输入 ni 进行逐步调试。一直回车。
发现到0x080494c5 然后boom了,所以回看代码看看有什么问题
发现前两行

 80494c0:	83 f8 02             	cmp    $0x2,%eax
 80494c3:	74 0c                	je     80494d1 <phase_1+0x3c>
 80494c5:	e8 1e 0a 00 00       	call   8049ee8 <explode_bomb>

有个cmp是比较的意思,比较了0x2和%eax,就是十六进制数和寄存器的值比较,
je是相等,行灯就跳转到80494d1 <phase_1+0x3c>,否则继续下一行,
也就是call 8049ee8 <explode_bomb>。
要想不爆炸,得相等。往前看,有个明码地址,非常明目张胆。先看看它是什么东西。

C语言表示的两个整数。
哦,现在大概知道了,需要输入2个整数,第一步是判断是不是2个数,不是爆炸。所以重头开始
继续输入 r 即可,不必关终端。

仔细点,对照操作到上一步,然后单步调试。
输入 ni 之前,先看看思路,到什么地方会boom。

往下继续看,发现有一个cmp,也就是比较操作。然后他的下一行是jne,也就是说,不相等就跳转到后面的80494f4然后可以根据程序进行查找对照,发现这个4f4这一行,是炸弹boom的操作,
所以肯定需要两个数相等才可以

 80494e0:	39 c2                	cmp    %eax,%edx
 80494e2:	75 10                	jne    80494f4 <phase_1+0x5f>

以及

 80494f0:	39 c2                	cmp    %eax,%edx
 80494f2:	74 0c                	je     8049500 <phase_1+0x6b>
 80494f4:	e8 ef 09 00 00       	call   8049ee8 <explode_bomb>

这一行同理跟前面是一个意思,也是要两数相等。所以现在单步调试的目的就是比较这两次的两个数是否相等。直接ni一直到80494e0。

我们发现之前前面的部分那一步没有爆炸,说明第一步确实是比较是不是输入了两个数。
然后输入 i r 查看寄存器内容。

发现cmp 的是%eax,%edx,而我们输入的是1 ,就是eax,edx是19902,用脚指头想一想,发现我们应该第一个说输入的和edx一样才可以。
于是得到第一个答案19902

继续单步调试哦
修改第一个为正确答案,下一次ni到这一行

80494f0:	39 c2                	cmp    %eax,%edx

看图


所以第二个答案是14805.
不解释。。

把这两个数保存在答案的文本里。然后可以验证一下。验证之前,在打断点的时候把断点打到第二题,然后然后运行答案文本就可以了。


最后一行看到了吧。就是说通过了。hhh我好棒【doge】

实验阶段2 - 循环

先看代码

08049507 <phase_2>:
 8049507:	55                   	push   %ebp
 8049508:	89 e5                	mov    %esp,%ebp
 804950a:	83 ec 28             	sub    $0x28,%esp
 804950d:	83 ec 04             	sub    $0x4,%esp
 8049510:	6a 06                	push   $0x6
 8049512:	8d 45 dc             	lea    -0x24(%ebp),%eax
 8049515:	50                   	push   %eax
 8049516:	ff 75 08             	pushl  0x8(%ebp)
 8049519:	e8 a8 06 00 00       	call   8049bc6 <read_n_numbers>
 804951e:	83 c4 10             	add    $0x10,%esp
 8049521:	85 c0                	test   %eax,%eax
 8049523:	75 07                	jne    804952c <phase_2+0x25>
 8049525:	b8 00 00 00 00       	mov    $0x0,%eax
 804952a:	eb 59                	jmp    8049585 <phase_2+0x7e>
 804952c:	8b 45 dc             	mov    -0x24(%ebp),%eax
 804952f:	3d a3 00 00 00       	cmp    $0xa3,%eax
 8049534:	74 0c                	je     8049542 <phase_2+0x3b>
 8049536:	e8 ad 09 00 00       	call   8049ee8 <explode_bomb>
 804953b:	b8 00 00 00 00       	mov    $0x0,%eax
 8049540:	eb 43                	jmp    8049585 <phase_2+0x7e>
 8049542:	c7 45 f4 01 00 00 00 	movl   $0x1,-0xc(%ebp)
 8049549:	eb 2f                	jmp    804957a <phase_2+0x73>
 804954b:	8b 45 f4             	mov    -0xc(%ebp),%eax
 804954e:	8b 44 85 dc          	mov    -0x24(%ebp,%eax,4),%eax
 8049552:	8b 55 f4             	mov    -0xc(%ebp),%edx
 8049555:	83 ea 01             	sub    $0x1,%edx
 8049558:	8b 54 95 dc          	mov    -0x24(%ebp,%edx,4),%edx
 804955c:	8b 4d f4             	mov    -0xc(%ebp),%ecx
 804955f:	01 c9                	add    %ecx,%ecx
 8049561:	29 ca                	sub    %ecx,%edx
 8049563:	83 c2 01             	add    $0x1,%edx
 8049566:	39 d0                	cmp    %edx,%eax
 8049568:	74 0c                	je     8049576 <phase_2+0x6f>
 804956a:	e8 79 09 00 00       	call   8049ee8 <explode_bomb>
 804956f:	b8 00 00 00 00       	mov    $0x0,%eax
 8049574:	eb 0f                	jmp    8049585 <phase_2+0x7e>
 8049576:	83 45 f4 01          	addl   $0x1,-0xc(%ebp)
 804957a:	83 7d f4 05          	cmpl   $0x5,-0xc(%ebp)
 804957e:	7e cb                	jle    804954b <phase_2+0x44>
 8049580:	b8 01 00 00 00       	mov    $0x1,%eax
 8049585:	c9                   	leave  
 8049586:	c3                   	ret    

先看到<read_n_numbers>,我英语好,擅长翻译,花几分钟看了一下,意思是读取n个数。这里都直接说吧,n就是6。也就是说这一题需要输入六个数字。
解题思路与上一题完全一样。。ni调试。

等等,先看看ni到哪里。我输入的六个数字是123456。有顺序,而且比较小,便于观察题的规律。

看第一个boom前几行,于是锁定 804952f。开始调试!

 804952f:	3d a3 00 00 00       	cmp    $0xa3,%eax
 8049534:	74 0c                	je     8049542 <phase_2+0x3b>
 8049536:	e8 ad 09 00 00       	call   8049ee8 <explode_bomb>


发现这里是1,也就是我们输入的第一个数,但是cmp的是0xa3,换成十进制就是163,对!聪明如你,已经想到第一个数应该是163.

然后相等就跳转,从而避开了炸弹。je 8049542 <phase_2+0x3b>

所以!!!!!!自己找一下,应该可以找到那剩余的5个数吧。。

好吧,不可以。那就一起来看一下吧,简单提示一下。
首先第一个数应该对才行。重新运行,输入r.

然后单步调试。

 8049566:	39 d0                	cmp    %edx,%eax
 8049568:	74 0c                	je     8049576 <phase_2+0x6f>
 804956a:	e8 79 09 00 00       	call   8049ee8 <explode_bomb>

到这一行。快去调试!【doge】

cmp的是2和162,聪明如你,是不是已经想到第二个数是什么了。。。。。。。对,就是162,太聪明了叭【破音】。

好了,剩下的不写了,步骤都一样,最后结果6个数。

保存进答案文件夹里。
下一个。

实验阶段3 - 条件/分支

08049587 <phase_3>:
 8049587:	55                   	push   %ebp
 8049588:	89 e5                	mov    %esp,%ebp
 804958a:	83 ec 18             	sub    $0x18,%esp
 804958d:	c7 45 f4 00 00 00 00 	movl   $0x0,-0xc(%ebp)
 8049594:	c7 45 f0 00 00 00 00 	movl   $0x0,-0x10(%ebp)
 804959b:	8d 45 e8             	lea    -0x18(%ebp),%eax
 804959e:	50                   	push   %eax
 804959f:	8d 45 ec             	lea    -0x14(%ebp),%eax
 80495a2:	50                   	push   %eax
 80495a3:	68 ff b1 04 08       	push   $0x804b1ff
 80495a8:	ff 75 08             	pushl  0x8(%ebp)
 80495ab:	e8 20 fb ff ff       	call   80490d0 <__isoc99_sscanf@plt>
 80495b0:	83 c4 10             	add    $0x10,%esp
 80495b3:	89 45 f0             	mov    %eax,-0x10(%ebp)
 80495b6:	83 7d f0 01          	cmpl   $0x1,-0x10(%ebp)
 80495ba:	7f 0f                	jg     80495cb <phase_3+0x44>
 80495bc:	e8 27 09 00 00       	call   8049ee8 <explode_bomb>
 80495c1:	b8 00 00 00 00       	mov    $0x0,%eax
 80495c6:	e9 93 00 00 00       	jmp    804965e <phase_3+0xd7>
 80495cb:	8b 45 ec             	mov    -0x14(%ebp),%eax
 80495ce:	83 e8 35             	sub    $0x35,%eax
 80495d1:	83 f8 09             	cmp    $0x9,%eax
 80495d4:	77 63                	ja     8049639 <phase_3+0xb2>
 80495d6:	8b 04 85 08 b2 04 08 	mov    0x804b208(,%eax,4),%eax
 80495dd:	ff e0                	jmp    *%eax
 80495df:	c7 45 f4 d5 00 00 00 	movl   $0xd5,-0xc(%ebp)
 80495e6:	eb 5d                	jmp    8049645 <phase_3+0xbe>
 80495e8:	c7 45 f4 d5 00 00 00 	movl   $0xd5,-0xc(%ebp)
 80495ef:	eb 54                	jmp    8049645 <phase_3+0xbe>
 80495f1:	c7 45 f4 cb 03 00 00 	movl   $0x3cb,-0xc(%ebp)
 80495f8:	eb 4b                	jmp    8049645 <phase_3+0xbe>
 80495fa:	c7 45 f4 d5 00 00 00 	movl   $0xd5,-0xc(%ebp)
 8049601:	eb 42                	jmp    8049645 <phase_3+0xbe>
 8049603:	c7 45 f4 cb 03 00 00 	movl   $0x3cb,-0xc(%ebp)
 804960a:	eb 39                	jmp    8049645 <phase_3+0xbe>
 804960c:	c7 45 f4 d5 00 00 00 	movl   $0xd5,-0xc(%ebp)
 8049613:	eb 30                	jmp    8049645 <phase_3+0xbe>
 8049615:	c7 45 f4 cb 03 00 00 	movl   $0x3cb,-0xc(%ebp)
 804961c:	eb 27                	jmp    8049645 <phase_3+0xbe>
 804961e:	c7 45 f4 cb 03 00 00 	movl   $0x3cb,-0xc(%ebp)
 8049625:	eb 1e                	jmp    8049645 <phase_3+0xbe>
 8049627:	c7 45 f4 d5 00 00 00 	movl   $0xd5,-0xc(%ebp)
 804962e:	eb 15                	jmp    8049645 <phase_3+0xbe>
 8049630:	c7 45 f4 cb 03 00 00 	movl   $0x3cb,-0xc(%ebp)
 8049637:	eb 0c                	jmp    8049645 <phase_3+0xbe>
 8049639:	e8 aa 08 00 00       	call   8049ee8 <explode_bomb>
 804963e:	b8 00 00 00 00       	mov    $0x0,%eax
 8049643:	eb 19                	jmp    804965e <phase_3+0xd7>
 8049645:	8b 45 e8             	mov    -0x18(%ebp),%eax
 8049648:	39 45 f4             	cmp    %eax,-0xc(%ebp)
 804964b:	74 0c                	je     8049659 <phase_3+0xd2>
 804964d:	e8 96 08 00 00       	call   8049ee8 <explode_bomb>
 8049652:	b8 00 00 00 00       	mov    $0x0,%eax
 8049657:	eb 05                	jmp    804965e <phase_3+0xd7>
 8049659:	b8 01 00 00 00       	mov    $0x1,%eax
 804965e:	c9                   	leave  
 804965f:	c3                   	ret    

这一行很熟悉。应该知道什么意思叭。
读取2个数,所以这一关也是要读取两个数。

80495a3:	68 ff b1 04 08       	push   $0x804b1ff

很容易能够看出第一个炸弹爆炸的地方是要判断是不是读取了两个数。

然后看代码,调试。ni到哪一行呢????

 80495d6:	8b 04 85 08 b2 04 08 	mov    0x804b208(,%eax,4),%eax

发现有个明码地址,太猖狂了,先看看它。

啥也不是。。
看代码吧。

 80495ce:	83 e8 35             	sub    $0x35,%eax
 80495d1:	83 f8 09             	cmp    $0x9,%eax
 80495d4:	77 63                	ja     8049639 <phase_3+0xb2>
 
 8049639是boom
 ja是大于

eax先减0x35也就是53,然后cmp了0x9,也就是9,小学加减法,所以eax是53+9=62.最大是62,先试试62看看
更改答案的输入,重新来。

继续吧,,看代码到哪一行比较好呢

 8049648:	39 45 f4             	cmp    %eax,-0xc(%ebp)
 804964b:	74 0c                	je     8049659 <phase_3+0xd2>
 804964d:	e8 96 08 00 00       	call   8049ee8 <explode_bomb>

对8049648这一行,来吧,调试

好像不大对。em…
细心点!慢慢看,与随后一个boom相邻,在它上面不远处,也有个boom,那么什么时候会用到它呢。调试康康。

发现异常!
单步调试的时候这里跳转的很多,所以看看它有什么猫腻。

 8049630:	c7 45 f4 cb 03 00 00 	movl   $0x3cb,-0xc(%ebp)
 8049637:	eb 0c                	jmp    8049645 <phase_3+0xbe>
 8049639:	e8 aa 08 00 00       	call   8049ee8 <explode_bomb>

这里有比较?按捺住你的小激动,显然这里是结果。

嗯,没错就是971。
验证一下。第一个是62党的时候,第二个是971。

没毛病搞定。
当然这题是条件语句,根据第一个数不同,结果不唯一。

休息一下,累了累了。读文章的你,再接再厉哦!

等点赞有好多的时候,再继续更hhh


转载:https://blog.csdn.net/cena1001/article/details/109570188
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场