CS:APP二进制炸弹phase3

本文详细解析了phase_3挑战的解决过程,包括利用sscanf读取输入、判断输入值及通过switch语句跳转表进行条件验证的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

到目前为止,已经比较轻松的完成了前两个阶段。本文来试试第三个阶段吧。let's go !!!


分析

还是一样,先找到调用phase_3处的汇编:


继续反汇编函数phase_3如下:


函数phase_3一走来就调用了sscanf函数来读取我们的输入。有了分析phase_2的经验,很容易从寄存器%esi中获得格式化字符串,x/s显示的结果是"%d %d",即从我们的输入中获得两个int型整数。我们不妨将第一个整数命令为num1,第二个为num2。

紧接着判断sscanf的返回值,如果小于等于1,则触发炸弹。否则继续。

cmpl   $0x7,0x8(%rsp),判断num1是否大于7,如果大于,则调整到地址0x0000000000400fad处,触发炸弹。否则继续。

接下来的两条指令是难点,如果搞懂了这两条指令就差不多了。第一条指令,mov    0x8(%rsp),%eax,将num1的值存储寄存器%eax中,第二条指令jmpq   *0x402470(,%rax,8),这条指令什么意思呢? 可能AT&T的汇编指令不太容易看懂,那我们通过set disassembly-flavor intel来查看intel形式的这条指令为jmp    QWORD PTR [rax*8+0x402470],这下就容易多了 -- 取出地址rax*8+0x402470处的值,并调转到这个值指示的内存地址处继续执行。如果读者有一点点的经验,就可以很容易看出此处是switch语句的跳转表,跳转表的首地址为0x402470,我们可以通过x命令看看这个表中都存储了哪些地址。


因为上面判断num1小于8,因此可知跳转表中应该存储有8个地址。x表明以十六进制的形式显示地址,g表示每8个字节的内存,因为这是x64平台,所以地址占8个字节。

仔细观察这些地址,可以发现都是函数phase_3范围内的地址。

当num1等于0时,跳转到0x0000000000400f7c处执行。如果num2不等于0xcf,则触发炸弹。

当num1等于1时,跳转到0x0000000000400fb9处执行。如果num2不等于0x137,则触发炸弹。

当num1等于2时,跳转到0x0000000000400f83处执行。如果num2不等于0x2c3,则触发炸弹。

当num1等于3时,跳转到0x0000000000400f8a处执行。如果num2不等于0x100,则触发炸弹。

当num1等于4时,跳转到0x0000000000400f91处执行。如果num2不等于0x185,则触发炸弹。

当num1等于5时,跳转到0x0000000000400f98处执行。如果num2不等于0xce,则触发炸弹。

当num1等于6时,跳转到0x0000000000400f9f处执行。如果num2不等于0x2aa,则触发炸弹。

当num1邓毅7时,跳转到0x0000000000400fa6处执行。如果num2不等于0x147,则触发炸弹。

因此可以得出这个阶段的答案有8种,任选其一。分别为(0,207)、(1,311)、(2,707)、(3,256)、(4,389)、(5,206)、(6,682)、(7,327)。

C源码应该如下所示:


void phase_3(const char *input)
{
	//  0x8(%rsp)  0xc(%rsp)
	int num1, num2;
	//     %rdi     %rsi   %rdx   %rcx 
	int result = sscnaf(input, "%d %d", &num1, &num2);
	if (result <= 1) {
		explode_bomb();	
	}

	switch (num1) {
		case 0:	// 0 207
			if (num2 != 0xcf) {
				explode_bomb();
			}
			break;
		case 1:	// 1 311
			if (num2 != 0x137) {
				explode_bomb();
			}
			break;
		case 2:	// 2 707
			if (num2 != 0x2c3) {
				explode_bomb();	
			}
			break;
		case 3:	// 3 256
			if (num2 != 0x100) {
				explode_bomb();	
			}
			break;
		case 4:	// 4 389
			if (num2 != 0x185) {
				explode_bomb();
			}
			break;
		case 5:	// 5 206
			if (num2 != 0xce) {
				explode_bomb();	
			}
			break;
		case 6:	// 6 682
			if (num2 != 0x2aa) {
				explode_bomb();	
			}
			break;
		case 7:	// 7 327
			if (num2 != 0x147) {
				explode_bomb();	
			}
			break;
		default:
			explode_bomb();
			break;
	}
}

总结:

本阶段主要考察switch语句的跳转表,如果能迅速察觉到,没什么难度!继续下一个阶段吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值