-
-
[原创] 看雪 2022 KCTF 秋季赛 第三题 水患猖獗
-
发表于: 2022-11-21 01:51 11644
-
VMP是当下最强的代码混淆,它的强度已无需再验证,而且目前并不存在成熟的开源的自动化的脱壳工具。
然而,很多恶意软件也采用了类似的代码混淆,这为安全研究人员分析恶意软件带来了巨大的困难,因此一个通用的自动化去混淆工具意义非凡。有一些探索性的研究项目,例如 VMProtect Devirtualization 和 SATURN - Software Deobfuscation Framework Based On LLVM 等,但是距离成熟的工具还有很大的距离。
如果不考虑副作用,那么代码逻辑本质是接受输入,对输入做计算和变换,最后输出结果,与数学上的函数并无二致。VMP保护虽然把控制流变得面目全非,但数据流作为运算逻辑的本质仍然是贯穿于程序中的(当然也有很多针对数据流的混淆(如不透明谓词、MBA等),但与控制流还是相对独立的),因为无论代码如何混淆,原始程序的逻辑是不能被改变的。
最擅长数据流分析的工具是编译器。目前很多去混淆通用工具的研究项目,核心思想还是设法把被混淆的程序提升为 LLVM IR,然后利用编译器强大的数据流优化能力(主要是常量传播、活跃分析、死代码消除等)剥离大部分与核心逻辑无关的垃圾指令,同时引入SMT求解器处理某些数据流混淆。
不久前才刚知道SATURN这篇论文,感觉可行性是最高的,文章对设计思路的描述也相当详细,只可惜作者没有开源。
(计算机行业的技术整体上还是开放共享的,SATURN论文虽然没有开源,但是可以相信一定有人会按照论文的思路实现这个项目(例如当年Google提出了MapReduce但没有开源,于是有了后来的Hadoop)。另外如果某个技术成熟了,尽管会有一些人做闭源商业化创收,但一定也会有另一些人做开源共享(例如IDA是最强的反编译器,它是商业化的,而开源界也有Ghidra,虽然效果差了一些,但总是有的)(这是计算机行业的整体技术氛围,应该说目前互联网的很多基础设施都依赖于一些基础的开源项目,所以真正投入开源的人是最值得尊重的(开源困境:Log4j2 维护者发声:没有工资,还要挨骂!!))
但是把代码混淆作为CTF题目考点来出的话,如果没有较为成熟的开源项目可以利用,个人感觉对攻击方是有些为难的。因为CTF的初衷是Hack for FUN,其次是技术交流。硬刚VMP的过程往往不太FUN,而从技术分享的角度看,此题的混淆强度4天时间如果从零开始写自动化工具基本也不大可能。
当然,防守方也许会考虑到攻击方有自己的私藏武器。但是如果思考一下这个问题可以发现,如果以SATURN论文的工作量作为参考,可以想象实现这样一个去混淆框架至少要全力投入数月(甚至考虑前期对VMProtect的逆向分析,时间周期会更长),经过不断的迭代才能有一些初步的效果,可能只有本职工作在此的人才能有足够的精力投入其中;而且,即使有了这样的工具,用来解题肯定也要做针对性适配,而这又是一个深坑:单凭一道题目搞清楚代码混淆方式就要花费大量时间,何况还要修改原有的工具,再重新测试,4天时间恐怕也不太现实。另外,考虑到计算机行业的技术开放程度,虽然业界最强的工具不一定开源,但基本上开源界总会有相同功能的工具,而且至少可以做到能用的程度(可以对比IDA和Ghidra)。但是现在似乎还没有发现高调售卖的商业化VMP去混淆工具,而且现有的几个开源的VMP去混淆工具效果还不是非常好。不过,随着时间发展,还有能够相信未来会出现成熟的工具的。
(其他CTF比赛也出现过以代码混淆作为考点的题目,不过题目为了考虑时限内的可解性(而不是为了单纯测试混淆的强度是否足够高到无人能解;如果真是这样的目的就应该搞付费悬赏,和SRC平台一样),强度往往被有意降低,重点在于展示思路,于是很好的兼顾了难度和技术交流)
不妨回顾下近几届KCTF所有以代码混淆为主要考点的题目,似乎没有一个人是真的靠自己写的自动化去混淆工具还原出原始逻辑进而解出题目的,基本上都是靠动态调试、trace跟踪、人为观察等方式,靠堆体力找出逻辑,而且,也没有任意一个出题人公开自己写的自动化去混淆工具,这样无论攻击方还是防守方,从技术交流的角度总感觉缺少了一点灵魂(p.s. 不过很多基于动态调试的解题方法也非常硬核而且能学到很多知识)。而且这种工具对安全行业具有颠覆性的意义,即使闭源高价售卖也是有巨大市场的)(此外,回想自己作为某比赛出题人时,负责人给的硬性要求就是必须自己以做题人的视角解一遍确保可解性和做题体验,而且对于代码混淆的使用有严格的限制,必须保证自己有合理的解法(比如,有成熟工具可利用,或者从零开始能在赛期内写出工具,或者有足够的线索提示能够完全绕开混淆);而且到最后往往会发现,某些题目即使开源给做题者都不会降低难度)
所以,基于以上推理,只能合理假设既然用了VMP来出题,那么就默认了出题人是希望攻击方寻找捷径,而不是硬刚代码混淆,因为对于本题的混淆强度从零开始的话4天的时间基本上不可能写出自动化的工具。
回到本题,对本人来说正常做是不可能做出来了,也只能想一想其他的路。
根据公开的serial可知合法的serial长64字节,每个字符取值[0-9A-F],实际上hexdecode后是32字节。
jadx逆向apk,发现java层什么都没有,只是把name和serial都传给so然后接受一个字符串并显示出来。
Android Studio 开一台 arm 架构的虚拟机,x64dbg 调试 qemu-system-armel.exe
输入正确的serial会提示"祝贺,闯关顺利",输入错误的serial会提示"不对!再探再报",而且从java层看到这两个字符串都是so返回的。
把这两个字符串utf8编码,在x64dbg里全内存搜索,只能找到一片内存。
保持name不变,改变输入的serial,观察附近内存的变换,发现以下区域:
观察到 0x2892A9CE580 处的 02 EB 会随着 serial 的变化而变化,而且错误的 serial 在此处的值都小于 0xEB02。
固定 name 为 KCTF,逐字节改变输入。每个字节有 16 种取值,找出使得 0x2892A9CE580 处的值最大的那种即为正确的输入。
剩下的就是体力活了,下面是花几个小时手动搞出来的表:
(做完才发现,其实每个字节尝试 1、2、4、8 四种情况就够了。如果某种情况使得 0x2892A9CE580 的值比输入取 0 时大,就加上这个值,否则不加)
(另外自动化也是有可能的:通过 adb shell input 控制输入,ReadProcessMemory 读取内存;但是评估了下手动的工作量,感觉几个小时能搞完,所以还是手动搞的)
(以及,第一次动手发现 Windows 上通过 ReadProcessMemory 读其他进程的内存竟然不需要权限。细思恐极,Windows上的恶意软件是不是随便读其他进程内存获取密码等敏感数据?)
题目的最终答案:
(p.s. 关于动态调试,这两天才知道内核的 eBPF uprobe 机制(从Linux 3.5就存在了)。通过这个机制可以跟踪用户态程序、在任意地址处停下、dump寄存器等(原理也是插入int 3指令,但不走ptrace(?),应对反调试估计很有效),值得发掘)
P.S. 发帖时竟然提示涉黄,要人工审核?好想知道是哪个词触发的问题,自己完全看不出来。
000002892A9CE570
00
00
00
00
00
00
00
00
13
00
00
00
AB
00
00
00
............«...
000002892A9CE580
02
EB FF FF A9
15
00
00
E7
97
8C
92
84
96
8C
92
.ëÿÿ©...ç.......
000002892A9CE590
E8
96
8C
92
50
00
00
00
23
00
00
00
10
C1
7B
A2 è...P...
#....Á{¢
000002892A9CE5A0
EE DF DE
0E
B8 CB
7B
A2
00
00
00
00
1C
96
8C
92
îßÞ.¸Ë{¢........
000002892A9CE5B0
15
FC
7D
A2
9D
60
7C
A2 D4 FF
7D
A2
00
00
00
00
.ü}¢.`|¢Ôÿ}¢....
000002892A9CE5C0
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
................
000002892A9CE5D0
00
00
00
00
00
00
00
00
00
00
00
00
2C
3F
7C
A2 ............,?|¢
000002892A9CE5E0
01
00
00
00
E8
96
8C
92
E7
97
8C
92
23
C1
7B
A2 ....è...ç...
#Á{¢
000002892A9CE5F0
E7
97
8C
92
00
00
00
00
E8
96
8C
92
50
00
00
00
ç.......è...P...
000002892A9CE600
FC
56
00
00
00
30
7B
A2 FC
86
7B
A2
23
00
00
00
üV...
0
{¢ü.{¢
#...
000002892A9CE610
E8
96
8C
92
04
00
00
00
79
3F
7C
A2 FC
86
7B
A2 è.......y?|¢ü.{¢
000002892A9CE620
20
00
00
00
84
96
8C
92
5C
96
8C
92
49
49
7B
A2 .......\...II{¢
000002892A9CE630
A9
15
00
00
00
00
00
00
00
00
00
00
20
0A
00
00
©........... ...
000002892A9CE640
22
00
00
00
30
00
00
00
EF FE DD
00
30
C1
7B
A2 "...
0.
..ïþÝ.
0
Á{¢
000002892A9CE570
00
00
00
00
00
00
00
00
13
00
00
00
AB
00
00
00
............«...
000002892A9CE580
02
EB FF FF A9
15
00
00
E7
97
8C
92
84
96
8C
92
.ëÿÿ©...ç.......
000002892A9CE590
E8
96
8C
92
50
00
00
00
23
00
00
00
10
C1
7B
A2 è...P...
#....Á{¢
000002892A9CE5A0
EE DF DE
0E
B8 CB
7B
A2
00
00
00
00
1C
96
8C
92
îßÞ.¸Ë{¢........
000002892A9CE5B0
15
FC
7D
A2
9D
60
7C
A2 D4 FF
7D
A2
00
00
00
00
.ü}¢.`|¢Ôÿ}¢....
000002892A9CE5C0
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
................
000002892A9CE5D0
00
00
00
00
00
00
00
00
00
00
00
00
2C
3F
7C
A2 ............,?|¢
000002892A9CE5E0
01
00
00
00
E8
96
8C
92
E7
97
8C
92
23
C1
7B
A2 ....è...ç...
#Á{¢
000002892A9CE5F0
E7
97
8C
92
00
00
00
00
E8
96
8C
92
50
00
00
00
ç.......è...P...
000002892A9CE600
FC
56
00
00
00
30
7B
A2 FC
86
7B
A2
23
00
00
00
üV...
0
{¢ü.{¢
#...
000002892A9CE610
E8
96
8C
92
04
00
00
00
79
3F
7C
A2 FC
86
7B
A2 è.......y?|¢ü.{¢
000002892A9CE620
20
00
00
00
84
96
8C
92
5C
96
8C
92
49
49
7B
A2 .......\...II{¢
000002892A9CE630
A9
15
00
00
00
00
00
00
00
00
00
00
20
0A
00
00
©........... ...
000002892A9CE640
22
00
00
00
30
00
00
00
EF FE DD
00
30
C1
7B
A2 "...
0.
..ïþÝ.
0
Á{¢
(初始serial是
64
个
0
;行标头表示改变serial的第几位,列标头表示改变为哪个值)
0
1
2
3
4
5
6
7
8
9
A B C D E F
0
DB86 DB76 DB66 DB56 DBC6 DBB6 DBA6 DB96 DB06 DAF6 DAE6 DAD6 DB46 DB36 DB26 DB16
1
DB86 DB85 DB88 DB87 DB82 DB81 DB84 DB83 DB7E DB7D DB80 DB7F DB7A DB79 DB7C DB7B
2
DB86 DB76 DBA6 DB96 DB46 DB36 DB66 DB56 DC06 DBF6 DC26 DC16 DBC6 DBB6 DBE6 DBD6
3
86
85
84
83
8A
89
88
87
7E
7D
7C
7B
82
81
80
7F
4
B8 B7 BA B9 BC BB BE BD C0 BF C2 C1 C4 C3 C6 C5
5
86
85
84
83
8A
89
88
87
8E
8D
8C
8B
92
91
90
8F
6
B8 B7 BA B9 B4 B3 B6 B5 C0 BF C2 C1 BC BB BE BD
7
86
85
84
83
82
81
80
7F
7E
7D
7C
7B
7A
79
78
77
42A4ECA0
/
/
这是使得
0x2892A9CE580
取值最大的输入
(BD5B135F)
/
/
这是使得
0x2892A9CE580
取值最小的输入
0
1
2
3
4
5
6
7
8
9
A B C D E F
8
B8 B7 BA B9 BC BB BE BD B0 AF B2 B1 B4 B3 B6 B5
9
86
87
88
89
8A
8B
8C
8D
7E
7F
80
81
82
83
84
85
10
B8 B9 BC C0 C4 C7
11
86
8A
8B
89
7E
7C
82
12
B8 B7 B6 B5 BC B9 B0 AD B4 B1
13
86
82
7E
7A
77
14
B8 BC BF B0 B3 B4
15
86
8A
89
7E
7D
7C
7B
82
67F54074
(
980ABF8B
)
0
1
2
3
4
5
6
7
8
9
A B C D E F
16
B8 B5 BC C0 C4
17
86
89
82
7E
81
7A
7D
18
B8 B7 B9 BC C0 C4 C3 C6 C5
19
86
82
83
84
8E
8F
91
8A
20
B8 B7 BA B5 B0 AC AB AD
21
86
89
8A
8E
92
95
22
B8 B9 B7 B4 B0 B1 AE AC AD AA
23
86
8A
8D
7E
C3EB2F17
(
3C14D0E8
)
0
1
2
3
4
5
6
7
8
9
A B C D E F
24
B8 BC BF B0 B4
25
86
82
81
83
8E
90
8A
26
B8 B5 C0 C4 C1
27
86
82
83
8E
90
91
8A
28
B8 B4 B0 AC A9
29
86
8A
89
8C
8B
7E
7D
30
B8 BB BC C0 C4 C5 C6 C7
31
86
85
89
90
91
94
93
7ACB06FE
(
8534F901
)
0
1
2
3
4
5
6
7
8
9
A B C D E F
32
B8 B9 B5 B2 B3 AE AA AB
33
86
87
89
83
80
7A
7C
7D
34
B8 BD BF B0 B2 B7
35
86
83
80
8F
8C
89
36
B8 B3 AE A9
37
86
8B
7C
38
B8 BD AE B3
39
86
84
83
89
8C
92
8F
1379055C
(EC86FAA3)
0
1
2
3
4
5
6
7
8
9
A B C D E F
40
B8 B6 BD BE C5 C3
41
86
8A
89
88
7C
7B
7F
42
B8 BD C2 C7
43
86
82
83
85
90
91
8D
44
B8 BA B3 B2 AC AB AD
45
86
88
81
80
79
7B
46
B8 B9 B5 AE AA AB
47
86
87
83
7C
78
79
D4FB2211
0
1
2
3
4
5
6
7
8
9
A B C D E F
48
B8 B5 BB BE C4 C2 C1
49
86
89
83
80
7A
7D
50
B8 B4 B5 C2 C3 BF
51
86
84
8B
8C
93
91
52
B8 B3 B1 C0 BE B9
53
86
8B
8D
7E
80
85
54
B8 BC BB B0 AE AD B1
55
86
8B
90
92
95
C3BD874F
0
1
2
3
4
5
6
7
8
9
A B C D E F
56
B8 B3 C2
57
86
84
8B
8C
93
91
58
B8 B4 B5 B2 C1 BE BF BB
59
86
85
88
89
8D
90
94
93
60
B8 B9 B6 B5 AE AA AB
61
86
81
7C
77
62
B8 B9 B5 AE AA AB
63
86
84
8B
8C
93
91
AD9E101D
(初始serial是
64
个
0
;行标头表示改变serial的第几位,列标头表示改变为哪个值)
0
1
2
3
4
5
6
7
8
9
A B C D E F
0
DB86 DB76 DB66 DB56 DBC6 DBB6 DBA6 DB96 DB06 DAF6 DAE6 DAD6 DB46 DB36 DB26 DB16
1
DB86 DB85 DB88 DB87 DB82 DB81 DB84 DB83 DB7E DB7D DB80 DB7F DB7A DB79 DB7C DB7B
2
DB86 DB76 DBA6 DB96 DB46 DB36 DB66 DB56 DC06 DBF6 DC26 DC16 DBC6 DBB6 DBE6 DBD6
3
86
85
84
83
8A
89
88
87
7E
7D
7C
7B
82
81
80
7F
4
B8 B7 BA B9 BC BB BE BD C0 BF C2 C1 C4 C3 C6 C5
5
86
85
84
83
8A
89
88
87
8E
8D
8C
8B
92
91
90
8F
6
B8 B7 BA B9 B4 B3 B6 B5 C0 BF C2 C1 BC BB BE BD
7
86
85
84
83
82
81
80
7F
7E
7D
7C
7B
7A
79
78
77
42A4ECA0
/
/
这是使得
0x2892A9CE580
取值最大的输入
(BD5B135F)
/
/
这是使得
0x2892A9CE580
取值最小的输入
0
1
2
3
4
5
6
7
8
9
A B C D E F
8
B8 B7 BA B9 BC BB BE BD B0 AF B2 B1 B4 B3 B6 B5
9
86
87
88
89
8A
8B
8C
8D
7E
7F
80
81
82
83
84
85
10
B8 B9 BC C0 C4 C7
11
86
8A
8B
89
7E
7C
82
12
B8 B7 B6 B5 BC B9 B0 AD B4 B1
13
86
82
7E
7A
77
14
B8 BC BF B0 B3 B4
15
86
8A
89
7E
7D
7C
7B
82
67F54074
(
980ABF8B
)
0
1
2
3
4
5
6
7
8
9
A B C D E F
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)