这道题目算挺简单的,全部都是标准库函数,没有用户自己写的函数,所以程序功能比较好推测。
源程序下载:http://file.eonew.cn/re/easyCpp 。
目录
主要代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // r15
__int64 v4; // rdx
__int64 v5; // rdx
__int64 v6; // rdx
__int64 v7; // rdx
__int64 v8; // r12
__int64 end; // rbx
__int64 v10; // rax
__int64 v11; // rdx
__int64 v12; // rbx
__int64 v13; // rax
__int64 v14; // r8
__int64 v15; // r9
__int64 v16; // rbx
char v17; // al
unsigned int *v18; // rax
const char **v20; // [rsp+0h] [rbp-190h]
signed int i; // [rsp+1Ch] [rbp-174h]
signed int j; // [rsp+20h] [rbp-170h]
char v23; // [rsp+30h] [rbp-160h]
char v24; // [rsp+50h] [rbp-140h]
char v25; // [rsp+70h] [rbp-120h]
char v26; // [rsp+90h] [rbp-100h]
char v27; // [rsp+B0h] [rbp-E0h]
__int64 v28; // [rsp+D0h] [rbp-C0h]
__int64 v29; // [rsp+F0h] [rbp-A0h]
char v30[72]; // [rsp+110h] [rbp-80h]
unsigned __int64 v31; // [rsp+158h] [rbp-38h]
v20 = argv;
v31 = __readfsqword(0x28u);
std::vector<int,std::allocator<int>>::vector(&v23, argv, envp);
std::vector<int,std::allocator<int>>::vector(&v24, argv, v4);
std::vector<int,std::allocator<int>>::vector(&v25, argv, v5);
std::vector<int,std::allocator<int>>::vector(&v26, argv, v6);
std::vector<int,std::allocator<int>>::vector(&v27, argv, v7);
for ( i = 0; i <= 15; ++i )
{
scanf("%d", &v30[4 * i], v20);
std::vector<int,std::allocator<int>>::push_back(&v24, &v30[4 * i]);
}
for ( j = 0; j <= 15; ++j )
{
LODWORD(v29) = fib(j);
std::vector<int,std::allocator<int>>::push_back(&v23, &v29);
}
std::vector<int,std::allocator<int>>::push_back(&v25, v30);
v8 = std::back_inserter<std::vector<int,std::allocator<int>>>(&v25);
end = std::vector<int,std::allocator<int>>::end(&v24);
v29 = std::vector<int,std::allocator<int>>::begin(&v24);
v10 = __gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator+(&v29, 1LL);
std::transform<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::back_insert_iterator<std::vector<int,std::allocator<int>>>,main::{lambda(int)#1}>(
v10,
end,
v8,
v30);
std::vector<int,std::allocator<int>>::vector(&v28, end, v11);
v12 = std::vector<int,std::allocator<int>>::end(&v25);
v13 = std::vector<int,std::allocator<int>>::begin(&v25);
std::accumulate<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::vector<int,std::allocator<int>>,main::{lambda(std::vector<int,std::allocator<int>>,int)#2}>(
(__int64)&v29,
v13,
v12,
(__int64)&v28,
v14,
v15,
v3);
std::vector<int,std::allocator<int>>::operator=(&v26, &v29);
std::vector<int,std::allocator<int>>::~vector(&v29);
std::vector<int,std::allocator<int>>::~vector(&v28);
if ( (unsigned __int8)std::operator!=<int,std::allocator<int>>(&v26, &v23) )
{
puts("You failed!");
exit(0);
}
std::back_inserter<std::vector<int,std::allocator<int>>>(&v27);
v16 = std::vector<int,std::allocator<int>>::end(&v24);
v17 = std::vector<int,std::allocator<int>>::begin(&v24);
std::copy_if<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::back_insert_iterator<std::vector<int,std::allocator<int>>>,main::{lambda(int)#3}>(v17);
puts("You win!");
printf("Your flag is:flag{", v16, v20);
v28 = std::vector<int,std::allocator<int>>::begin(&v27);
v29 = std::vector<int,std::allocator<int>>::end(&v27);
while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int,std::allocator<int>>>(&v28, &v29) )
{
v18 = (unsigned int *)__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator*(&v28);
std::ostream::operator<<(&std::cout, *v18);
__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator++(&v28);
}
putchar(125);
std::vector<int,std::allocator<int>>::~vector(&v27);
std::vector<int,std::allocator<int>>::~vector(&v26);
std::vector<int,std::allocator<int>>::~vector(&v25);
std::vector<int,std::allocator<int>>::~vector(&v24);
std::vector<int,std::allocator<int>>::~vector(&v23);
return 0;
}
思路
从上面的代码可以看出,程序基本使用的都是C++自带的库函数,像这种自带的库函数往往符合高内聚低耦合的编程思想,所以每个模块的功能会设计的尽可能简单。即使我们不是专业的C++编程人员,也可以通过动态调试来推测每个模块的功能。
核心代码
累加
v10 = __gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator+(&v29, 1LL);
std::transform<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::back_insert_iterator<std::vector<int,std::allocator<int>>>,main::{lambda(int)#1}>(
v10,
end,
v8,
v30);
这段代码的功能就是把我们输入的16个数,将第一个数累加到后面15个数上,然后得到新的vector,可以通过调试来进行验证该功能。
翻转数组
std::accumulate<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::vector<int,std::allocator<int>>,main::{lambda(std::vector<int,std::allocator<int>>,int)#2}>(
(__int64)&v29,
v13,
v12,
(__int64)&v28,
v14,
v15,
v3);
将新的vector进行首尾倒置,得到处理好的vector。
斐波那契数列
for ( j = 0; j <= 15; ++j )
{
LODWORD(v29) = fib(j);
std::vector<int,std::allocator<int>>::push_back(&v23, &v29);
}
生成16个斐波那契数列,并放在一个vector中。
验证
if ( (unsigned __int8)std::operator!=<int,std::allocator<int>>(&v26, &v23) )
{
puts("You failed!");
exit(0);
}
只要处理好的vector和生成的 有16个斐波那契数列的vector是相同的。那么就得到了flag。
脚本
由于上面的步骤是可逆的,所以将上面的步骤反过来进行一遍即可得到要输入的数据。
#! /usr/bin/python3
# -*- coding: utf-8 -*-
def fib(n):
if(n == 1):
return 1
elif(n == 2):
return 1
return fib(n-1) + fib(n-2)
# 生成16个斐波那契数列
inner_vector = [fib(i+1) for i in range(16)]
# 倒置
reversed_inner_vector = inner_vector[::-1]
key = []
first = reversed_inner_vector[0]
key += [first]
# 后面的15位和第一位相减
for i in range(1, len(reversed_inner_vector)):
key += [reversed_inner_vector[i] - first]
# 输出
output = ''
for v in key:
output += str(v) + ' '
print(output)
总结
编程思想真的很重要。