导航
BombLab Phase-3 & Phase-4 &Phase-5
BombLab phase-6 & secret_phase
Phase_1
1.观察源代码,看一下输入有哪些
通过观察,我们知道每个phase前面都有一个输入,并且为string类型,我们会将这个string传入phase_1中,所以栈帧中phase_1帧前面应该只有一个参数。
2.反汇编phase_1函数。
我们可以看到,在栈顶的顶8个字节存储了两个东西,第一个是将常量 $0x804a15c存入了(esp)+4的位置,第二个是将ebp+8存入了(esp),这第二个就是我们传入phase_1的参数,可以看出应该就是我们输入的字符串的地址,那么可以猜测第一个就是被比较的字符串的地址了。
3.画出phase_1的栈帧结构图
4.分析strings_not_equeal作用
从名字上来看,我们猜得到这个函数是对两个字符串比较是否相等,从调用时机来看——在调用前将字符串地址传入了栈顶,更加印证我们的猜想,当然这些都是猜测,我们还是具体来看下反汇编代码来分析一下。
查看strings_not_equeal函数汇编代码
我们可以看到,上面两个箭头分别跳到如下两个箭头的位置:
当二者长度不一致,eax的值就为1,当二者一致时,eax返回0.所以这个函数就是用来比较两个字符串是否相等的。
我们看到phase_1里面调用了strings_not_equal函数,那么我们就来画一下这个函数的栈帧图:
5.到这儿,我们就明白,我们输入的字符最后是要和0x804a15c地址的字符串做比较,既然要求相等,那么我们查看这个内存里存放的字符串:
我们看到这句话,那当我们输入进去测试的时候:
Ok,phase_1就搞定了!
Phase_2
1.同样,我们先对Phase_2进行反汇编测试看看结果:
2.观察phase_2,我们观察到里面有两个函数调用,分别是read_six_numbers和explode_bomb函数,此外,观察到phase_2里面还有一个循环:
3.我们可以画出phase_2的栈帧如下所示:
4.看完了phase_2,我们再来研究一下read_six_numbers函数
我们观察到read_six_numbers的功能就是读取六个数字然后存到对应的内存上,然后我们观察到在这个函数中,edx寄存器存储的都是phase_2中存储的六个书数的地址,这样scanf读取的六个数就能存在phase_2的六个内存位置上。
对于read_six_numbers的栈帧图如下;
5.了解了read_six_numbers之后,我们再回到phase_2的循环:
我们可以看到再循环之前有两个寄存器初始化,一个是ebx,还有一个是esi,
Ebx很简单,我们可以看到,ebx是一个用来记录循环位置的变量,而esi会和ebx 比较,所以esi是一个用来判断截止条件的。我们有看到这个:
这个实现了前两个数的相加,这两个数的位置是根据ebx确定的,所以这个循环的意义在于不断地累加前面两个值,也就是一个斐波那契地序列计算过程。
6.最后地分析:
如果前两个我们输入地值不是 0和1,那么炸弹爆炸。所以我们前面输入的值必须是0 和1,并且还要满足斐波那契序列,如果你该数不等于前两个数相加,则爆炸:
遇到的问题及解决方法
- 关于cmp指令和test指令区别
我们发现汇编代码在进行指令跳转的前一步,通常会有这两步,那么同样都是比较指令,二者的具体区别又是什么呢?
查看教材和网上博客,大致异同点可以整理如下:
异:cmp 是做加减运算,test是做逻辑与运算。
同:cmp和test运算的结果都不会传回影响目的操作数,而都会去改变标志位。
二者用法:
Cmp用来比较有符号数和无符号数的大小,而test用法检测该数某些位是否存在1,如检查AL中的位6和位2是否有一位为1,可以用如下指令:test AL,01000100b,如果这两个位全为0.则ZF的值为1,否则清0,那么根据标志位设置的跳转就只能为jz或jnz
1.lea指令和mov指令的差别
在刚学这两个指令时,老师说lea指令和mov指令都可以实现数据传输,但是没有说二者的具体使用区别,一直以来都是处于半知半解的状态,今天就二者做了下总结。
mov的用法:
mov指令又称数据传输指令,它的作用是进行除内存与内存之间的其他形式的数据传输。
lea的用法:
load effective address,又称加载有效地址指令,直接将得到的数赋值,而不会去寻址。
比如:
lea eax,[ebx+8]--- 将ebx+8 的值给eax. 等价于 mov eax,ebx+8
mov eax,[ebx+8] --- 加载内存中地址为ebx+8 处的数据
lea eax,ebx+8 ------ 加载内存中地址为ebx+8 处的数据
2.关于字符串存储方式的疑惑
我们看到关于在传递字符串时,我们传递的是字符串的地址,而不是具体内容,既然我们是在栈中申明,为什么不是将字符串存在栈中呢?
后来,我们查询了内存的分配机制:
附:博客地址 http://www.cnblogs.com/chenleiustc/archive/2011/04/08/2009994.html
从一个直观的角度理解,字符串类型不是作为C中的基本类型,在C中并没有规定string类型的具体长度,所以编译器在编译时并不能确定该为它分配多大的栈内存,而像int,char他们都有规定的内存长度,所以当作为局部变量时可以存放在栈内存中。
综上,我们就可理解为什么传递字符串时是传递它的地址而不是它的内容了。