CSAPP lab2 二进制拆弹 binary bombs phase_6
给出对应于7个阶段的7篇博客
phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.html
phase_2 https://www.cnblogs.com/wkfvawl/p/10636214.html
phase_3 https://www.cnblogs.com/wkfvawl/p/10651205.html
phase_4 https://www.cnblogs.com/wkfvawl/p/10672680.html
phase_5 https://www.cnblogs.com/wkfvawl/p/10703941.html
phase_6 https://www.cnblogs.com/wkfvawl/p/10742405.html
secret_phase https://www.cnblogs.com/wkfvawl/p/10745307.html
1 phase_6
phase_6要求输入6个1~6的数,这6个数不能重复。phase_6根据用户的输入,将某个链表按照用户的输入的值(进行某种计算后)进行排序,如果最终能排成降序,则解题成功。
phase_6主要考察学生对C语言指针、链表以及结构的机器级表示的掌握程度。
观察框架源文件bomb.c:
从上可以看出:
1、首先调用了read_line()函数,用于输入炸弹秘钥,输入放置在char* input中。
2、调用phase_6函数,输入参数即为input,可以初步判断,phase_6函数将输入的input字符串作为参数。
因此下一步的主要任务是从asm.txt中查找在哪个地方调用了readline函数以及phase_6函数。
1.1 寻找并分析调用phase_6函数的代码
打开asm.txt,寻找phase_6函数。
和phase_1类似分析:
1、当前栈的位置存放的是read_line函数读入的一串输入;
2、phase_6的函数入口地址为0x8048e81。
此时的函数栈为:
1.2 phase_6分析
在asm.txt中继续寻找phase_6,或者寻找0x8048e81,找到phase_6函数入口:
584-591行:初始化函数栈帧,然后调用read_six_numbers函数。调用之后,从input中读取了6个数num[0] ~ num[5](read_siz_numbers函数分析参见前面),位于esp+0x10 ~esp+0x24,此时函数栈帧如下图所示:
2、592行:0 --> esi
3、593-597行:判断(esp + esi*4 + 0x10)是否小于等于6以及大于等于1,如果不满足,则引爆炸弹(625行);也即输入的数(esi=0时,为num[0],esi=1时,为num[1]......)应该大于等于1,同时小于等于6。注意,比较时,先将该值减1(594行),然后与5进行比较(595行),比较时用的jbe(无符号整数比较),也即,如果该输入值小于1,减1之后变成一个很大的无符号数(负数),肯定是大于5的。因此这几行就实现了判断num[esi] >=1 && num[esi] <=6。(这应该是编译器做的优化)
4、598行:esi += 1
5、599-602行:esi与6进行比较,如果等于,则意味着6个数已经比较完毕,跳转到8048ef7。
6、603行:如果602行没有跳转,也即6个数还没有判断完毕,则继续执行,将esi赋值给ebx
7、604-607行:判断num[ebx]是否与num[esi-1]相等,如果相等,则引爆炸弹;
8、608-610行:ebx+=1,然后判断ebx是否小于等于5,如果是,则跳转到8048ec1,即604行,也即跳转到第7步。
9、611行:跳转到8048e9f,进行num[esi]的比较(注意num[esi]在第608行加1)
10、综合以上分析,可以判断出以上代码的作用是:
1)判断每个输入的数应小于等于6,大于等于1;
2)num[i]不等于它的后续的每个数;
3)也即输入的6个数,应是1/2/3/4/5/6,但顺序不一定。
使用类c语言描述:
for (i = ; i < ; i++)
{
if ((num[i] < ) || (num[i] > ))
{
explode_bomb();
}
for (j = i + ; j < ; j++)
{
if (num[i] == num[j])
{
explode_bomb();
}
}
}
14、622行(0x8048fa2<phase_6+0x90>)- 625行:ebx保存到esi(mov %ebx, %esi),将esp + ebx*4 + 0x10的内容(当ebx=0时,为num[0],当ebx=1时,为num[1]......)与1相比较,如果 esp + ebx*4 + 0x10 <= 1(624行),则跳转到 8048ee6 <phase_6+0x65>(625行),否则继续执行626行。(根据前面分析,ecx为输入的num的值,仅且仅当ecx=1时,执行这个625行跳转语句,跳转到8048ee6 <phase_6+0x65>。
15、617行(0x8048f91<phase_6+0x7f>):当ecx=1时,会执行该条语句,将0x804c174送入到edx。查看0x804c174地址的内容(objdump --start-address=0x804c174 -s bomb):
16、618行:将edx内容送入到esp + esi*4 + 0x28。
17、619-621行:ebx += 1,然后与6相比较,如果等于6,则跳转到0x8048f0e 。
18、如果不等于6,则继续执行622行,对于本文,即跳转到第14步,前面分析了ecx=1的情况,如果ecx不等于1,则应继续执行626-628行。
19、626-628行:eax赋值为1,edx赋值为0x804c174,跳转到8048eda <phase_6+0x59>。(第612行)
20、612-615行:这是一个循环。判断ecx(num[ebx])是否等于eax,如果不是,则将edx + 8的内容送入到edx,然后继续判断, edx +8的内容应该是指向的是一个地址。如果相等,则跳转到 8048eda <phase_6+0x59>(从第612行继续执行)
21、根据前面的分析,13~20步的代码,是根据处理后的num值(参见第10步分析),将相关信息压栈(从esp+28开始压栈):(注意:IA32是小端方式)
1)当num[i] == 1时,将0x804c174(node1)压入到esp + 0x28 + i * 4;
2)当num[i] == 2时,将0x804c180(node2)压入到esp + 0x28 + i * 4;
3)当num[i] == 3时,将0x804c18c(node3)压入到esp + 0x28 + i * 4;
4)当num[i] == 4时,将0x804c198(node4)压入到esp + 0x28 + i * 4;
5)当num[i] == 5时,将0x804c1a4(node5)压入到esp + 0x28 + i * 4;
6)当num[i] == 6时,将0x804c1b0(node6)压入到esp + 0x28 + i * 4;
7)观察压入栈的内容,每个内容地址实际上是指向12(例如:0x804c180-0x804c174)字节的一段数据,该数据的末尾又是指向一个地址,因此,可以判断0x804c174开始的地方指向的是一个链表(但这些链表的存空间是连续分配的),每个节点包括12个字节,其中最后一个是指向下一个的指针,猜测每个节点的定义:
struct node
{
int d1;//尚不清楚含义,以4个字节的int暂替
int d2;//尚不清楚含义,以4个字节的int暂替
struct node* next;
}
6个节点,分别为:
node1 = {0x6d, 0x01, 0x804c180}; (&node1 = 0x804c174)
node2 = {0x69, 0x02, 0x804c18c }; (&node2 = 0x804c180)
node3 = {0x3b2, 0x03, 0x804c198}; (&node3 = 0x804c18c)
node4 = {0x299, 0x04, 0x804c1a4}; (&node4 = 0x804c198)
node5 = {0xc7, 0x05, 0x804c1b0}; (&node5 = 0x804c1a4)
node6 = {0x285b, 0x06, 0}; (&node6 = 0x804c1b0)
链接关系为:
node1 --> node2 --> node3 --> node4 --> node5 --> node6 --> 0
8)假设当前6个num的值为6/5/4/3/2/1,则经过6次循环后,函数栈帧如下图所示。
注:后面分析,均假设6个num的值为6/5/4/3/2/1。
22、以上操作结束,则跳转到 8048f0e <phase_6+0x8d>(第629行,参见第17步分析)。
23、629(8048fb9 <phase_6+0xa7>)- 676行:
1)629行:0x28(%esp)的内容(num[0]这个值指向的节点的地址) --> ebx
2)630行:esp+0x2c --> eax,esp+0x2c这个地址的内容为num[1]这个值对应的节点的地址
3)631行:esp + 0x40 --> esi,esp + 0x40,根据后面的分析,这个值是作为“哨兵”,防止访问越界
4)632行:ebx --> ecx(此时ebx以及ecx都是num[0]这个值指向的节点的地址)
5)633行:eax所指向的地址的内容(num[1]这个值对应的节点的地址)--> edx
6)634行:将edx的内容赋值给8(%ecx)的地址,注意,此时ecx为num[0]指向的节点的地址,8(%ecx)正好是num[0]这个值所对应的next,即node6.next = &node5
7)635行:eax += 4,即eax所指向的地址的内容变成了num[2]所指向的节点的地址;
8)636行:将eax与esi(哨兵)相比较,如果等于,则说明循环结束,跳转到 8048f2c <phase_6+0xab>,如果不是,继续执行。
9)638行:edx --> ecx:根据前面分析,edx为num[1]值指向的节点的地址。
10)639行:跳转到8048f1c <phase_6+0x9b>,即第633行,可以转到上面第5)步继续执行,注意,此时edx为num[1]值指向的节点地址,eax的内容为num[2]值指向的节点的地址,即node5.next = &node4。
11)如此循环,最后的结果是:
node6.next = &node5,node5.next = &node4,node4.next = &node3,node3.next = &node2,node2.next = &node1
12)如果以上都做完,跳转到8048fd7 <phase_6+0xc5>(677行)继续。
13)640行:将0赋值给8(%edx)指向的地址,此时edx为node1的地址,即将node1.next=0;
14)显然,以上步骤,根据num的值重新构成了一个链表,此时的链接关系变成了:
node6 --> node5 --> node4 --> node3 --> node2 --> node1 --> 0。(注:以上分析均是基于6个num的值为6/5/4/3/2/1)
24、641 - 行:
1)641行:5 --> esi
2)642行:将ebx+8这个地址的内容送给eax,注意, ebx为node6的地址,ebx+8为node6->next这个值的地址,这个地址的内容即为node5的地址。也即eax的内容为node5的地址。
3)643行:将eax指向的地址的内容赋值为eax,也即eax的内容为node5.d1
4)644行:将node5.d1与ebx指向的地址的内容相比较;(显然,此处是整数的比较,因此,也可以判断struct node中第一个元素应该是int),此时ebx的内容为node6的地址,node6的地址的内容为node6.d1,即node5.d1与node6.d1相比较。
5)645-646行:如果node6.d1 >= node5.d1,则跳转到8048f46 <phase_6+0xc5>,否则引爆炸弹
6)647行:ebx的内容变为其指向的节点的next,即ebx=node6-next,指向了node5
7)648行:esi-= 1
8)649行:如果esi不为0,则跳转到642行,按以上的2)继续分析,应注意,此处ebx的值为node5的地址了。
9)显然,此时会判断node5.d1是否大于等于node4.d1,如果是,则继续,如果不是,则引爆炸弹
10)后续会依次判断node4.d1是否大于等于node3.d1,node3.d1是否大于等于node2.d1,......,综合起来,就是判断按照num值排序之后的节点是否降序排列,如果是,则解题成功,如果不是,则引爆炸弹。
1.3 phase_6结果分析
根据以上分析,phase_6的功能:
1)phase_6定义了一个包含6个节点的链表,每个节点中包含两个整型(d1,d2),以及指向下一个节点的指针;6个节点依次的链接顺序为node1->node2->node3->node4->node5->node6
2)要求用户输入6个数,这6个数应为1~6,而且不能重;为便于以后说明,假设这6个数为6/5/4/3/2/1。
3)按照num[i]的值重新排列链表,此时链表变为:
node6->node5->node4->node3->node2->node1
4)判断以上链表是否降序排列(按分量d1),如果是,则拆弹成功,否则,引爆炸弹。
也即phase_6会给出一个链表,链表中的节点的d1分量含有一个整数值,需要用户输入一个序列号,按照这个顺序重新排列链表中的节点,如果链表是按照降序排列,则输入的这个序列号是正确的。
对于前面的炸弹,其初始化的节点值为:
node1 = {0x6d, 0x01, 0x804c180}; (&node1 = 0x804c174)
node2 = {0x69, 0x02, 0x804c18c }; (&node2 = 0x804c180)
node3 = {0x3b2, 0x03, 0x804c198}; (&node3 = 0x804c18c)
node4 = {0x299, 0x04, 0x804c1a4}; (&node4 = 0x804c198)
node5 = {0xc7, 0x05, 0x804c1b0}; (&node5 = 0x804c1a4)
node6 = {0x285b, 0x06, 0}; (&node6 = 0x804c1b0)
显然,使得这个链表按降序排列的序列是:3 4 6 5 1 2,因此,输入的序列号应为:3 4 6 5 1 2,此即为本关答案。
CSAPP lab2 二进制拆弹 binary bombs phase_6的更多相关文章
- CSAPP lab2 二进制拆弹 binary bombs phase_1
这个实验从开始到完成大概花了三天的时间,由于我们还没有学习编译原理.汇编语言等课程,为了完成这个实验我投机取巧了太多,看了网上很多的解题方法,为了更加深入学习编译反编译,觉得需要从头开始好好梳理一下. ...
- CSAPP lab2 二进制拆弹 binary bombs phase_4
给出对应于7个阶段的7篇博客 phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.htmlphase_2 https://www.cnblogs. ...
- CSAPP lab2 二进制拆弹 binary bombs phase_5
给出对应于7个阶段的7篇博客 phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.htmlphase_2 https://www.cnblogs. ...
- CSAPP lab2 二进制拆弹 binary bombs phase_3
给出对应于7个阶段的7篇博客 phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.htmlphase_2 https://www.cnblogs. ...
- CSAPP lab2 二进制拆弹 binary bombs phase_2
给出对应于7个阶段的7篇博客 phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.htmlphase_2 https://www.cnblogs. ...
- [逆向工程] 二进制拆弹Binary Bombs 快乐拆弹 详解
二进制拆弹 binary bombs 教你最快速解题,成功拆弹 最近计算机基础课,的实验lab2,二进制拆弹,可以说是拆的我很快乐了(sub n, %hair) 此处头发减n 我刚开始做的时候很是懵逼 ...
- 2016年11月3日JS脚本简介数据类型: 1.整型:int 2.小数类型: float(单精度) double(双精度) decimal () 3.字符类型: chr 4.字符串类型:sting 5.日期时间:datetime 6.布尔型数据:bool 7.对象类型:object 8.二进制:binary 语言类型: 1.强类型语言:c++ c c# java 2.弱类型语
数据类型: 1.整型:int 2.小数类型: float(单精度) double(双精度) decimal () 3.字符类型: chr 4.字符串类型:sting 5.日期时间:datetime 6 ...
- MySQL 二进制日志(Binary Log)
同大多数关系型数据库一样,日志文件是MySQL数据库的重要组成部分. MySQL有几种不同的日志文件.通常包括错误日志文件,二进制日志,通用日志,慢查询日志,等等.这些日志能够帮助我们定位mysqld ...
- CSAPP Lab2: Binary Bomb
著名的CSAPP实验:二进制炸弹 就是通过gdb和反汇编猜测程序意图,共有6关和一个隐藏关卡 只有输入正确的字符串才能过关,否则会程序会bomb终止运行 隐藏关卡需要输入特定字符串方会开启 实验材料下 ...
随机推荐
- October 15th 2017 Week 42nd Sunday
Excellence is a continuous process and not an accident. 卓越是一个持续的过程而不是一个偶然事件. It is said that ten tho ...
- Oracle Spatial中SDO_Geometry说明
Oracle Spatial中SDO_Geometry说明 在ArcGIS中通过SDE存储空间数据到Oracle中有多种存储方式,分别有:二进制Long Raw .ESRI的ST_Geometry以及 ...
- Volley源码分析(四)NetWork与ResponseDelivery工作原理
这篇文章主要分析网络请求和结果交付的过程. NetWork工作原理 之前已经说到通过mNetWork.performRequest()方法来得到NetResponse,看一下该方法具体的执行流程,pe ...
- 2.HBase In Action 第一章-HBase简介(1.1数据管理系统:快速学习)
Relational database systems have been around for a few decades and have been hugely successful in so ...
- NOIP模拟赛-2018.11.7
NOIP模拟赛 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 编译之前另存一份,听说如果敲 ...
- php 两个二维数组重组新数组,数组下标不同
Array ( [0] => Array ( [PosNum] => 27025008 [start_time] => 20180328164929 [type] => 0 ) ...
- centos下安装pip-python
pyspider需要通过pip工具安装 首先检查linux有没有安装python-pip包,直接执行 yum install python-pip 没有python-pip包就执行命令 yum -y ...
- Python3.6+nginx+uwsgi部署Django程序到阿里云Ubuntu16.04系统
Python3.6+nginx+uwsgi部署Django程序到阿里云Ubuntu16.04系统 这个是写好的Django程序在本地机运行的情况,一个查询接口. 准备工作 1.首先购买一台阿里云的EC ...
- PAT B1035 插入与归并 (25 分)
根据维基百科的定义: 插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列.每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置.如此迭代直到全部元素有序. 归并排序进行如下迭 ...
- android asmack调用MultiUserChat.getHostedRooms方法出现空指针的异常解决方案
今天在做即时通讯群聊时,调用MultiUserChat.getHostedRooms(conn, SmackTools.getInstance().conn.getServiceName());方法获 ...