深入理解计算机系统bomb lab

Data lab

Wercker Wercker Wercker
pic

一:实验梗概

Dr.Evil在你的机器上埋了大量的“”二进制炸弹“,你的任务是输入字符串来拆除炸弹。如果输入了正确的字符串,炸弹将被拆除,否则 ”BOOM!!!“
加油吧,拆弹英雄们!!!



bomb lab共有6个关卡:
1-4关卡 10分一个5-6关卡 比较难,15分一个,总共70分

二:实验工具

①objdump

GNU专用debugger工具,简单好用。如果你从来没有debugger过,建议看看gdb Tutorial,下面列出一些该实验中需要的指令

指令效果
run开始运行程序
kill结束运行
finish执行完当前函数
nexti执行一条指令(跳过子程序)
nexti 4执行4条指令
stepi执行一条指令
stepi 4执行4条指令
print/format打印表达式
break设置断点
x/format查看内存里的值
disas function反汇编函数

其中format是:
n 打印几个单位
o(八进制) …x(十六进制)…d(十进制)…u(unsigned)…t(二进制)…f(浮点),s(字符串)
b(bytes)…h(halfword)…w(word)
例:

x/20b mem  打印地址mem的20个字节
x/s mem   打印地址mem的字符串    
print $esp    (是的,你没看错,在gdb里寄存器是用$前缀)    

②:objdump

objdump -t 反汇编程序

四:实验感受

这里写图片描述
为什么我要把最后的实验感受放在前面呢?因为这个实验深刻教育了我。
当我面对满屏黑漆漆的汇编代码的时候,内心有些小崩溃的,当我开始开始做实验的时候,根本不知道从哪里入手,手忙脚乱的输入指令,却没有一丝思路,内心崩溃程度50%。当终于找到路子,开始拆弹时,看到和cs:app里完全不同的汇编代码,他们混乱,复杂,你会有种盲人摸象的感觉,分析了好长时间的代码,发现根本不是重点,崩溃100%
但是,还是坚强QAQ地拆完了炸弹,写下了这篇blog。经过这一次拆弹体验,我才真正学会了调试,千言万语,尽在不言中。QwQ
所有如果你遇到困难,坚持做下去o( ̄▽ ̄)o
我总结了几个调试经验
①不要试图分析所有代码,分析关键,不然会很浪费时间。
②仔细分析跳转指令,是拆弹的关键
③不要放弃(ಥ _ ಥ)

三:实验步骤

① 我们先大致看看程序的符号表

输入 objdump -t |bomb less
ds
印入你眼前的,是恶心的代码。不要急,慢慢寻找线索。你会慢慢看到

phase_1
phase_2
......
explode_bomb

phase_1应该是关卡1函数的名字,explode_bomb应该是炸弹爆炸函数的名字。
好啦,得到这些信息后就可以开始调试了。

②Gdb调试开始

phase_1

首先设置断点,并运行程序

break phase_1
break explode_bomb
run


然后根据提示,输入第一关的密码。随便输入一个(我输入1234)
然后在反汇编phase_!函数

disas

pic1
看到了这个函数的汇编代码。好咯,开始干活了。

第四行 callq string_not_equaled
第五行:test %eax,%eax
第六行 je 0x4003f  <phase_1+23>
第七行: call explode_bomb

大概就明白了,首先调用函数string_not_equaled,如果返回值是0,拆弹成功,否则BOMB!!!
string_not_equaled,从名字上看,大概是判断字符串是否相等。那我们再运行到string_not_equaled函数里,看看该函数的参数
pic2

x/s $edi
x/s esi

第一个参数显然就是我们的输入
第二个参数是Border relations with Canada have never been better.
呢,答案出来了,判断输入的字符串是否为Border relations with Canada have never been better.,赶快保存起来吧。
pic4

phase_2

还是一样

break phase_2
run
输入密码 (我的输入是1234)
disas

pic4

第5行 callq read_six_number
第6行 cmpl $0x1,(%rsp)
第7行 je phase_2+52
第8行 callq 0x400f30

从中可以看到,调用了read_six_number,比较(%rsp)是否为1,否则爆炸。我们可以得到一些模糊的信息。但不确定。只能看看read_six_number的代码了。
pic

第12行 call _isoc99_sscanf
第13行 cmp $0x5,%eax
第14行 jg read_six_number+61
第15行 call explode_bomb

同样,我们还是看看_isoc99_sscanf的参数
这里写图片描述
第一个参数是 ”1234“即是我们的输入
第二个参数 “%d %d %d %d %d %d”
再加上比较返回值是否大于5,否则爆炸。我们可以推测密码是6个数字



重新来过

run
输入密码 (我的输入是1 2 3 4 5 6)
disas
nexti 5

现在,直接研究执行完read_six_number后的情况
pic
程序需要检查(%rsp)的值,那我们就看看现在(%rsp)里的值。可以看到 ,是对应了我们的输入。哦,程序把我们输入的6个值放在了(%rsp)里,而且第一个数字必须为1(第6行 cmpl $0x1,(%rsp))
沿着程序,我们发现这是的循环(即下图)
pic
这个循环干什么呢,①你可以分析每条语句,判断该循环在干什么。 ②你可以单步调试,看看每一步产生的影响是什么(比如寄存器值的改变,栈的改变)来推测 循环在干什么 (笔者用的第二种方法)。
可以分析得到,该循环是每次数字翻倍.答案即是 1 2 4 8 16 32

phase_3

话不多说 输入密码 (1 2 3 4 )
这里写图片描述

第6行 callq __isoc99_sscanf
第7行 cmp $0x1,%eax
第8行 jg   
第9行 callq explode_bomb

可知,输入的数 数量要大于1,否则Bomb!!
在看看_isoc99_sscanf的参数:
%edi ”1 2 3 4 5 6“
%esi ”%d %d“
(⊙o⊙)?原来只用输入2个数。

第10行 cmpl $0x7,0x8(%rsp)
第11行 ja phase_3+106
第12行 mov 0x8(%rsp),%rax
第13行 jmpq *0x402470(,%rax,8)

首先,看看0x8(%rsp)里的值,是1,对应了我第一个输入。可知,第一个输入必须小于7,否则bomb,第13行,明显的跳转表,我们可以估计是用我们第一个输入当索引跳转。
此时,你有2个选择①逐行分析跳转表②单步调试,看看跳转表产生的效果。
这里写图片描述
最后,我们明白跳转表会给%eax赋值,而我们第二个输入必须等于该值,否则Bomb!!!
答案有很多,我测试的答案是 1 311

phase_4

还是输入密码(1 2 )(●ˇ∀ˇ●)
这里写图片描述

第6行 callq __isoc99_sscanf
第7行 cmp $0x2,%eax
第8行 jne 
第9行 cmpl $0xe,0x8(%rsp)
第10行 jbe

很明显,输入数的数量必须等于2,否则Bomb!!!
且第一个输入小于14
在分析%rsp,发现输入的第一个数在 0x8(%rsp),第二个数在0xc(%rsp)

callq func4
test %eax,%eax
jne

看来这个func4是关键了。
这里写图片描述
首先看看参数
这里写图片描述
这个时候,你会很摸不着头脑,感觉参数都很莫名其妙,为什么是三个参数,为什么只有第一个参数和我们的输入对应(ಥ _ ಥ) (为什么是三个参数,可以从func4里得知)
此时,先就试试者三个参数的值,把func4的返回值摸清楚。
这里我也老老实实的把程序分析了一便(*  ̄︿ ̄)。还不知道什么取巧的方法。

func4(x,y,z)
{
	%ecx  = ((((z-y)>>3) +z-y)>>1)+y //偷懒了
	if(%ecx==x)
		return 0;
	else if(%ecx > x)
		return func(x,y,%ecx-1);
	else
		return func(x,y,%ecx+1)
}

说实话,被这个代码恶心到了(ง •_•)ง .就姑且认为y =0 ,z=14.

func4(x,0,14)
{
	%ecx  = 7 //偷懒了
	if(%ecx==x)
		return 0;
	else if(%ecx > x)
		return func(x,y,%ecx-1);
	else
		return func(x,y,%ecx+1)
}
in phase_4
callq func4
test %eax,%eax
jne

既然要求func4的返回值是0,那我们就不管后面的递归,让第一个参数x=7,也就是输入第一个数字是7
这里写图片描述

cmpl $0x0,0xc(%rsp)
je 

这里看出,第二个输入必须是0,否则Bomb
答案便是 7 0
(这关真的挑战人的心态,感觉答案都很迷(#°Д°)

phase_5

这关非常有意思( ̄︶ ̄)↗ 
(这个关卡有金丝雀哦)
话不多说 输入密码 (abcdef)
这里写图片描述

callq string_length
cmp $0x6,$eax
je

看来是我们输入的字符串长度要等于6,否则Bomb!!! (那就重来,输入abcdef)

callq string_not_equal
test %eax,%eax
je

和第一关一样的套路啊,运行到string_not_equal,看看参数"★,°:.☆( ̄▽ ̄)/ : ∗ . ° ★ ∗ 。 &quot; ! [ 这 里 写 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n . n e t / 20180526105516878 ? w a t e r m a r k / 2 / t e x t / a H R 0 c H M 6 L y 9 i b G 9 n L m N z Z G 4 u b m V 0 L 3 d l a X h p b l 80 M T I 1 N j Q x M w = = / f o n t / 5 a 6 L 5 L 2 T / f o n t s i z e / 400 / f i l l / I 0 J B Q k F C M A = = / d i s s o l v e / 70 ) 我 们 发 现 , :*.°★* 。&quot; ![这里写图片描述](https://img-blog.csdn.net/20180526105516878?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTI1NjQxMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 我们发现, :.°"![](https://imgblog.csdn.net/20180526105516878?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTI1NjQxMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)edi是空地址,而第二个参数是flyers, 而在rsp里也找不到我们输入的abcdef(;´༎ຶД༎ຶ`)
没办法,只能分析在执行string_not_equal前,程序做了什么事。
这里写图片描述
此时你有两个选择①老老实实的分析循环②单步调试,看看每一步的作用是什么(我选择的是第一二结合(✿◡‿◡))

movzbl (%rbx,%rax,1),%ecx     #取输入的字符(我看了%ecx的值,发现是我们的输入,就能推测出)  
mov %cl,(%rsp)                #取字符的低8位
mov (%rsp),%rdx               
and $0xf,%edx                 #取低4位    
movvbl 0x4024b0(%rdx),%edx    #big discover 
mov %dl,0x10(%rsp,%rax,1) 

add $0x1,%rax                  #循环6次,正好对应我们输入6个字母
cmp $0x6,%rax      
jne 0x40102b<phase_5+41>

这里写图片描述
big discover : 我们发现,这是一个映射表,取你输入字母的低4位当索引,转换成上面字符串中的字母。
这样就能解释为什么我们输入abcdef,会出现aduier
|input|index|output
|–|--|
|a|0001|a
|b|0010|d
|c|0011|u
|d|0100|i
|e|0101|e
|f|0110|r
ASCii
答案也就出来了,输入6个字母,其低4位,经过映射表的转化,是flyers。 ψ(`∇´)ψ
ionefg

phase_6

第6关,是个硬骨头(ง •_•)ง加油。建议腾出超过2小时。
而且这题,我没有取巧,老老实实的把代码都分析了一编(这个代码很良心)(下面具体代码就不分析了)
这里写图片描述
第一段:执行read_six_numbers判断是否读了6个数
这里写图片描述
首先判断你输入的数是否小于等于6,否则Bomb,再判断你输入的6个是是否各不相等,否则Bomb
这里写图片描述
把你输入的六个数num, num = 7-num
这里写图片描述
是一个结构体

typedef  struct node{
	int lval;
	int rval;
	node *next;	  
};

后面的代码我没有分析,因为我估计是输入的数字是链表的顺序,要么是从大到小,要么是从小到大。
从大到小 3 4 5 6 1 2 从小到大 2 1 6 5 4 3
但你会发现,输入的上面两个密码都是错的,这时,你会想去之前有把六个数被减7,那答案应该是:
从大到小4 3 2 1 6 5 从小到大 5 6 2 1 3 4。经过测试。正确答案是从大到小,即4 3 2 1 6 5

秘密关卡

???有空在研究

  • 25
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值