题目链接https://pan.baidu.com/s/1Rq4lJmANHSL1EKk8AZxqDw?pwd=0422

下载下来是一个txt文件,直接人工逆向分析。

基础知识详见文章python逆向

初始化及flag判断

image-20231120094102877

前面容易看出初始化了三个列表arr0、arr1和arr2,python版本为2.7

1
2
3
arr0 = [249, 91, 149, 113, 16, 91, 53, 41]
arr1 = [43, 1, 6, 69, 20, 62, 6, 44, 24, 113, 6, 35, 0, 3, 6, 44, 20, 22, 127, 60]
arr2 = [90, 100, 87, 109, 86, 108, 86, 105, 90, 104, 88, 102]

image-20231120100451027

先声明四个check函数,然后是校验flag。由于每一次返回FALSE都是跳转到239偏移地址,flag错误。因此可以判断出四个check间是&的关系。

1
2
3
4
5
6
flag = input()
if check0(flag) & check1(flag) & check2(flag) & check3(flag):
print('ok')
else:
print('no')

check0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# check0 line 5 of game.py

6 0 LOAD_GLOBAL 0 'all'
3 LOAD_GENEXPR '<code_object <genexpr>>'
6 MAKE_FUNCTION_0 0 None
9 LOAD_FAST 0 's'
12 GET_ITER
13 CALL_FUNCTION_1 1 None
16 CALL_FUNCTION_1 1 None
19 RETURN_VALUE
# <genexpr> line 6 of game.py

6 0 LOAD_FAST 0 '.0'
3 FOR_ITER 32 'to 38'
6 STORE_FAST 1 'x'
9 LOAD_GLOBAL 0 'ord'
12 LOAD_FAST 1 'x'
15 CALL_FUNCTION_1 1 None
18 LOAD_GLOBAL 1 'range'
21 LOAD_CONST 32
24 LOAD_CONST 128
27 CALL_FUNCTION_2 2 None
30 COMPARE_OP 6 in
33 YIELD_VALUE
34 POP_TOP
35 JUMP_BACK 3 'to 3'
38 LOAD_CONST None
41 RETURN_VALUE

创建一个生成器,对输入字符进行判断,输入字符ascii码范围为32~128

all() 函数接受一个可迭代对象为参数,仅当可迭代对象中的所有项的计算结果为 True,或可迭代对象为空时才返回 True

1
2
3
4

def check0(s):
return all(ord(x) in range(32, 128) for x in s)

check1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# check1 line 8 of game.py

9 0 LOAD_GLOBAL 0 'len'
3 LOAD_FAST 0 's'
6 CALL_FUNCTION_1 1 None
9 LOAD_CONST 100
12 COMPARE_OP 0 <
15 POP_JUMP_IF_FALSE 58 'to 58'
18 LOAD_GLOBAL 0 'len'
21 LOAD_FAST 0 's'
24 CALL_FUNCTION_1 1 None
27 LOAD_GLOBAL 0 'len'
30 LOAD_FAST 0 's'
33 CALL_FUNCTION_1 1 None
36 BINARY_MULTIPLY
37 LOAD_CONST 777
40 BINARY_MODULO
41 LOAD_CONST 233
44 BINARY_XOR
45 LOAD_CONST 513
48 COMPARE_OP 2 ==
51_0 COME_FROM 15 '15'
51 POP_JUMP_IF_FALSE 58 'to 58'

10 54 LOAD_GLOBAL 1 'True'
57 RETURN_END_IF
58_0 COME_FROM 51 '51'

12 58 LOAD_GLOBAL 2 'False'
61 RETURN_VALUE
62 LOAD_CONST None
65 RETURN_VALUE

1
2
3
4
5
6
7
8

def check1(s):
if len(s) < 100 and (((len(s) * len(s)) % 777) ^ 233 == 513):
#and 是逻辑与操作符。它用于连接两个布尔表达式,并在两者都为 True 时返回 True,否则返回 False。
#& 是按位与操作符。它用于对两个整数的每一位进行与运算。
return True
else:
return False
1
2
3
4
5
6
7
8
9
10
11
#check1
from math import *
for i in range(100):
len_s = sqrt(744+777*i) #744=513^233
if (len_s%1) == 0 and len_s < 100:
print(len_s)

for x in range(100):
if x<100 and (x*x)%777^233 == 513:
print(x)
#得出字符串长度为39 两种破解方法

check2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# check2 line 14 of game.py

15 0 LOAD_GLOBAL 0 'ord'
3 LOAD_FAST 0 's'
6 LOAD_CONST 0
9 BINARY_SUBSCR
10 CALL_FUNCTION_1 1 None
13 LOAD_CONST 128
16 BINARY_MULTIPLY
17 LOAD_GLOBAL 0 'ord'
20 LOAD_FAST 0 's'
23 LOAD_CONST 1
26 BINARY_SUBSCR
27 CALL_FUNCTION_1 1 None
30 BINARY_ADD
31 LOAD_CONST 128
34 BINARY_MULTIPLY
35 LOAD_GLOBAL 0 'ord'
38 LOAD_FAST 0 's'
41 LOAD_CONST 2
44 BINARY_SUBSCR
45 CALL_FUNCTION_1 1 None
48 BINARY_ADD
49 LOAD_CONST 128
52 BINARY_MULTIPLY
53 LOAD_GLOBAL 0 'ord'
56 LOAD_FAST 0 's'
59 LOAD_CONST 3
62 BINARY_SUBSCR
63 CALL_FUNCTION_1 1 None
66 BINARY_ADD
67 LOAD_CONST 128
70 BINARY_MULTIPLY
71 LOAD_GLOBAL 0 'ord'
74 LOAD_FAST 0 's'
77 LOAD_CONST 4
80 BINARY_SUBSCR
81 CALL_FUNCTION_1 1 None
84 BINARY_ADD
85 LOAD_CONST 128
88 BINARY_MULTIPLY
89 LOAD_GLOBAL 0 'ord'
92 LOAD_FAST 0 's'
95 LOAD_CONST 5
98 BINARY_SUBSCR
99 CALL_FUNCTION_1 1 None
102 BINARY_ADD
103 LOAD_CONST 3533889469877L
106 COMPARE_OP 2 ==
109 POP_JUMP_IF_FALSE 138 'to 138'
112 LOAD_GLOBAL 0 'ord'
115 LOAD_FAST 0 's'
118 LOAD_CONST -1
121 BINARY_SUBSCR
122 CALL_FUNCTION_1 1 None
125 LOAD_CONST 125
128 COMPARE_OP 2 ==
131_0 COME_FROM 109 '109'
131 POP_JUMP_IF_FALSE 138 'to 138'

16 134 LOAD_GLOBAL 1 'True'
137 RETURN_END_IF
138_0 COME_FROM 131 '131'

18 138 LOAD_GLOBAL 2 'False'
141 RETURN_VALUE
142 LOAD_CONST None
145 RETURN_VALUE
1
2
3
4
5
def check2(s):
if (((((ord(s[0]) * 128 + ord(s[1])) * 128 + ord(s[2])) * 128 + ord(s[3])) * 128 + ord(s[4])) * 128 + ord(s[5]) == 3533889469877) and (ord(s[-1]) == 125):
return True
else:
return False
1
2
3
4
5
6
7
8
9
#check2
s = 3533889469877
for x in range (6):
ch =chr(s%128)
flag[5-x]= ch
s=s//128
flag[-1]='}'
#前面限定了字符的范围为32-128。
print(flag)

check 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

# check3 line 20 of game.py

21 0 LOAD_GLOBAL 0 'map'
3 LOAD_GLOBAL 1 'ord'
6 LOAD_FAST 0 's'
9 CALL_FUNCTION_2 2 None
12 STORE_FAST 1 'arr'

22 15 LOAD_FAST 1 'arr'
18 LOAD_CONST 6
21 LOAD_CONST 30
24 LOAD_CONST 3
27 BUILD_SLICE_3 3
30 BINARY_SUBSCR
31 STORE_FAST 2 'a'

23 34 SETUP_LOOP 62 'to 99'
37 LOAD_GLOBAL 2 'range'
40 LOAD_GLOBAL 3 'len'
43 LOAD_FAST 2 'a'
46 CALL_FUNCTION_1 1 None
49 CALL_FUNCTION_1 1 None
52 GET_ITER
53 FOR_ITER 42 'to 98'
56 STORE_FAST 3 'i'

24 59 LOAD_FAST 2 'a'
62 LOAD_FAST 3 'i'
65 BINARY_SUBSCR
66 LOAD_CONST 17684
69 BINARY_MULTIPLY
70 LOAD_CONST 372511
73 BINARY_ADD
74 LOAD_CONST 257
77 BINARY_MODULO
78 LOAD_GLOBAL 4 'arr0'
81 LOAD_FAST 3 'i'
84 BINARY_SUBSCR
85 COMPARE_OP 3 !=
88 POP_JUMP_IF_FALSE 53 'to 53'

25 91 LOAD_GLOBAL 5 'False'
94 RETURN_END_IF
95_0 COME_FROM 88 '88'
95 JUMP_BACK 53 'to 53'
98 POP_BLOCK
99_0 COME_FROM 34 '34'

26 99 LOAD_FAST 1 'arr'
102 LOAD_CONST -2
105 LOAD_CONST 33
108 LOAD_CONST -1
111 BUILD_SLICE_3 3
114 BINARY_SUBSCR
115 LOAD_CONST 5
118 BINARY_MULTIPLY
119 STORE_FAST 4 'b'

27 122 LOAD_GLOBAL 0 'map'
125 LOAD_LAMBDA '<code_object <lambda>>'
128 MAKE_FUNCTION_0 0 None
131 LOAD_GLOBAL 6 'zip'
134 LOAD_FAST 4 'b'
137 LOAD_FAST 1 'arr'
140 LOAD_CONST 7
143 LOAD_CONST 27
146 SLICE+3
147 CALL_FUNCTION_2 2 None
150 CALL_FUNCTION_2 2 None
153 STORE_FAST 5 'c'

28 156 LOAD_FAST 5 'c'
159 LOAD_GLOBAL 7 'arr1'
162 COMPARE_OP 3 !=
165 POP_JUMP_IF_FALSE 172 'to 172'

29 168 LOAD_GLOBAL 5 'False'
171 RETURN_END_IF
172_0 COME_FROM 165 '165'

30 172 LOAD_CONST 0
175 STORE_FAST 6 'p'

31 178 SETUP_LOOP 105 'to 286'
181 LOAD_GLOBAL 2 'range'
184 LOAD_CONST 28
187 LOAD_CONST 34
190 CALL_FUNCTION_2 2 None
193 GET_ITER
194 FOR_ITER 88 'to 285'
197 STORE_FAST 3 'i'

32 200 LOAD_FAST 1 'arr'
203 LOAD_FAST 3 'i'
206 BINARY_SUBSCR
207 LOAD_CONST 107
210 BINARY_ADD
211 LOAD_CONST 16
214 BINARY_DIVIDE
215 LOAD_CONST 77
218 BINARY_ADD
219 LOAD_GLOBAL 8 'arr2'
222 LOAD_FAST 6 'p'
225 BINARY_SUBSCR
226 COMPARE_OP 3 !=
229 POP_JUMP_IF_TRUE 268 'to 268'
232 LOAD_FAST 1 'arr'
235 LOAD_FAST 3 'i'
238 BINARY_SUBSCR
239 LOAD_CONST 117
242 BINARY_ADD
243 LOAD_CONST 16
246 BINARY_MODULO
247 LOAD_CONST 99
250 BINARY_ADD
251 LOAD_GLOBAL 8 'arr2'
254 LOAD_FAST 6 'p'
257 LOAD_CONST 1
260 BINARY_ADD
261 BINARY_SUBSCR
262 COMPARE_OP 3 !=
265_0 COME_FROM 229 '229'
265 POP_JUMP_IF_FALSE 272 'to 272'

33 268 LOAD_GLOBAL 9 'false'
271 RETURN_END_IF
272_0 COME_FROM 265 '265'

34 272 LOAD_FAST 6 'p'
275 LOAD_CONST 2
278 INPLACE_ADD
279 STORE_FAST 6 'p'
282 JUMP_BACK 194 'to 194'
285 POP_BLOCK
286_0 COME_FROM 178 '178'

35 286 LOAD_GLOBAL 10 'True'
289 RETURN_VALUE
# <lambda> line 27 of game.py

27 0 LOAD_FAST 0 'x'
3 LOAD_CONST 0
6 BINARY_SUBSCR
7 LOAD_FAST 0 'x'
10 LOAD_CONST 1
13 BINARY_SUBSCR
14 BINARY_XOR
15 RETURN_VALUE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def check3(s):
arr=map(ord,s)
#map(function, iterable, ...) function -- 函数 iterable -- 一个或多个序列
#Python 2 返回列表。 Python 3 返回迭代器。
a=arr[6:30:3]
for i in range (len(a)):
if (a[i]*17684+372511)%257 != arr0[i]:
return False

b=arr[-2:33:-1]*5 #[37, 36, 35, 34],*5表示将切片内容重复五遍
c= map(lambda:b[0]^b[1],zip(b, arr[7:27]) )
if c!= arr1:
return False
#zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
p = 0
for i in range(28,34):
if((arr[i]+107)//16)+77!= arr2[p] or ((arr[i]+177)%16)+99 != arr2[p+1]:
return False
p=p+2
#Python 2 返回元组列表。 Python 3 返回一个对象


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#check3
#slice[start:stop:step]切片获取子序列 包含start,不包含stop
arr0 = [249, 91, 149, 113, 16, 91, 53, 41]
for i in range(8):
for ch in range (32,128):
if (ch*17684+372511)%257 == arr0[i]:
flag[6+i*3]=chr(ch)
print(flag)


arr1 = [43, 1, 6, 69, 20, 62, 6, 44, 24, 113, 6, 35, 0, 3, 6, 44, 20, 22, 127, 60]#长度为20

for temp in enumerate(flag):
print(temp)
#flag[9]=5,flag[12]=x,flag[15]=i,flag[18]=V,flag[21]=5,flag[24]=P,flag[27]=K
""""
7 8 9 10
11 12 13 14
15 16 17 18
19 20 21 22
23 24 25 26
"""
#因为b列表每隔四个元素重复一次,所以只需每一列都有一个元素与arr元素相等即可
key= [0]*4
key[0]=ord(flag[15])^arr1[8]
key[1]=ord(flag[12])^arr1[5]
key[2]=ord(flag[9])^arr1[2]
key[3]=ord(flag[18])^arr1[11]

flag[-2] = chr(key[0])
flag[-3] = chr(key[1])
flag[-4] = chr(key[2])
flag[-5] = chr(key[3])

for i in range(len(arr1)):
flag[7+i]=chr(arr1[i]^key[i%4])



for temp in enumerate(flag):
print(temp)

arr2 = [90, 100, 87, 109, 86, 108, 86, 105, 90, 104, 88, 102]
tmp2 = 28
for i in range(0, len(arr2), 2):
for j in range(32,128):
if ((j + 107) // 16) + 77 == arr2[i] and ((j + 117) % 16) + 99 == arr2[i + 1]:
flag[tmp2] = chr(j)
tmp2 = tmp2 + 1



print(''.join(flag))

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

flag = [' '] *39
#check1


for x in range(100):
if x<100 and (x*x)%777^233 == 513:
print(x)

#check2
s = 3533889469877
for x in range (6):
ch =chr(s%128)
flag[5-x]= ch
s=s//128
flag[-1]='}'


#check3
arr0 = [249, 91, 149, 113, 16, 91, 53, 41]
for i in range(8):
for ch in range (32,128):
if (ch*17684+372511)%257 == arr0[i]:
flag[6+i*3]=chr(ch)


arr1 = [43, 1, 6, 69, 20, 62, 6, 44, 24, 113, 6, 35, 0, 3, 6, 44, 20, 22, 127, 60]


key= [0]*4
key[0]=ord(flag[15])^arr1[8]
key[1]=ord(flag[12])^arr1[5]
key[2]=ord(flag[9])^arr1[2]
key[3]=ord(flag[18])^arr1[11]

flag[-2] = chr(key[0])
flag[-3] = chr(key[1])
flag[-4] = chr(key[2])
flag[-5] = chr(key[3])

for i in range(len(arr1)):
flag[7+i]=chr(arr1[i]^key[i%4])

arr2 = [90, 100, 87, 109, 86, 108, 86, 105, 90, 104, 88, 102]
tmp2 = 28
for i in range(0, len(arr2), 2):
for j in range(32,128):
if ((j + 107) // 16) + 77 == arr2[i] and ((j + 117) % 16) + 99 == arr2[i + 1]:
flag[tmp2] = chr(j)
tmp2 = tmp2 + 1

print(''.join(flag))

flag

flag flag{5LZG50ex5Yi75VqE5YePLIKl541pNu3Fq}

参考博客

虎符网络安全赛道 Re Game - Hk_Mayfly - 博客园 (cnblogs.com)

2020-虎符网络安全赛道-Re-game - 简书 (jianshu.com)

[原创]python字节码逆向题 虎符第一题-CTF对抗-看雪-安全社区|安全招聘|kanxue.com