CS:APP二进制炸弹phase2
写在前面
在前文《CS:APP二进制炸弹phase1》中成功“破解”了phase_1,毕竟是第一个阶段,非常简单。本篇来破解第二阶段。let's go!!!
分析
反汇编调用phase_2处的代码如下:
同样的,跟phase_1一样,我们输入的字符串首地址存储在寄存器%rdi中。
反汇编phase_2:
一眼望去,phase_2明显要比phase_1要复杂一些。不过没关系,应该只是复杂一点。
先看前五行代码。先分别将寄存去%rbp和%rbx压栈,之所以将这两个寄存器压栈,可以通过后面的汇编语句得知在函数phase_2中用到了它们。
sub $0x28,%rsp 这条汇编语句是在开辟栈空间。
mov %rsp,%rsi 将栈首地址传送到寄存器%rsi中。根据x64 ABI文档,%rsi通常用来传递函数的第二个参数。
接下来通过callq调用函数read_six_numbers,从函数名就可以知道是从我们的输入中获取6个数字。那么就可以大胆的猜测,刚才开辟栈空间的操作是在栈上分配了一个具有6个元素的数组,至于数组元素是什么类型,目前不得而知。并且可以判断函数read_six_numbers具有两个参数,第一个参数使我们的输入input,第二个参数就是数组第一个元素的首地址,即函数read_six_numbers的原型为void read_six_numbers(const char *input, TYPE *p)。我们不妨将这个数组取名为a,TYPE a[6],即在函数phase_2有个局部数组a,数组元素总共6个,类型待定。
进入函数read_six_numbers,该函数反汇编如下:
原来函数read_six_numbers是通过函数sscanf从我们的输入中获得6个数字的。这就好办了,根据函数sscanf的原型,我们来仔细看看调用函数sscanf之前,它需要的参数是如何传递进去的。
为了方便,还是从X64 ABI文档中截个图吧,描述函数参数传递时的约定,即calling convention!
第一个参数肯定是我们的输入input的首地址,它目前储存在寄存器%rdi中,那么第二个参数应该是sscanf需要的格式化字符串,从mov $0x4025c3,%esi中知道这个格式化字符串存储在地址0x4025c3处,用x/s命令查看,原来是"%d %d %d %d %d %d",这下我们可以断定,在函数phase_2中的数组元素类型是int型,即int a[6]。
既然格式化字符串中有个6个%d,自然的sscanf函数还需要6个参数,应该分别是数组a每个元素的地址,即分别是&a[0],&a[1],&a[2],&a[3],&a[4],&a[5]。根据调用约定,前4个元素的地址应该用寄存器传递,分别是%rdx、%rcx、%r8、%r9,最后两个通过栈来传递,通过lea 0x10(%rsi),%rax,mov %rax,(%rsp)和lea 0x14(%rsi),%rax,mov %rax,0x8(%rsp)分别将&a[4]和&a[5]压栈,这就完成了sscanf所有参数的传递任务。
接下来判断sscanf函数的返回值,如果返回值大于5则OK,如果小于等于5则触发炸弹。也就是说我们需要输入至少6个数字,只要前6个数字正确即可。
OK,read_six_numbers函数分析完毕,返回函数phase_2继续分析。
现在我们可以确定数组a在栈空间中的布局了,如下:
cmpl $0x1,(%rsp),用a[0]和数字1比较
je 0x400f30 <phase_2+52> 相等,跳转到0x400f30处继续执行,否则调用explode_bomb触发炸弹。这里很显然得出a[0]的值必须为1。
从地址0x0000000000400f30处开始的两条汇编指令lea 0x4(%rsp),%rbx,lea 0x18(%rsp),%rbp用到了函数一开始就压入栈的两个寄存器,使之分别指向&a[1]和&a[6]。读者可能会问,数组a只有6个元素啊,那么最后一个元素不是应该是a[5]吗? 注意,这里取的是a[6]的地址,这在标准C中是允许的,只要不取这个地址处的值都是OK的,而标准允许这样做是有原因的,这样就可以很方便在循环中来遍历数组了。
jmp 0x400f17 <phase_2+27>,jmp到地址0x0000000000400f17处继续执行。
如果仔细观察地址0x0000000000400f2c处也有个jmp到地址0x0000000000400f17处的指令,我们可以判定这里应该是个循环语句,那么循环体的内容可以根据地址0x0000000000400f17 ~ 地址0x0000000000400f29处的指令来获知。
假设第一次进入循环体,现在寄存器%rbx指向&a[1],那么mov -0x4(%rbx),%eax就是讲a[0]的值存储寄存器%eax,add %eax,%eax将寄存器%eax的值乘以2,cmp %eax,(%rbx)就是将现在%eax的值与a[1]比较,也就是a[0]乘以2后的值与a[1]比较。如果不相等, 则触发炸弹,相等则%rbx指向下一个元素的地址,在这里就是&a[3]。好,原来数组a的第一个元素的值a[0]为1,而a[1]的值是根据a[0]的值算来的,公式为a[1] = a[0] x 2。更普通的为a[n] = a[n -1] x 2(n >= 1)。
根据以上推演出的公式可以很容易的得出数组a后续元素的值分别为2、4、8、16、32。
验证一下,果然正确。
C源码如下:
static void read_six_numbers(const char *input, int *a)
{// %rdi %rsi %rdx %rcx %r8 %r9 (%rsp) *(%rsp)int result = sscanf(input, "%d %d %d %d %d %d", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);if (result <= 5) {explode_bomb();}
}void phase_2(const char *input)
{int a[6];read_six_numbers(input, a);int *begin = &a[1];int *end = &a[6];for ( ; begin < end; ++begin) {int prev_value = begin[-1] * 2;if (prev_value != begin[0]) {explode_bomb();}}
}
总结:
phase_2比phase_1来说要复杂一些,不过仔细分析一下,也不难,不是吗?继续phase_3吧!
CS:APP二进制炸弹phase2相关推荐
- CS:APP二进制炸弹phase5
写在前面 在阶段4中的,我不得不承认,为了搞懂func4在搞什么,我还是花费了一些功夫的,主要原因是对其中几个汇编代码生疏,还特地上网查了一下.不过还好最后得出了答案! 本篇来看看phase_5,应该 ...
- [祭祖作业一]二进制炸弹破解笔记2
哨兵值 数据结构与算法随笔之------哨兵变量(编程思想与技巧) 编程技巧1_哨兵值(sentinel) 为什么"哨兵值"没有解决错误处理问题 while 循环中的变量 i 控制 ...
- CSAPP实验二:二进制炸弹(Bomb Lab)
本系列文章为中国科学技术大学计算机专业学科基础课<计算机系统>布置的实验,上课所用教材和内容为黑书CSAPP,当时花费很大精力和弯路,现来总结下各个实验,本文章为第二个实验--二进制炸弹( ...
- 深入了解计算机系统(CS:APP)思考题
QA1 1.简述C.ASM.ML的关系,各自优缺点? 机器语言是二进制数据表示的语言,机器可以直接识别:汇编语言是与机器指令一一对应的助记符,是一种低级语言,经过汇编和链接之后机器可以运行:C语言在低 ...
- 哈工大 计算机系统 二进制炸弹实验报告
实验报告 实 验(三) 题 目 Binary Bomb 二进制炸弹 专 业 计算机学院 学 号 班 级 学 生 指 导 教 师 实 验 地 点 实 验 日 ...
- 计算机系统二进制炸弹实验报告,二进制拿炸弹实验报告完整版.doc
课程名称:计算机系统原理实验 实验课时:32课时 实验项目名称:BombLab二进制炸弹 实验材料:可执行文件bomb.源代码bomb.c.说明README 实验环境:Linux操作系统(安装虚拟机和 ...
- 计算机系统原理实验之BombLab二进制炸弹1、2关
实验目的: 通过二进制炸弹实验,熟悉汇编语言,反汇编工具objdump以及gdb调试工具. 实验过程: 实验包里有三个文件,分别是二进制可执行文件bomb,C语言源程序文件bomb.c以及一个READ ...
- 二进制拆弹实验详解linux,拆解二进制炸弹
拆解二进制炸弹 一.实验目的 1.理解C语言程序的机器级表示. 2.初步掌握GDB调试器的用法. 3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现. 二. 实 ...
- 二进制炸弹(arm)
x86上的二进制炸弹对于反汇编的练习来说还是比较经典的,由于网上有很多该程序的讲解,所以在此我打算写一下arm平台上的二进制拆炸弹这个游戏. 环境的搭建 由于是arm平台的环境,所以需要在linux环 ...
最新文章
- Laravel:使用Migrations
- 百度竞价用户免费拥有百度指数?
- 《认清C++语言》---谈谈const
- RedisDesktopManager客户端可视化工具下载安装与使用
- Codeforces 989C (构造)
- shell常用命令之curl: -w,–write-out参数详解
- 【IDE插件】- XCode6代码注释之VVDocumenter
- java jdbc开启事务_spring jdbc 事务配置
- 2 年 6 个月 11 天,外包到阿里的修仙之路!| 原力计划
- html同时用多个css,多类选择器的运用_html/css_WEB-ITnose
- App山寨疯狂 爱加密Apk加密平台防破解
- stephen boyd著王书宁译凸优化课后题答案
- 【easyui】combobox 静态数据时,设置默认值时,不触发onselect事件
- 汉语词频统计工具java_中文分词词频统计工具_python 结巴_Java开源中文分词类库分类列表...
- 用FFmpeg快捷加文字水印
- 面板模型进行熵值法分析
- 计算机代表学校拿什么奖,学校荣获第十届中国大学生计算机设计大赛优秀组织奖...
- 异地灾备,利用华为云就可以实现
- Gif动态图片怎样在线生成?一招快速完成gif在线制作
- 手机号和座机号正则表达式