lab1 二进制炸弹

汇编与反汇编

汇编与反汇编的区别

c程序如何变成一个可执行程序

phase_1  比较字符串是否相同

二进制炸弹

常见汇编指令详解

AT&T 格式Linux 汇编语法格式

AT&T(GAS)汇编指令小集

ESP和EBP指针寄存器

汇编指令

步骤一: 反编译  

将二进制可执行文件变为汇编语言

objdump -d bomb > bomb.s

反编译命令 objdump -d

步骤二:调试 

执行二进制可执行文件

gdb bomb

gdb命令

gdb调试命令 全面

一些gdb简单命令  

一步一步学调试——gdb命令小结

gdb layout使用

断点

设置断点 b 运行 r  退出ctrl+d 或 quit

x/3i $pc显示3条指令(3为示范,数字可选)

display result 

display相当于添加监听变量,每一次run后都会给出result的值。而print就对应着IDE中的鼠标停留时显示变量的值。

$pc 指向当前程序运行地址

display/i $pc 跟踪显示命令

 1.查看display设置的自动显示的信息

info display 。

2.删除自动显示,dnums意为所设置好了的自动显式的编号。如果要同时删除几个,编号可以用空格分隔,如果要删除一个范围内的编号,可以用减号表示(如:2-5)

undisplay dnums…

deletedisplay dnums…

3.disable和enalbe不删除自动显示的设置,而只是让其失效和恢复。

disabledisplaydnums…

enabledisplaydnums…

(gdb)(e)x(amine)

语法:

x/

n选择从当前地址向后显示几个

f是显示格式,还有s字符串和i整型

u表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

例子:

x/3uh 0x54320表示,从地址0x54320读取,h表示以双字节为单位,3表示三个单位,u表示十六进制

问题:


找不到文件

解决过程:

问题原因查找


查找原因

通过命令  readelf -l 地址 | grep interpreter 查找原因

原因为:/lib/ld-linux.so.2

解释:系统为64位,缺少32位依赖,无法运行32位程序

解决方案:

64位ubuntu16.04兼容32位程序

安装如下三个依赖:

sudo apt-get install libc6:i386

sudo apt-get install lib32stdc++6

sudo apt-get install lib32z1

gdb调试

设置断点  b 地址 

查看断点 info br

删除断点  单个删除 delete 序号  如delete 1 多个删除 delete 范围序号 如delete 1-3


phase1 比较字符串


phase1 代码

由上面代码,主要关注strings_not_equal,就是比较字符串是否相同:那应该有一个样例与所输入的进行比较,因此压栈操作引起了我的注意,查看其内容并输入,发现第一个成功破解。

查看字符串
phase_1成功拆除

phase2

* LEA指令

    lea 7(%edx, %edx,4), %eax    ==> 将寄存器%eax的值置为 5 * %edx + 7.

    base(offset, index, i) 计算方法为base + offset + index * i

phase2

phase_2 循环  寻找数字间的逻辑


第一个爆炸点
第一个爆炸点

可以看出第一个爆炸点是比较第一个数字与第四个数字大小,相等才不会爆炸。

由上图可以得知,由ebp地址开始每四个字节存储一个数字,ebp-0x38为第一个数字,ebp-0x2c为第四个数字。


流程分析

lea -0xc(%ebp),%eax   incl  (%eax)

由分析可知 ebp-0xc为计数器 ,假设用N表示,每次循环后加一

分析第一个红框炸弹点:

mov -0xc(%ebp),%eax

mov    -0xc(%ebp),%edx

简单分析逻辑,首先eax和edx赋值为N

mov -0x38(%ebp,%eax,4),%eax

cmp    -0x2c(%ebp,%edx,4),%eax

六个数字存储用数组A[6]表示,因为每4字节存储一数字,每次N增加一,其相当于向后挪一位数,从第1个和第4个开始对比,遍历到所有数字。 

-0x38(%ebp,%eax,4)为ebp+4N-0x38就相当A[0+N]

0x2c(%ebp,%edx,4)为ebp+4N-0x2c就相当A[3+N],

对比A[0+N]与A[3+N],不等则爆炸。

分析最下面红框第二个爆炸点:

mov -0x38(%ebp,%eax,4),%edx

lea    -0x10(%ebp),%eax

add    %edx,(%eax)

ebp-0x10 存储每次累加的和 

cmpl $0x0,-0x10(%ebp) jne 80489ee  call 80487de

和为零则爆炸

简易逻辑如下:


简易逻辑


phase_2成功拆除

phase_3 

相当于switch函数。

分析第一个爆炸点

输入

首先随意输入了4个数字


观察sscanf函数


sscanf相关代码片段

通过观察sscanf运行前后的内存状态及观察内容,发现其功能是读取两个数字,存储在ebp-0x4和ebp-0x8位置,并用eax存储其个数。这也就是第一个爆炸点要求的输入的个数大于1。


第一个爆炸点

分析第二、三个爆炸点

逻辑移位作用

首先有cmp可知要求第一个数字小于7,否则爆炸。

接下来读取第一个数字到eax中,并进行逻辑左移,移两位,就相当于扩大4倍。例如,0x1逻辑左移两位后变为0x100,就由1变为了4。由于每四字节存储一个数字,就是每四个地址存储一个数字。并且mov 0x8049060(%eax),%eax可翻译为eax=0x8049060+4*第一个数字。可以看出我们输入的一个数字对应一个地址。


内存状态
跳转地址

通过观察由0x8049060开始的内存内容及代码段地址,可发现他们之间的关联。输入的第一个数字决定跳转的位置,第一个数字范围0-7。

跳转的代码作用:存入数字。

之后代码作用:见下图,使存入的数字并与第二个数字进行比较,相同则安全,不同则保证。注意上面是16进制数,输入时要转换为10进制数。

第二个数字作用

举例:如第一个数输入1,则对应0x1b7,换为10进制为439.


phase_3成功拆除

phase_4 递归函数



输入


观察输入

可以看出,只读取了一个数字,读取到ebp-0x8,eax计数为1。因此应该输入一个数字。


分析函数如何返回


分析函数调用及返回

介绍下面拆除前,首先分析函数调用及返回,调用时将该函数的下一行代码地址压入栈,上图就应该是0x8048b0b,函数结束应该执行下条语句,也就是地址0x8048b0b。


func4函数解析


phase_4片段代码


读取过程

由上面可知,ebp-0x8是我们所输入的数字。但随着fun4的调用,我们数字的存储位置为ebp+0x8

因此上面的循环可以解释为每次,每次该数字减1,并压栈,下次继续取出直至减到0才能继续。

如果不为0,则继续进入func函数,就会在下一行代码留下个标记点,如果输入的数字为3,则留下3次标记点,直至减至0才开始向下进行,由代码可知0时eax赋值为1。

接下来分析橘黄框,edx=8*eax;eax=edx-eax;结果就为eax=7*eax 每次变为原来的7倍;

已知0时eax=1,之后开始恢复标记点;1时eax=7;2时eax=7*7;3时eax=7*7*7;

这就是我们熟悉的递归函数。


递归函数

拆除爆炸点:

cmpl $0x1cb91,-0x4(%ebp) 不等则爆炸; 

0x1cb91变为十进制数为117649 为7的6次幂,因此输入的数字应为6


phase_4成功拆除

phase_5


第一个爆炸点


输入


string_length函数

看到string_length很自然想到比较字符长度,同时根据以上实验的经验,一般eax寄存器用来计数,事实证明,本关也是。因此第一个爆炸点就是要求字符串长度为6,不等则爆炸。


第二段代码

分析第二段代码,这是一个循环,可以看出循环六次,可以联系与输入的字符串有些关系。可以看出红框的add语句和黄框的mov语句,都是向下取值,其中ebp+0x8及0x804a620引起我们的注意;接下来可以看出绿框,ebp-0x8是存储累加值的,这个值就是下个爆炸点的判断;ebp-0x4是存储计数的。


ebp+0x8解析

查看ebp+0x8存储的内容为一地址,继续查看改地址就是我们所输入的字符串,因此add操作相当将字符串中的内容逐个取出,并存入eax进行下一步操作。

0x804a620解析

通过观察0x804a620,我们可以联想到数组,每个位置存储固定的数字。

mov 0x804a620(,%eax,4),%edx可翻译为edx=(0x804a620+4*eax)

这个可以看出我们输入的字符串的内容,影响着取出的内容,他们之间是一一对应关系,比如输入0取出的就是0x00000002等等,由于数字只能为0-9取出的范围4*eax为0-36;考虑到16进制,可以输入字母a-f,这样就扩大了范围。

之后lea -0x8(%ebp),%eax  add    %edx,(%eax) 是将取出内容进行累加,并存到ebp-0x8中;


爆炸点分析

分析最后一个爆炸点,要求累加的和等于0x25,也就是37;

综合考虑输入字符串有个数6个限制,观察对应的数组,相加的和等于37;因此可以有多种组合,列举其中一种:033355


phase_5成功拆除

phase_6

首先看代码,好多循环。。。


第一个两层循环

第一个为两层循环,目的是:是输入的6个数各不相同,且范围是1-6;否则爆炸。


输入
验证

上面两个压栈的地址,引起我们注意ebp-0x38及ebp+0x8,验证可知,是存储输入6个数的位置。


第二个两层循环


简易逻辑


存储对应

因为此次测试输入的为123456,因此一一对应。

输入    -0x58存储内容   相对于值                大小


1        0x0804a69c        0xce                         6


2        0x0804a690        0x3c8                       1


3        0x0804a684        0x106                       5


4        0x0804a678        0x21f                        3


5        0x0804a66c        0x276                        2


6        0x0804a660        0x158                        4


可以看出,每个数对应一个地址,存储在ebp-0x58;且每个地址对应一个值,按值的大小排序,输入顺序应该为 2 5 4 6 3 1

第三个循环


循环结果

第三个循环目的是将输入所对应的地址串联起来,就是第一个对应的地址+0x8存储下一个数对应的地址,如上图。


第四个循环及爆炸点

可以看出,这个循环是比较大小,前一个数所对应地址存储的值大于后一个,则安全;

根据前面分析输入范围为1-6,且输入各值不同;按照所对应地址的值从大到小排序,输入顺序应为2 5 4 6 3 1.

phase_6成功拆除

phase_secret


第六关

你可能感兴趣的:(lab1 二进制炸弹)