[re]反推树结构:2020网鼎杯朱雀组re tree wp

[re]反推树结构:2020网鼎杯朱雀组re tree wp

这道题感觉出题人放了一波水,隐藏了一个输出树的函数,导致发现了这个函数之后难度大幅降低,当然没有这个函数也可以解,但麻烦了很多!接下来分析题目:

题目分析

一道比较标准的逆向题,开局就输flag,一点不多BB:
在这里插入图片描述
逆向分析一下,主逻辑比较简单:
在这里插入图片描述
init里面是初始化,先把a-z26个字母放在一个结构体数组里:
在这里插入图片描述
然后用这个结构体数组生成了一个树结构:

具体生成算法不用太仔细研究,我当时也是看了好久,后来发现跟这个并没关系,后面介绍。

然后输入flag,进入chkflag函数:
在这里插入图片描述
这里将我们输入的flag里面的0-9,a-f也就是十六进制的数变成二进制,这也可以确定我们输入的flag长度是“flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}”这么长,42字节,并且由16进制数组成。然后将flag掐头去尾去掉“flag{”和“}”还有“-”之后的十六进制数转换成二进制数字符串。

接下来利用输入flag转换的二进制数和之前生成的二叉树结构进行寻路,0就是左子节点,1就是右子节点:
在这里插入图片描述
把找到的东西和“zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx”这个字符串进行比较,成功则通过。

解题

根据分析可知,这道题的关键是数结构,生成数结构的算法说实话还是比较复杂(虽然没几行),但从内存中直接分析又太麻烦,写脚本把脱出来的内存分析出树结构也比较麻烦。直到看到了有一个函数,静静的躺在函数列表,没有被调用,很孤独,很寂寞:
在这里插入图片描述
反编译看一下:
在这里插入图片描述
这特么不就是遍历输出树结构吗,但这个函数并没有被调用:
在这里插入图片描述
但我们可以调用,将程序patch一下,将原本调用parse的地方patch成调用outtree:
在这里插入图片描述
patch成:
在这里插入图片描述
直接用patch里的Assemble即可,然后把函数名替换一下就行,不用改机器码:
在这里插入图片描述
然后执行一下:
在这里插入图片描述
输出的内容:

50:left :48 ,right : 49
48:left :44 ,right : 45
44:left :38 ,right : 39
38:left :24 ,right : 33
24: char:y
33:left :1 ,right : 16
1: char:b
16: char:q
39:left :6 ,right : 5
6: char:g
5: char:f
45:left :9 ,right : 40
9: char:j
40:left :34 ,right : 35
34:left :22 ,right : 15
22: char:w
15: char:p
35:left :30 ,right : 10
30:left :23 ,right : 28
23: char:x
28:left :3 ,right : 8
3: char:d
8: char:i
10: char:k
49:left :46 ,right : 47
46:left :18 ,right : 41
18: char:s
41:left :25 ,right : 13
25: char:z
13: char:n
47:left :42 ,right : 43
42:left :36 ,right : 7
36:left :2 ,right : 31
2: char:c
31:left :19 ,right : 4
19: char:t
4: char:e
7: char:h
43:left :37 ,right : 21
37:left :14 ,right : 32
14: char:o
32:left :29 ,right : 12
29:left :11 ,right : 27
11: char:l
27:left :20 ,right : 26
20: char:u
26:left :17 ,right : 0
17: char:r
0: char:a
12: char:m
21: char:v

树结构就是这么个东西。

然后我们把每个字母的路线整理出来,还原一下就行了,但不用都整理。“zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx”这个字符串中只有“zvjyosgnkbpdmx"这几个字母,通过树反推(手工就行)出路线是:

z:1010
v:1111
j:010
y:0000
o:11100
s:100
g:0010
n:1011
k:01111
b:00010
p:01101
d:0111010
m:111011
x:011100

鉴于有小同学细聊问我怎么根据字母反推会二叉树的路线,这里简单说一下,如果实在不会反着推这个路线,那就根据这个输出结果把图画出来,大概是这样的:
在这里插入图片描述
以途中的字母b作为例子,从b触发,往回走走到根就是路线,左子节点是0又子节点是1,所以b的路线就是00010。

然后写个代码复原一下flag:

tree={
"z":"1010",
"v":"1111",
"j":"010",
"y":"0000",
"o":"11100",
"s":"100",
"g":"0010",
"n":"1011",
"k":"01111",
"b":"00010",
"p":"01101",
"d":"0111010",
"m":"111011",
"x":"011100"}
result="zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx"
flag=""
for i in result:
    flag+=tree[i]
flag1=""
i=0
while i<len(flag):
    flag1+=hex(int(flag[i:i+8],2))[2:]
    i+=8
print "flag{"+flag1[0:8]+'-'+flag1[8:12]+'-'+flag1[12:16]+'-'+flag1[16:20]+'-'+flag1[20:32]+'}'

在这里插入图片描述
然后成功:
在这里插入图片描述

附录

修改的结构体(没啥用):
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章