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语句的跳转表,如果能迅速察觉到,没什么难度!继续下一个阶段吧!
到目前为止,已经比较轻松的完成了前两个阶段。本文来试试第三个阶段吧。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语句的跳转表,如果能迅速察觉到,没什么难度!继续下一个阶段吧!
相关文章推荐
- CS:APP二进制炸弹开篇
- CS:APP二进制炸弹phase1
- CS:APP二进制炸弹phase2
- CS:APP二进制炸弹附加篇
- CS:APP二进制炸弹phase4
- CS:APP二进制炸弹phase5
- CS:APP二进制炸弹phase6
- CSAPP LAB————二进制炸弹(bomblab)
- CS:APP3e 深入理解计算机系统_3e Attacklab 实验
- 【WPF】app.g.cs文件无法修改、修改后自动恢复问题解决办法
- CS:APP3e Lab Assignments 的官方实验材料
- 《CS:APP》 chapter 7 Linking 笔记
- App.xaml.cs
- CSAPP lab binary bomb 二进制炸弹
- 《CS:APP》 chapter 8 Exceptional Control Flow 注意事项
- 为什么vs2005建立的cs类要放在app_code文件夹才能在其他页面用?
- 《CS:APP》 chapter 1 A Tour of Computer Systems 笔记
- 关于新旧版本的GCC对浮点数运算的一些行为(读《CS:APP》)
- CS:APP3e 深入理解计算机系统_3e ShellLab(tsh)实验
- Egret原生打包App Protobuf二进制以及一些列梗