CSAPP——实验二 拆炸弹
Phase1
disas phase_1, 反汇编 phase_1 函数
在 phase_1函数入口处 设置断点 break phase_1
run 开始运行,输入字符串 “hello”
stepi ,逐条执行命令。寄存器 %rdi、%rsi、%rdx,%rcx、%r8、%r9用作传递函数参数,分别对应第1个参数、第2个参数直到第6个参数。
我们的输入作为调用函数时用到的参数保存在了寄存器%rdi中。对应的地址为 0x603780,用 x/s 0x603780 查看对应的值,确实如此。
用 stepi 继续执行下一条指令,即运行到 mov $0x402400,%esi,此时用 x/s $esi 查看寄存器里面的值,即地址 0x402400的值,即为第一颗炸弹的答案。
Phase_2
观察 read_six_numbers 发现要输入6个数字,6个数字会依次存在 %rsp,%rsp+4,%rsp+8,%rsp+12...%rsp+24,cmpl $0x1,(%rsp), 第一个数字是1,再接下去看跳转到52,%rsp+4对应第2个数字,放进%rbx中,将%rbp设置成%rsp+24(%rbp是用来判断循环是否退出的寄存器),之后跳转到27,这里将第1个数赋值给%eax,将%eax*2去和第2个数对比,如果相等就继续,以此类推,可以发现这个循环就是用来判断输入的数字是否依次增大一倍的,所以第二题的拆弹密码就是:1 2 4 8 16 32
Phase_3
phase_3函数的反汇编代码
断点逐步执行指令,并打印出 0x4025cf 的内容
说明 sscanf 输入的两个整数存在 0x4025cf 中。反汇编后存在很多条jmp指令,可见是switch结构的语句判断。要跳转过去的地址是 0x402470+%rax+8,而eax就是我们输入的第一个数。
之后的每一个jmp都看做是一个case语句。每条 case 语句里,都是将 某个立即数 赋值给 寄存器 %eax, 最后都跳转到<phase_3+123> 的位置,判断第二个数字是否匹配。
而 %eax 的值,是根据输入的第一个数 跳转到相应的case语句中赋值的,所以 %eax 有很多的取值可能。但注意:cmpl $0x7,0x8(%rsp),第一个输入的数字一定要小于7,否则会直接引爆炸弹。
我们选择输入的第一个参数为 3,则对应的跳转到十六进制 0x100 ,即 256。
Phase_4
phase_4函数
查看 func4 函数的反汇编代码,func4内部在调用func4,递归的汇编
给每条指令加上了注释:
对应的c语言程序
int func4(int target, int step, int limit) {
/* edi = target; esi = step; edx = limit */
int temp = (limit - step) * 0.5;
int mid = temp + step;
if (mid > target) {
limit = mid - 1;
int ret1 = func4(target, step, limit);
return 2 * ret1;
} else {
if (mid >= target) {
return 0;
} else {
step = mid + 1;
int ret2 = func4(target, step, limit);
return (2 * ret2 + 1);
}
}
}
最后推出其一个答案为(7,0)
Phase_5
要求输入的字符串长度=6