CSAPP第二次实验 bomb二进制炸弹的破解
来源:互联网 发布:桂树焉知泰山之高的焉 编辑:程序博客网 时间:2024/04/30 12:55
一个类似于破解的初级实验。用到的gdb的指令并不多,只是基础的使用和内存查看的指令。考的大多是汇编代码的熟练程度和分析能力。不过有几个函数长的让人吐血。本着不轻易爆炸的原则,只好慢慢调。
1. 反汇编bomb
objdump -d ./bomb > bomb.s
2. phase_1
第一个函数的代码很简单,看到strings_not_equal()函数的调用就能大概知道参数应该是一个字符串。此外可以看到两个push将参数入栈,是为strings_not_equal()准备的。根据函数名,可以知道这个函数是在比较两个字符串是否相等,所以push的很有可能就是一个答案字符串所在地址(如果是程序自带的变量包括字符串等都会在.rodata部分,所以压栈时会直接压入对应地址),另一个来自标准输入的字符串地址。
很明显可以看到eax内容为来自标准输入的参数的地址,而直接入栈的地址很有可能就是答案。直接kill掉并重新加载bomb,在0x8048b3a处设置断点,由图4所示代码可以看出如果eax为0则通过。运行并输入测试字符串:
图4 phase_1检测部分代码
图5 测试字符串运行结果
如图 $eax==0 , 所以第一个关卡的答案就是”Public speaking is very easy.” 了。
3. phase_2
观察phase_2,可以看到如下片段:
图6 phase_2部分代码
入栈eax和edx可以看出是两个地址,而read_six_numbers可以看出这个关卡的答案是6个数字。所以就用1 2 3 4 5 6 来进行测试,并read_six_number()函数运行前后对参数进行追踪和对比:
可以看到并未触发断点,则结果正确。
4. phase_3
首先当然还是先观察phase_3的汇编代码,看是不是调用了有关输入的参数的函数:此外从整体看phase_3可以看出有9个分段,每个分段都类似于一下片段:
图17 phase_3重复片段
且都由一处语句控制跳转内存:
图18 控制跳转语句
5. phase_4
接下来就转战func4函数,可以看出它是一个递归函数。对于递归函数首先要找到特殊出口:
图27 func4的递归部分
不过代码较短又只涉及到输入的参数,所以可以直接看出等价以下C代码:
因为没有触发explode_bomb断点,所以phase_4就这样被KO啦。
6. phase_5
7. phase_6
根据以上信息,可以大概总结出如下内存和寻址的模式:
可以看到这次循环是根据上一次循环更改的相关内存进行第二次的修改,间接与输入的6个数字有关。接下来是phase_6的最后一个循环:
图51 phase_6最后一个循环
炸弹现在才出现,可以看出来是内存间的访问和比较,根据图47 和图50可以得到下面的流程模拟图:
图52 最后一个循环的运行模拟和参数推算
可以看到这个循环是在测试根据输入的6个数字排好序的地址中存放的数字,输入的6个数字应该使 0x804b230– 0x804b26c 这6个地址中的数字按照降序排列,而输入的6个数字是在图47所示的循环过程中控制6个地址在 0xffffd0c8 – 0xffffd0dc 中的顺序 进而通过图50所示过程控制6个地址存放在以0x804b开始的地址。所以正确输入顺序的推算应是 4 2 6 3 1 5 。如下图所示:
图57 第三阶段运行后检测其他相关内存
第三阶段后,根据图57和58可以得出下图所示的图示:
图58 内存图示和比较顺序推算
最后运行后显示成功拆除炸弹并退出程序:
图59 提示成功拆除炸弹并退出
8. phase_defused()
图62 异常跳过secret_phase()入口
图63 查找sscanf()的参数
可以看到模式串是数字+字符串,而收到的匹配串是一个数字9,由于并未手动输入新串,所以排除是程序自带的字符串,所以观察6个关卡的答案,发现第四关的答案是9,而且第四个关卡的参数串是%d,所以有多余的字符串也不会影响匹配的个数,所以推测需要改变第四个答案。在第四关时多输入任意一个字符串:
图64 测试任意字符串
图65 通过参数匹配测试
图66 再次异常跳转
可以看到在输入任意字符串后,在参数匹配个数部分已经成功,但在单步执行到strings_not_equal()时由于返回的参数$eax不为0,所以再次异常跳转,所以观察入栈的两个参数,发现一个字符串是标准输入的字符串,另一个是绝对地址存放的字符串,所以推定应该在第四关输入的字符串就是该处地址显示的字符串,即 “9 austinpowers”。用推算的答案进行测试:
图67 测试推算的答案
图68 成功进入secret_phase()入口
9. secret_phase()
.首先观察入口部分的代码:
图69 入口部分代码
可以看到有两次调用函数,第一次是read_line(),从而可以推断出此关卡应该是一个字符串作为参数。用gdb单步调试观察第二个调用函数的参数:
图70 第二个调用的函数参数
图71 发现错误
图73 成功通过并进入fun7()
可以看到已经成功通过,并运行到fun7()函数入口,对参数进行分析发现是输入的数字和0x24。由于除了参数匹配的检测fun7()中没有其他的爆炸带你,所以先直接完成fun7()函数回到secert_phase()函数,发现fun7()返回的值未通过测试:
图74 fun7()函数返回值错误
观察fun7()的汇编代码:
图75 一种完成fun7()的方式
图76 查看fun7()参数
可以看到$edx的值是传入的地址,所以首次进入时不会发生edx=0的情况。所以继续观察fun7()其他代码发现又是一个双层递归,但属于分支情况,分析可得如下图所示C模式:
图77 fun7()的三分支模式
根据三分支模式在分支处设置断点并运行测试:
图78 设置断点并测试
图79 根据三分支模式寻找递归返回点
如图,由于fun7()是三分支模式,除相等时直接返回0外,只有在传入地址参数为0时才会返回-1。所以查找所有可以递归的地址点,直到某个地址点的左右分支均为0则为结束点。由上图可知该递归模式是四层二叉树递归模式,则有如下的二叉树形态:
图80 内存的二叉树形态
由于secret_phase()判断返回值应为7,所以根据三分支的返回值公式,有且仅有7 = ((0*2+1)*2+1)*2+1。所以应该为$eax > 0x24 且$eax>0x6b 且 $eax==0x3e9,则输入的数字应该为0x3e9,即1001。strtol()函数在转换时会舍弃无法转换的部分,所以1001后可接第一个字符不为0-9的其他字符串。
根据推算的结果输入字符串进行测试:
图81 测试secret_phase()
由图81可以看到并未触发secret_phase()和fun7()内的explode_bomb()入口,即破解成功。结尾
- CSAPP第二次实验 bomb二进制炸弹的破解
- CSAPP的二进制炸弹实验
- csapp bomb lab:csapp lab2 炸弹实验
- 二进制炸弹(第二次实验)
- CSAPP lab binary bomb 二进制炸弹
- 【CSAPP】二进制炸弹 实验分析
- csapp 实验二 二进制炸弹
- CSAPP课程实验 bomb实验 拆炸弹实验(1)
- CSAPP课程实验 bomb实验 拆炸弹实验 (2)
- 逆向工程实验---二进制炸弹(CSAPP Project)
- csapp lab2 bomb 二进制炸弹《深入理解计算机系统》
- 二进制拆炸弹bomb实验第一弹
- 二进制炸弹BOMB报告
- 深入理解计算机系统(CSAPP)课程实验bomb程序炸弹实验日志(phase_1)
- 深入理解计算机系统(CSAPP)课程实验bomb程序炸弹实验日志(phase_2)
- 深入理解计算机系统(CSAPP)课程实验bomb程序炸弹实验日志(phase_3)
- 深入理解计算机系统(CSAPP)课程实验bomb程序炸弹实验日志(phase_4)
- 深入理解计算机系统(CSAPP)课程实验bomb程序炸弹实验日志(phase_5)
- Hibernate对象状态转化
- LaTeX 简介与安装
- TCP拥塞控制图解(不包括RTO,因为它太简单了)
- 又一次周赛题解
- poj 1953 World Cup Noise
- CSAPP第二次实验 bomb二进制炸弹的破解
- 1031. 查验身份证(15)
- poj1179(区间dp)
- 树的最大独立集(1初步)
- 1032. 挖掘机技术哪家强(20)
- Linux系统分类
- java位运算符
- Java注解(三) 自定义注解与提取注解
- C#碎碎念(二)快进一波