二进制炸弹bomblab-第三关解析

观前提示:本文并非速通指南,偏向于如何一步步思考与解题,也许会分析得有些拖沓。且本文为系列文章,每一篇会分析一关的破解思路,前文提到的知识点后面不会赘述,分析过的类似的汇编代码段也不会再分析,除非是没见过的结构,所以越往后分析得越少。

本文共一千一百余字。

前言

​ 如果这些解析对你有帮助,那么我会非常荣幸和开心!

​ 如果我的解析存在错误,非常抱歉误导了你!请在评论区提出!我也是一个正在不断学习的学生。

​ 谢谢你!

正式破解

概览全局

白色部分是需要开始分析的地方。其他部分是一些栈操作和堆栈溢出检查,与解题无关,简单说就是程序最开始设置一个值,执行过程中如果发生溢出情况,这个值就会被溢出的数值覆盖掉,最后检查这个值有没有变过,就可以知道有没有发生过溢出。后记会附上几个详细解释的文章链接。

blob

这一关没什么新玩意,只是一些跳转赋值,所以只提几个稍微需要注意的小点。

(1)跳转指令的区别

  1. jmp *0x804a000(,%eax,4)

    这是一条间接跳转指令。它的含义是跳转到存储在内存地址0x804a000 + 4 * %eax的位置的指令。这种寻址方式通常用于实现函数指针的跳转。具体来说,它会读取内存地址0x804a000 + 4 * %eax处的内容,将其解释为一个地址,并跳转到那个地址所指向的指令。

  2. jmp 0x804a000(,%eax,4)

    这是一条直接跳转指令。它的含义是将当前指令指针增加到存储在内存地址0x804a000 + 4 * %eax的值,然后继续执行该地址上的指令。换句话说,它不会读取内存中的内容,而是直接将地址作为跳转目标。

总结区别:

  • 第一条指令是间接跳转,它从内存中读取一个指针值并跳转到该指针所指的位置。
  • 第二条指令是直接跳转,它将内存中的值作为一个偏移量,将当前指令指针增加该偏移量,并跳转到结果地址上的指令。

所以,来到这一步的时候,需要用到x/a 命令,它用于查看内存中存储的指针值,并将这些值解释为内存地址。a指的是address。

blob

然后下一步就会跳转到0x8048c38 <phase_3+131>处继续执行命令。

(2)输入参数个数的限制方法

0x08048bd7 <+34>:	call   0x8048810 <__isoc99_sscanf@plt>
0x08048bdf <+42>:	cmp    $0x1,%eax
0x08048be2 <+45>:	jg     0x8048be9 <phase_3+52>
0x08048be4 <+47>:	call   0x804907d <explode_bomb>

可能有的人是这样推理的:sscanf出来后,eax存的是输入参数的个数,cmp指令和jg指令连起来看就是:if eax greater than 1, jump to <phase_3+52>, if not, call <explode_bomb>.

0x08048be9 <+52>:	cmpl   $0x7,0x4(%esp) ;查看内存可以发现0x4(%esp)是我们输入的第一个参数
0x08048bee <+57>:	ja     0x8048c2c <phase_3+119>;结合下文知道<phase_3+119>会引爆炸弹

然后接着分析,cmpl指令和ja指令连起来看就是:if input above 7,jump to 0x8048c2c to call <explode_bomb>.

所以得出我们的输入个数要大于1,而且第一个数值要小于等于7,再加上一般自己测试不会想到负数,所以看上去也对,也不会触发炸弹。但是,这忽略了一点细节:

  1. ja 指令: “Jump if Above” 的缩写,它用于无符号整数的比较。
  2. jg 指令: “Jump if Greater” 的缩写,它用于有符号整数的比较。

所以实际上,更完整地说,cmpl指令和ja指令连起来限制了第一个数值要小于等于7,同时,也限制了它要大于等于0。因为负数的最高位会是1,正数是0,如果按无符号数比较,即把符号位按数值位来解析,负数会大于正数。

还原成C代码

void phase_3(char *input){
    int numbersInput[2];
    int num = sscanf(input, "%d %d", &numbersInput[0],&numbersInput[1]);
    
    if(num > 1){
        int result;
        if( (unsigned int) numbersInput[1] <= 7 ){ //无符号比较
            switch (numbersInput[0]) {
    			case 0:
        			result = 979;break;
    			case 1:
       				result = 790;break;
    			// 其余 case 分支 略 会一直到case 7
			}
            
            if(numbersInput[1] == result){
            	return;
        	}
        } 
    }
    explode_bomb();
}

后记

详细参考文章:
what-is-gs-in-assembly
what-does-this-instruction-do-mov-gs0x14-eax

感谢你看到这里!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值