-
-
[原创]看雪 KCTF 2024 第四题 神秘信号 Writeup
-
发表于: 2024-8-22 11:23 4528
-
此题一看文件就应该是被打包了的PYTHON脚本,解题思路就是拦截PYC文件数据的字节码,并对其反编译,对编译出来的源码分析算法得到注册码.
1.抓取PYC:
用x64dbg加载main.exe,跑起来,等它加载python38.dll,之后在python38.dl中的PyMarshal_ReadObjectFromString下断,重新加载main.exe,再运行,就会在PyMarshal_ReadObjectFromString断下,这时rcx,rdx分别是PYC文件数据的地址和长度,逐一查看加载的被打包了的PYC文件,当数据中出现程序运行时的提示时串(Success, Fail等字符串)时就是主程序的PYC文件数据,就可以将这段PYC文件数据抓出,但这个数据是没有PYC文件头的,随便复制一个_internal\base_library.zip中的PYC文件的前0x10个字节(PYC文件头) 550D0D0A010000000000000000000000插入到抓出的数据前,再另存为main.pyc.这时抓取结束.
2.反编译main.pyc文件:
反编译时出错,不能生成py源码,好在文件比较小:
这时可以得到:
3.算法分析及求解:
由于程序比较简单,分析一下可以得到大致源码是这样的:
可以看到源码中对账号计算后的结果的长度有两种处理方式:
len(z)<20时key = "dZpKdrsiB6cndrGY" + z
否则为key = z[0:4] + ("dZpK") + z[4:8] + ("drsi") + z[8:12] + ("B6cn") + z[12:16] + ("drGY") + z[16:]
之后再对验证码用同账号一样的算法得到另一个z,再同key比较.
结合给出的一组注册码:
账号:D7C4197AF0806891
验证码:D7CHel419lo 7AFWor080ld!6891
对照以上分析的源码分析,这是用的第二种,可以看出CrackMe.main是将输入的串每3一个组来处理(若有余下不足3个的也一组),变成每4个一组. 常量串“dZpK”, ”drsi”, “B6cn”, “drGY” 分别对应的是 “Hel”, “lo “, “Wor”, “ld!”.及”dZpKdrsiB6cndrGY”对应”Hello World!”,而且对账号和验证码用的是同一算法再比较,所以其实就是将输入串和常量串”Hello World!” 3个一组变换得到验证码..根据分析可得到KeyGen代码:
最终得到:
KCTF
Hello World!KCTF
uncompyle6 main.pyc
uncompyle6 main.pyc
pydisasm main.pyc
pydisasm main.pyc
1
:
0
LOAD_CONST (
0
)
2
LOAD_CONST (
None
)
4
IMPORT_NAME (CrackMe)
6
STORE_NAME (CrackMe)
3
: >>
8
LOAD_NAME (
print
)
10
LOAD_CONST (
"(账号密码由字母大小写、数字、!、空格组成)"
)
12
CALL_FUNCTION (
1
positional argument)
14
POP_TOP
4
:
16
LOAD_NAME (
print
)
18
LOAD_CONST (
"请输入账号:"
)
20
CALL_FUNCTION (
1
positional argument)
22
POP_TOP
5
:
24
LOAD_NAME (
input
)
26
CALL_FUNCTION (
0
positional arguments)
28
STORE_NAME (h)
6
:
30
LOAD_NAME (CrackMe)
32
LOAD_METHOD (main)
34
LOAD_NAME (h)
36
CALL_METHOD (
1
positional argument)
38
STORE_NAME (z)
7
:
40
LOAD_NAME (
len
)
42
LOAD_NAME (z)
44
CALL_FUNCTION (
1
positional argument)
46
LOAD_CONST (
20
)
48
COMPARE_OP (<)
50
POP_JUMP_IF_FALSE (to
62
)
8
:
52
LOAD_CONST (
"dZpKdrsiB6cndrGY"
)
54
LOAD_NAME (z)
56
BINARY_ADD
58
STORE_NAME (key)
60
JUMP_FORWARD (to
138
)
10
: >>
62
LOAD_NAME (z)
64
LOAD_CONST (
0
)
66
LOAD_CONST (
4
)
68
BUILD_SLICE
2
70
BINARY_SUBSCR
72
LOAD_CONST (
"dZpK"
)
74
BINARY_ADD
76
LOAD_NAME (z)
78
LOAD_CONST (
4
)
80
LOAD_CONST (
8
)
82
BUILD_SLICE
2
84
BINARY_SUBSCR
86
BINARY_ADD
88
LOAD_CONST (
"drsi"
)
90
BINARY_ADD
92
LOAD_NAME (z)
94
LOAD_CONST (
8
)
96
LOAD_CONST (
12
)
98
BUILD_SLICE
2
100
BINARY_SUBSCR
102
BINARY_ADD
104
LOAD_CONST (
"B6cn"
)
106
BINARY_ADD
108
LOAD_NAME (z)
110
LOAD_CONST (
12
)
112
LOAD_CONST (
16
)
114
BUILD_SLICE
2
116
BINARY_SUBSCR
118
BINARY_ADD
120
LOAD_CONST (
"drGY"
)
122
BINARY_ADD
124
LOAD_NAME (z)
126
LOAD_CONST (
16
)
128
LOAD_CONST (
None
)
130
BUILD_SLICE
2
132
BINARY_SUBSCR
134
BINARY_ADD
136
STORE_NAME (key)
11
: >>
138
LOAD_NAME (
print
)
140
LOAD_CONST (
"请输入验证码:"
)
142
CALL_FUNCTION (
1
positional argument)
144
POP_TOP
12
:
146
LOAD_NAME (
input
)
148
CALL_FUNCTION (
0
positional arguments)
150
STORE_NAME (h)
13
:
152
LOAD_NAME (CrackMe)
154
LOAD_METHOD (main)
156
LOAD_NAME (h)
158
CALL_METHOD (
1
positional argument)
160
STORE_NAME (m)
14
:
162
LOAD_NAME (key)
164
LOAD_NAME (m)
166
COMPARE_OP (
=
=
)
168
POP_JUMP_IF_FALSE (to
182
)
15
:
170
LOAD_NAME (
print
)
172
LOAD_CONST (
"Success"
)
174
CALL_FUNCTION (
1
positional argument)
176
POP_TOP
16
:
178
JUMP_ABSOLUTE (to
194
)
180
JUMP_ABSOLUTE (to
8
)
18
: >>
182
LOAD_NAME (
print
)
184
LOAD_CONST (
"Fail"
)
186
CALL_FUNCTION (
1
positional argument)
188
POP_TOP
19
:
190
JUMP_ABSOLUTE (to
8
)
192
JUMP_ABSOLUTE (to
8
)
>>
194
LOAD_CONST (
None
)
196
RETURN_VALUE
1
:
0
LOAD_CONST (
0
)
2
LOAD_CONST (
None
)
4
IMPORT_NAME (CrackMe)
6
STORE_NAME (CrackMe)
3
: >>
8
LOAD_NAME (
print
)
10
LOAD_CONST (
"(账号密码由字母大小写、数字、!、空格组成)"
)
12
CALL_FUNCTION (
1
positional argument)
14
POP_TOP
4
:
16
LOAD_NAME (
print
)
18
LOAD_CONST (
"请输入账号:"
)
20
CALL_FUNCTION (
1
positional argument)
22
POP_TOP
5
:
24
LOAD_NAME (
input
)
26
CALL_FUNCTION (
0
positional arguments)
28
STORE_NAME (h)
6
:
30
LOAD_NAME (CrackMe)
32
LOAD_METHOD (main)
34
LOAD_NAME (h)
36
CALL_METHOD (
1
positional argument)
38
STORE_NAME (z)
7
:
40
LOAD_NAME (
len
)
42
LOAD_NAME (z)
44
CALL_FUNCTION (
1
positional argument)
46
LOAD_CONST (
20
)
48
COMPARE_OP (<)
50
POP_JUMP_IF_FALSE (to
62
)
8
:
52
LOAD_CONST (
"dZpKdrsiB6cndrGY"
)
54
LOAD_NAME (z)
56
BINARY_ADD
58
STORE_NAME (key)
60
JUMP_FORWARD (to
138
)
10
: >>
62
LOAD_NAME (z)
64
LOAD_CONST (
0
)
66
LOAD_CONST (
4
)
68
BUILD_SLICE
2
70
BINARY_SUBSCR
72
LOAD_CONST (
"dZpK"
)
74
BINARY_ADD
76
LOAD_NAME (z)
78
LOAD_CONST (
4
)
80
LOAD_CONST (
8
)
82
BUILD_SLICE
2
84
BINARY_SUBSCR
86
BINARY_ADD
88
LOAD_CONST (
"drsi"
)
90
BINARY_ADD
92
LOAD_NAME (z)
94
LOAD_CONST (
8
)
96
LOAD_CONST (
12
)
98
BUILD_SLICE
2
100
BINARY_SUBSCR
102
BINARY_ADD
104
LOAD_CONST (
"B6cn"
)
106
BINARY_ADD
108
LOAD_NAME (z)
110
LOAD_CONST (
12
)
112
LOAD_CONST (
16
)
114
BUILD_SLICE
2
116
BINARY_SUBSCR
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!