美文网首页
lab1 二进制炸弹

lab1 二进制炸弹

作者: Jerry_589e | 来源:发表于2018-07-14 17:00 被阅读0次

    汇编与反汇编

    汇编与反汇编的区别

    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 二进制炸弹

          本文链接:https://www.haomeiwen.com/subject/ewuypftx.html