二进制炸弹bomblab |
您所在的位置:网站首页 › 隐藏296关怎么过关视频 › 二进制炸弹bomblab |
观前提示:本文并非速通指南,偏向于如何一步步思考与解题,也许会分析得有些拖沓。且本文为系列文章,每一篇会分析一关的破解思路,前文提到的知识点后面不会赘述,分析过的类似的汇编代码段也不会再分析,除非是没见过的结构,所以越往后分析得越少。 本文共2400余字。 前言 如果这些解析对你有帮助,那么我会非常荣幸和开心! 如果我的解析存在错误,非常抱歉误导了你!请在评论区提出!我也是一个正在不断学习的学生。 谢谢你! 破解前的分析当我们来到这里,已经解完了6个关卡。在第一篇文章我们有说过,main函数里一共调用了6个关卡函数。炸弹提示语好像也告诉我们拆除了炸弹: “But isn’t something… missing? Perhaps something they overlooked? Mua ha ha ha ha! ” 但是是不是有什么东西… 缺失了? 也许是他们忽略了什么!*得意地怪笑 可见,炸弹还没有完全破解。 回顾一下,我们一路走来几乎是把所有关卡函数和它的子函数都分析了个遍。所以,仅剩的phase_defused函数就是最后的疑点。 正式破解 隐藏关卡触发方法扫视一下phase_defused函数果然可以发现它有可能会触发隐藏关: 0x08049249 : call 0x8048e92那就来分析一下这个函数: 0x080491d6 : sub $0x6c,%esp 0x080491d9 : mov %gs:0x14,%eax 0x080491df : mov %eax,0x5c(%esp) 0x080491e3 : xor %eax,%eax ;栈保护操作,之前的文章讲过 0x080491e5 : cmpl $0x6,0x804c3cc 0x080491ec : jne 0x8049261 ;………………略去中间代码…………………… 0x08049261 : mov 0x5c(%esp),%eax 0x08049265 : xor %gs:0x14,%eax 0x0804926c : je 0x8049273 0x0804926e : call 0x8048790 0x08049273 : add $0x6c,%esp 0x08049276 : ret可以发现:
假设我们没有跳转,程序接着往下走: 0x08049217 : sub $0x8,%esp 0x0804921a : push $0x804a1d2 0x0804921f : lea 0x18(%esp),%eax 0x08049223 : push %eax 0x08049224 : call 0x8048f86 0x08049229 : add $0x10,%esp 0x0804922c : test %eax,%eax 0x0804922e : jne 0x8049251这个逻辑我在第一篇文章的后半部分提过,不在此赘述。在这里就是比较我们第四关输入的通关字符串的第三个字符串参数是否和0x804a1d2处的字符串相等,不相等又会导致跳过。 查看0x804a1d2处的字符串: 输出的2句字符串: 该死的!你找到了隐藏关卡! 但是找到它和解决它是完全不同的…… 看到了语气有趣的困难预告。 到这里已经知道触发隐藏关的条件了: 先要破解完6个普通关卡第四关的通关字符串要额外加一个字符串参数 “DrEvil” 分析隐藏关卡 0x08048e92 : push %ebx 0x08048e93 : sub $0x8,%esp 0x08048e96 : call 0x80490dd 0x08048e9b : sub $0x4,%esp 0x08048e9e : push $0xa 0x08048ea0 : push $0x0 0x08048ea2 : push %eax 0x08048ea3 : call 0x8048880strtol(String to Long)函数是C语言标准库中的一个函数,用于将字符串转换为长整型数(long int类型),并返回该数值。它的函数原型在头文件 中声明: long int strtol(const char *nptr, char **endptr, int base); nptr:要转换的字符串的指针。endptr:一个指向字符指针的指针,用于存储转换停止的位置。如果不想获取这个信息,可以传入 NULL。base:进制数,指定待转换字符串的进制。在这里就是把我们的输入转成10(0xa)进制。 0x08048ea8 : mov %eax,%ebx 0x08048eaa : lea -0x1(%eax),%eax 0x08048ead : add $0x10,%esp 0x08048eb0 : cmp $0x3e8,%eax 0x08048eb5 : jbe 0x8048ebc 0x08048eb7 : call 0x804907d ;输入的数字大于0x3e8 (即1000) 就炸 0x08048ebc : sub $0x8,%esp 0x08048ebf : push %ebx 0x08048ec0 : push $0x804c088 ;把ebx和0x804c088处的数据作为参数传入fun7 ebx是我的输入 另一个是题目定好的变量n1 0x08048ec5 : call 0x8048e41
那说明n1既不是数组也不是链表,那是什么呢?我们来试试查看从他开始的接下来的变量名,但是,内存空间该地址该怎么变换呢?地址该+4还是+8还是别的特殊位数?目前我们不知道,就先不碰运气枚举查看了,先往下看。 从fun7出来后: 0x08048eca : add $0x10,%esp 0x08048ecd : cmp $0x5,%eax 0x08048ed0 : je 0x8048ed7 0x08048ed2 : call 0x804907d ;fun7返回值不等于5就爆炸 0x08048ed7 : sub $0xc,%esp 0x08048eda : push $0x8049fbc 0x08048edf : call 0x80487c0 0x08048ee4 : call 0x80491d6 ;fun7返回值等于5就打印提示语 通关 0x08048ee9 : add $0x18,%esp 0x08048eec : pop %ebx 0x08048eed : ret
从这两句可以看出,那个新的数据结构能够按+4和+8两种方式跳转到下面的存储单元。 知道这个就可以查看余下的其他的变量了:
扫一眼就发现又是递归。 之前分析fun7最后应该要返回5,不然就会触发炸弹。那就意味着: 输入的值不能等于36这个根节点,不然直接返回0。如果过程中来到了叶子节点,并且此时它与输入值不相等,就会导致返回值为-1,就不可能通过(-1)*2 +1or +0 最后达成返回5的结果,所以输入值不能是遍历到达了叶子结点发现找不到,回溯到上一层去另外一个节点,即过程中不可以发生回溯。所以最后一定是找到了,所以输入值是树上的节点。所以5应该是递去到结点等于输入值,然后返回0, 然后一次次归回0x2+1, 1x2=2, 2x2 +1 =5。上面是从递去终点开始分析的,现在回过来结合fun7代码按正常顺序: 输入值 > 根 去右孩子输入值 < 当前节点的值 去左孩子输入值 > 当前节点的值 去右孩子输入值 == 当前节点的值 返回在刚刚画出的二叉树上走一遍即可发现输入值应该是47。 后记写到这里,这个系列共7篇文章终于完结了。 一路写下来发现有些地方可以讲解得更连贯,但是博客讲解还是有点受限,也许以后会录制视频版? 感谢你看到这里! |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |