《深入理解计算机系统》第三章的bomb lab,拆弹实验:给出一个linux的可执行文件bomb,执行后文件要求分别进行6次输入,每一次输入错误都会导致炸弹爆炸,程序终止。需要通过反汇编来逆向关键代码,得出通关密钥。

相关实验材料可以在CMU的官网下载:http://csapp.cs.cmu.edu/3e/labs.html

目前的水平只能完成到1-3关,详细记录攻关过程。

1.正式开始前的分析

先执行一下bomb,随便输入一个字串123。

首先要做的是在炸弹爆炸前设置断点,看程序都做了什么事情。

输入objdump  -t  bomb | less查看符号表,内容太多;猜测关键字和bomb有关,所以用正则表达式过滤一下:objdump -t bomb | grep "bomb".

其中explode_bomb应该和炸弹爆炸有关,可以在这里设置断点: b  explode_bomb

再反汇编看一下代码:objdump  -d  bomb > bomb.txt, 搜索“main”,很容易找到主函数入口。

从main函数往下找, 往下有phase_1--phase_6的函数名称,猜测是每个关卡的入口,也在这里设断点:

b phase_1

2.Phase_1攻关

分析完了用GDB打开bomb,执行以下命令,让程序停在phase_1入口:

反汇编查看下代码: disas

从汇编代码来看,执行的过程是比较输入的字符串和预设的字符串,如果相同的话就通关,不相等就爆炸。调用strings_not_equal前,把地址0x402400的内容复制到了寄存器%esi。

X86-64系统CPU使用的16个寄存器中,每个寄存器都有一定的使用规则。比如%rbp, %rbx属于被调用者保存寄存器,被调用的函数必须保证返回调用者时,这两个寄存器的内容不变。所以被调用者一开始就必须先压栈,结束再出栈。

%rdi, %rsi, %rdx, %rcx, %r8, %9, 在执行call函数调用时,分别依次存放第1-6个参数,参数不足6个则后面的不使用;参数大于6个寄存器不够了,则开辟栈存在栈里面。

据此可以猜测,函数string_not_equal有两个形参,分别存在%edi和%esi中,用x/s $rdi 和 x/s $rsi 打印看下,果然一个是输入参数,一个是通关密码。据此第一关通过了。

3、Phase_2攻关

用"b phase_2"命令设置断点,随便输入一个字串后程序在phase_2入口停下,"disas"反汇编查看代码:

可以看到,0x400efc-0x400f02首先把“被调用者保存”寄存器压栈,然后开辟了一个28字节的栈,把栈指针拷贝给了%rsi寄存器,再调用了read_six_numbers函数。反汇编"disas read_six_numbers"看下:

0x40145c-0x40147c都是执行的从栈中拷贝内容到寄存器之类的操作,对于突然出现的地址0x4025c3,打印出来看下,是格式字符串,由此判断第二关要输入的内容是6个int类型的数据。重新运行程序,在第二关时随便输入6个数字:1 2 3 4 5 6,并将断点设置在下图红框的位置,并运行到这里。这里往下都是比较的操作,所以在红框位置之上,相应的数据应该都已经入栈或者放在指定的寄存器了。

阅读这段汇编代码要注意的有寄存器寻址和间接寻址的区别mov和lea的区别

比如0x400f17 mov -0x4(%rbx), %eax这一句,第一个操作数属于间接寻址,那么执行的翻译成C语句相当于:%eax = *(%rbx-4)。没错是取地址中的值。0x400f25: add $0x4,%rbx这一行是寄存器寻址,翻译成C语句相当于:%rbx=%rbx-4。

mov和lea的区别是,lea不解引用,所以0x400f30: lea 0x4(%rsp),%rbx相当于%rbx = %rsp+4,   x400f35 lea 0x18(%rsp), %rbp相当于:%rbp = %rsp+0x18=%rsp+24.

继续回到汇编代码,输入的数字是int型,在64/32机器上都占用4个字节,所以需要的占用栈24字节的空间。很容易联想到栈中存放着的是我们输入的数字,打印出来证实:

首先进行栈顶元素和1的比较,不相等则调用explode_bomb,相等则进行跳转1(红笔标注的数字)【所以输入的第一个数字应该是1】,1箭头末尾的两个lea操作,第一个是让%rbx=%rsp+4,即指向第二个我们输入的数字,第二个是让%rbp=%rsp+24,即指向栈的第六个元素末尾,用于判断循环结束的。

接着进行跳转2,%eax = *(%rbx-4),即%eax=1;接着%eax翻倍等于2,判断%eax是否等于*(%rbx),即*(%rsp+4),不等就调用explode_bomb【所以输入的第二个数字是2】。

接着进行跳转3,%rbx=%rbx+4,注意%rbx目前存放的是指针不是数据,所以%rbx又往栈底移动了一个4个字节,现在指向第3个我们输入的数字了.cmp %rbp, %rbx这是比较%rbx有没有到第六个元素末尾,如果到达,循环就结束了。

接着进行跳转6,%eax = *(%rbx-4),即%eax=2;接着%eax翻倍等于4,判断%eax是否等于*(%rbx),即*(%rsp+8),不等就调用explode_bomb【所以输入的第三个数字是4】。

翻译成C语言类似

int val = 1;
int * end = rsp+6;
do
{
if(*rsp==val)
{
val = *rsp * 2;
rsp++;
}
else{
explode_bomb();
}
}while(rsp!=end);

依次类推,需要我们输入的数字分别是:1 2 4 8 16 32

4.Phase_3攻关

Phase_3和Phase_2类似,也是在一开始开辟了18个字节的栈,分别令%rcx, %rdx指向栈的两个位置,这里并没有从栈顶开始使用。

出现0x4025cf比较突兀,打印出来看是格式化字符串“%d %d”,推断这次要输入的是两个int类型数据。调用sscanf回来后比较返回值是否大于1,大于1则跳到<Phase_3+39>。可以输入两个数字,运行到这里后,打印%rsp+8和%rsp+0xc来确认,这两个位置存放的就是我们输入的第一个和第二个数字。

0x400f6a判断第一个参数是否小于8,如果大于或等于则跳到<phase_3+106>处的explode_bomb处。负数的补码相当于正无穷,也会跳到explode_bomb,由此判断第一个参数参数是[0,7]之间的数。看起来有点像一个switch结构了。

接下来出现的无条件调整语句,jmpq  *0x402470(,%rax,8), 也是一个间接跳转,跳转地址是*(0x402470+%rax*8)。

分别打印出%rax的值的不同情况:

%rax--------*(0x402470+%rax*8)----------%跳转地址----------%跳转后的操作

0           0x402470                                           0x00400f7c               %eax=0xcf   (d: 207)

1         0x402470+0x8                                     0x00400fb9              %eax=0x137 (d:311)

2         0x402470+0x10                                   0x00400f83              %eax=0x2c3 (d:707)

3          0x402470+0x18                                    0x00400f8a              %eax=0x100 (d:256)

4          0x402470+0x20                                   0x00400f91              %eax=0x185 (d:389)

5          0x402470+0x28                                    0x00400f98              %eax=0xce (d:206)

6          0x402470+0x30                                   0x00400f9f              %eax=0x2aa (d:682)

7          0x402470+0x38                                    0x00400fa6              %eax=0x147 (d:327)

所以Phase_3其实等价于一个switch结构:

int args1, args2,val;
scanf("%d %d", &args1, &args2);
switch(args1)
{
case 0: val = 207;break;
case 1: val = 311;break;
case 2: val = 707;break;
case 3: val = 256;break;
case 4: val = 389;break;
case 5: val = 206;break;
case 6: val = 682;break;
case 7: val = 327;break;
default:
   explode_bomb();
}
if(args2!=val)
   explode_bomb();

所以正确答案有7组:(0,207), (1,311),(2,707),(3,256),(4,389),(5,206),(6,682),(7,327).

至此,Phase_3攻关完毕。后面的关卡未来水平提高了再战。

《CS:APP》二进制炸弹实验(phase_1-3)的更多相关文章

  1. BinaryBombs(二进制炸弹实验)

    实验介绍 使用所学知识拆除Binary Bombs来增强对程序的机器级表示.汇编语言.调试器和逆向工程等理解. Binary Bombs(二进制炸弹)是一个可执行程序,是C语言编译链接成的,包含pha ...

  2. 深入理解计算机系统 (CS:APP) 缓冲区漏洞实验 – Buffer Lab 解析

    原文地址:https://billc.io/2019/05/csapp-cachelab/ 写在前面 这是 CSAPP 官网上的第 4 个实验 buflab,也是学校要求的第三个实验.这个实验比上一个 ...

  3. 《CSAPP》实验二:二进制炸弹

    二进制炸弹是第三章<程序的机器级表示>的配套实验,这章主要介绍了x64汇编,包括:操作数的表示方式,数据传送指令,算术和逻辑指令,控制流跳转指令,过程(procedure)的实现与运行时栈 ...

  4. CS:APP配套实验 Data Lab

    刚刚完成注册博客,想写一篇随笔,方便以后自己回顾.如果恰好也能帮助到你,是我的荣幸. 这次随笔是记载我的计算机系统(CS:APP,Computer Systems:A Programer's Pers ...

  5. 深入理解计算机系统 (CS:APP) Lab2 - Bomb Lab 解析

    原文地址:https://billc.io/2019/04/csapp-bomblab/ 写在前面 CS:APP是这学期的一门硬核课程,应该是目前接触到最底层的课程了.学校的教学也是尝试着尽量和CMU ...

  6. csapp lab2 bomb 二进制炸弹《深入理解计算机系统》

    bomb炸弹实验 首先对bomb这个文件进行反汇编,得到一个1000+的汇编程序,看的头大. phase_1: 0000000000400ef0 <phase_1>: 400ef0: 48 ...

  7. CSAPP:逆向工程【二进制炸弹】

    转载请注明出处:https://www.cnblogs.com/ustca/p/11694127.html 二进制炸弹任务描述 拓展:缓冲区溢出攻击 "二进制炸弹包含若干个阶段,每个阶段需要 ...

  8. 图文并茂-超详解 CS:APP: Lab3-Attack(附带栈帧分析)

    CS:APP:Lab3-ATTACK 0. 环境要求 关于环境已经在lab1里配置过了.lab1的连接如下 实验的下载地址如下 说明文档如下 http://csapp.cs.cmu.edu/3e/at ...

  9. 深入理解计算机系统 (CS:APP) - 高速缓存实验 Cache Lab 解析

    原文地址:https://billc.io/2019/05/csapp-cachelab/ 这个实验是这学期的第四个实验.作为缓存这一章的配套实验,设计得非常精妙.难度上来讲,相比之前的修改现成文件, ...

随机推荐

  1. fedora下一些问题的解决方案汇总

    解决fedora下一些使用问题 一 解决fedora下无法使用Fn+功能键来调整亮度的问题 在fedora下,背光的配置参数在/sys/class/backlight文件夹下,根据不同的显卡,有不同的 ...

  2. HDU 5547 Sudoku(DFS)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=5547 题目: Sudoku Time Limit: 3000/1000 MS (Java/Others ...

  3. 20170721_python字符串操作_《python语言及其应用》

    str = 'abcde...wxyz' [num]提取指定字符 str[0] == 'a' str[1] == 'b' str[-1] == 'z' [start:end:step]分片/切片,一定 ...

  4. Vue.js之深入浅出

    介绍引言 Vue.js(读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库只关注视图层,它不仅易于上 ...

  5. cocos2dx之WebView踩过的坑(android返回键处理问题)

    最近游戏接入了一个私服平台,由于没有sdk,所以支付相关的操作需要在网页端进行,也就是说点击充值需要在游戏内部弹出一个网页,并定位到平台充值的地址.查阅相关资料后决定使用cocos2dx自带的WebV ...

  6. 【SpringMVC】【EasyUI】关于使用EasyUIForm上传文件,返回JsonIE提示下载文件的解决办法!

    先说一下环境 EasyUI+SpringMVC+MyBatis 因为按正常手段,无法使用Ajax来提交一个包含文件的表单,故想到利用EasyUI的Form来提交,EasyUI的form封装了一套伪Aj ...

  7. [js] 小谈 export (没总结完)

    作用 导出变量/类 等等 用法 index.js 文件 export default name 仅导出一个变量 import name from './index.js' index.js 文件 ex ...

  8. 【HTML】table元素

    1.最简单的table <table> <tr> <th></th> </tr> <tr> <td></td& ...

  9. 统一代码风格工具——editorConfig

    前面的话 在团队开发中,统一的代码格式是必要的.但是不同开发人员的代码风格不同,代码编辑工具的默认格式也不相同,这样就造成代码的differ.而editorConfig可以帮助开发人员在不同的编辑器和 ...

  10. RabbitMQ入门-高效的Work模式

    扛不住的Hello World模式 上篇<RabbitMQ入门-从HelloWorld开始>介绍了RabbitMQ中最基本的Hello World模型.正如其名,Hello World模型 ...