0x00 查壳

没有壳,发现是ELF文件,用IDA打开
0x01 IDA分析
直接看到main函数,总共就调用了init,type1,type2三个函数,也没有用户输入。所以放进虚拟机看看会输出什么

输出两个字符串,显而易见顺序不一样:

可以猜测的是type1和type2是两种不同的排序或者遍历方式。回到IDA再分析一下这三个函数:

这里对 x 字符数组有一个赋值操作,需要注意的是,这里每次保存一个值都要增加24字节的地址,说明x可能不是常见的char或者int类型,(盲猜是结构体),然后再将之前的值传到x里面的其他相对比较奇怪的位置(其他结构体?)。
exp1
这里的赋值循序也是奇奇怪怪,就不是顺序的,所以我想看一下。动调了下,看了下内存,然后有了惊人的发现。因为动调只能一个字符一个字符的查看,所以写了个exp来还原当时的调用顺序:
Index = [0x11E8,0x1260,0x10F8,0x1110,0x1140,0x1230,0x1158,0x1098,0x1200,0x1188,0x1170,0x11B8,0x10B0,0x1080,0x1218,0x1278,0x10E0,0x11A0,0x1128,0x12A8,0x11D0,0x1248,0x10C8]
s = 'I{_}Af2700ih_secTS2Et_wr'
for i in Index:
x = int((i-0x1080)/0x18)
print(s[x],end='')
#ctf2020{This_IS_A_7reE}
结果就是得到了flag。这里没有用到字符’w’,结合题目所以应该是wctf2020{This_IS_A_7reE}
然后这题就奇奇怪怪的结束了。哈哈哈哈哈哈哈哈哈哈红红火火恍恍惚惚。
回到IDA,还是继续看完这个题的其他部分:

第一时间我还真没看出来这是二叉树的中序和后续遍历,不过看明白后就好办了。根据二叉树的两种遍历可以知道另一张遍历(中序例外)。
exp2
#include <iostream>
#include <cstring>
using namespace std;
void preorder(string mid,string post,int len){
int tail = 0;
string mid1="";string post1="";
string mid2="";string post2="";
if(len)
printf("%c",post[len-1]);
if(len>1){
tail= mid.find(post[len-1]);
mid1=mid.substr(0,tail);
post1=post.substr(0,tail);
mid2=mid.substr(tail+1,len-1-tail);
post2=post.substr(tail,len-tail-1);//考虑分割后左右序列为空。
preorder(mid1, post1, mid1.length());
preorder(mid2, post2, mid2.length());
}
//find函数从左侧0索引开始,查找第一个出现的字符位置,如果查到,返回以0索引起始的位置;未查到,返回-1。
//start所需的子字符串的起始位置。字符串中的第一个字符的索引为 0。
//length在返回的子字符串中应包括的字符个数。
//s.substr(pos, n)返回一个string,包含s中从pos开始的n个字符的拷贝
}
int main() {
int len = 24;
string mid ="2f0t02T{hcsiI_SwA__r7Ee}\0";
string post="20f0Th{2tsIS_icArE}e7__w\0";
preorder(mid, post, len);
return 0;
}
运行得到flag:
