观前提示:本文并非速通指南,偏向于如何一步步思考与解题,也许会分析得有些拖沓。且本文为系列文章,每一篇会分析一关的破解思路,前文提到的知识点后面不会赘述,分析过的类似的汇编代码段也不会再分析,除非是没见过的结构,所以越往后分析得越少。
本文共一千余字。
前言
如果这些解析对你有帮助,那么我会非常荣幸和开心!
如果我的解析存在错误,非常抱歉误导了你!请在评论区提出!我也是一个正在不断学习的学生。
谢谢你!
正式破解
phase_4代码分析
大概扫视一下phase4代码,可以大致分成4部分:
关于关卡核心逻辑部分,下面我们边分析代码边追踪堆栈内存(内存信息我没截图),就可以分析出一些信息:
- phase_4传了2个参数给func4,一个是我们输入的第一个参数,一个是9。所以猜测func4的参数列表有2个参数。
- 从func4出来之后,应该还是按照这个程序的惯例把函数返回结果存到了eax里面。其实这个可能涉及“调用约定”(calling convention)的其中一种——C declaration。图源维基百科:
- 简单来说,Cdecl是一种常见的调用约定,特点是参数由调用者在函数调用之前压入栈中,调用完成后由调用者负责清理栈。返回值通常存储在寄存器
%eax
中。后记有附上一篇关于函数调用实现的文章。
func4函数代码分析
进入func4函数,明显可以注意到它自己调用了自己,它是递归函数:
绿框部分涉及到的知识(比如 test)在之前的文章里面有说过,不再赘述,在这里只分析func4的递归部分:
还原成C代码大概如此(不太可能百分百还原):
int func4(int ebx, int edi) {
int eax;
if (ebx <= 0) {
result = 0;
} else {
eax = edi;
if (ebx != 1) {
eax += func4(ebx - 1, edi) + func4(ebx - 2, edi);
}
}
return eax;
}
然后偷个懒,丢到编译器里跑一跑,答案就出来了。
因为纯自己分析太费手了,9层递归,每个分成3项。4层就开始麻烦了:
完整还原成C代码
int func4(int i, int input) {
int result;
if (i <= 0) {
result = 0;
} else {
result = input;
if (i != 1) {
result += func4(i - 1, input) + func4(i - 2, input);
}
}
return result;
}
void phase_4(char *input){
int numbersInput[2];
int num = sscanf(input, "%d %d", &numbersInput[0],&numbersInput[1]);
if(num == 2){
numbersInput[1] -= 2;
if( (unsigned int)numbersInput[1] <= 2 ){
int result = func4(9,numbersInput[1]);
if(numbersInput[0] == result){
return;
}
}
}
explode_bomb();
}
后记
感谢你看到这里!