最近在学C++底层的相关知识,又拿出了当时西湖论剑初赛的easyCpp
,当时做题的时候没做出来,再研究一下代码
另外感觉最近C++的逆向越来越多,不熟悉这块的话分析很费力,但熟悉之后大概就知道关键代码在哪了
静态分析
后来复现时发现动态调试很容易看出程序逻辑,不过有一点猜的成分,本文主要详细地进行静态分析
输入16个数
程序交互一开始输入16个数,然后把它们依次push_back
到vector input
中
程序中还有一个vector
存了fib
数列的前16项,fib
就是普通的fibonacci
数列
transform
接下来主要是一个std::transform
,改了一下变量名
可以看到,主要是对vector input
实施一个函数操作,从第二项(begin),到最后一项(end),都应用一个一元操作,并且将结果保存在vector v25
中,命名为back_insert
了
模板声明如下:
template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform (InputIterator first1, InputIterator last1,
OutputIterator result, UnaryOperation op);
点开可以看到一大堆iterator
相关的代码,但关键是其中的lambda函数
,也就是关键的一元操作
发现关键的lambda函数
其实只是做了一个简单的加法
也就是说,到这一步
输入的16个数字,后15个都加上了第一项,保存到v25这个vector中
accumulate
接下来的关键是std::accumulate
,这是折叠函数,代码比较复杂
举个例子,用
std::accumulate
对一个vector
求和,迭代器设置头尾,操作(函数)设置成加法,设定初始累加值为0,就会将整个vector
加到累加值上
总之,std::accumulate
是用来把这个数据集通过某一操作折叠起来获得结果的函数,可以加,可以乘,等等
不过这个accumulate
中的函数看起来不太好理解...改一下变量名字
注意到std::copy
,把begin到end
都插入到result
的尾部
变量a1
即result
,因为是折叠函数,每次push_back
当前数后,再把begin到end
插入到尾部
再作为返回值返回result
也就是说,比如本来是1 2 3
第一轮就是简单的 push_back(1)
第二轮,vector一开始只有2,再copy上之前的1,就是2 1
第三轮,vector一开始是3,copy上之前的2 1,也就是3 2 1
这个accumulate
实际上做的事是反转vector
自己写一个代码试一下
vec1 = std::accumulate(vec2.begin(), vec2.end(), std::vector<int>(),
[](std::vector<int>acc, int num)->std::vector<int> {
std::vector<int>result; result.push_back(num);
std::copy(acc.begin(), acc.end(), std::back_inserter(__));
return result;
});
逻辑基本相同,测试结果也正是反转vector
解题
总结一下程序流程
- 输入16个数,后15个每个加上第一个数
- 16个数倒序后,要求相等fib数列的前16项
最后会通过std::copy_if
输出我们输入的一部分数值
解题代码比较简单
#include<stdio.h>
#include<stdlib.h>
int fib(int n) {
if (n == 0 || n == 1)return 1;
else return fib(n - 1) + fib(n - 2);
}
int main(){
for (int i = 15; i >= 0; i--){
printf("%d ", fib(i) - fib(15));
}
}
输入这16个数就得到了flag
题目的逻辑很简单,但是代码比较费解
甚至有一点...混淆的感觉?
还是得多熟悉C++