西湖论剑初赛easyCpp探究
ret2nullptr CTF 9334浏览 · 2019-04-22 01:51

最近在学C++底层的相关知识,又拿出了当时西湖论剑初赛的easyCpp,当时做题的时候没做出来,再研究一下代码

另外感觉最近C++的逆向越来越多,不熟悉这块的话分析很费力,但熟悉之后大概就知道关键代码在哪了

静态分析

后来复现时发现动态调试很容易看出程序逻辑,不过有一点猜的成分,本文主要详细地进行静态分析

输入16个数

程序交互一开始输入16个数,然后把它们依次push_backvector 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的尾部

变量a1result,因为是折叠函数,每次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

解题

总结一下程序流程

  1. 输入16个数,后15个每个加上第一个数
  2. 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++

0 条评论
某人
表情
可输入 255