您的位置:首页 > 移动开发

CS:APP二进制炸弹phase3

2017-06-14 16:35 323 查看
写在前面

到目前为止,已经比较轻松的完成了前两个阶段。本文来试试第三个阶段吧。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语句的跳转表,如果能迅速察觉到,没什么难度!继续下一个阶段吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: