CS:APP二进制炸弹phase3

写在前面

到目前为止,已经比较轻松的完成了前两个阶段。本文来试试第三个阶段吧。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语句的跳转表,如果能迅速察觉到,没什么难度!继续下一个阶段吧!

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和引用[2]提供了关于`System.Resources.ResXResourceWriter`和`System.Resources.ResXResourceReader`的信息。些类是用于读取和写入资源文件的。资源文件包含了应用程序中使用的文本、图像和其他非代码资源。这些资源可以通过这两个类来读取和写入。因此,这两个类可以用于在Windows.Forms应用程序中管理资源。 引用和引用提供了有关使用Git进行版本控制时的一些错误信息和解决方法的信息。错误`error: failed to push some refs to 'https://github.com/xuefeilong/test.git'`意味着在推送更改到远程仓库时遇到了问题。错误提示建议先合并远程的更改(例如使用`git pull`命令),然后再次推送更改。引用提供了一种使用参数`-f`来强制推送更改的方法,但是并不推荐使用这种方法,因为它可能会导致丢失其他人的更改。 关于你提到的问题`SC : error CS2015: '“C:\Users\GZSL\source\repos\HelloWorld\Controllers\AboutController.cs”是二进制文件而非文本文件`,这个错误通常是由于尝试将二进制文件当作文本文件进行处理而导致的。要解决这个问题,你需要检查文件的类型并相应地进行处理。如果文件确实是二进制文件,则需要使用适当的工具或方法来处理它,而不是将其视为文本文件。 综上所述,`System.Resources.ResXResourceWriter`和`System.Resources.ResXResourceReader`是用于读取和写入资源文件的类,可以在Windows.Forms应用程序中使用。在使用Git进行版本控制时,遇到错误时可以尝试合并远程更改或使用强制推送的方法进行解决。在处理文件类型时,需要注意将二进制文件和文本文件区分开来,并使用适当的方法进行处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值