昨天上午弄了那么久以为能拿一血没想到被砍在前六个字符,是我太菜了。权当学习python字节码指令了。
下载给的就是asm文件,不是pyc文件,不能反编译成源代码,只能看汇编码,还好汇编不难。
源文件见附件(加了注释)
硬编码三个字符串,然后定义四个check函数,check0~check3.
输入的值保存在flag里面:
37 174 LOAD_NAME 7 'raw_input' #获取控制台的输入函数
177 CALL_FUNCTION_0 0 None
180 STORE_NAME 8 'flag' //输入flag保存在此
后面就是对flag四次check,
check0:调用genexpr函数,对输入进行判断,输入的所有字符串范围 32 ~ 128
6 0 LOAD_GLOBAL 0 'all'
3 LOAD_GENEXPR '<code_object <genexpr>>' //输入的字符32~128
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
check1函数,输入长度的函数,首先小于100,同时 满足(s*s)%777^233==513 :
# check1 line 8 of game.py 输入的值 先 * 再%777 再xor 233
9 0 LOAD_GLOBAL 0 'len' len函数
3 LOAD_FAST 0 's' 形参
6 CALL_FUNCTION_1 1 None
9 LOAD_CONST 100 #flag长度小于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 * s*s
37 LOAD_CONST 777
40 BINARY_MODULO tos=tos1%tos (s*s)%777
41 LOAD_CONST 233
44 BINARY_XOR tos=tos1^tos (s*s)%777^233
45 LOAD_CONST 513 最后等于513 (s*s)%777^233==513 s=39
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
简单的可以爆破出flag长度是39:
for s in range(100):
if (s*s)%777^233==513:
print("flag长度:{}".format(s)) 涉及到的关键字节码指令:
BINARY_MULTIPLY
实现 TOS = TOS1 * TOS 。
BINARY_MODULO
实现 TOS = TOS1 % TOS 。
BINARY_XOR
实现 TOS = TOS1 ^ TOS 。
python都是运行在虚拟机上的,写过stack_base的虚拟机可以看出值都是堆栈操作指令。
check2 函数:是对前六个字符操作,这就是卡着我的地方,每一个字符*128再+后面的值再*128,最后等于3533889469877,我以为可以爆破出来,我too young了:
0 LOAD_GLOBAL 0 'ord'
3 LOAD_FAST 0 's'
6 LOAD_CONST 0
9 BINARY_SUBSCR a[0]
10 CALL_FUNCTION_1 1 None
13 LOAD_CONST 128
16 BINARY_MULTIPLY a[0] *128
17 LOAD_GLOBAL 0 'ord'
20 LOAD_FAST 0 's'
23 LOAD_CONST 1
26 BINARY_SUBSCR a[i]
27 CALL_FUNCTION_1 1 None
30 BINARY_ADD a[0] *128+a[1]
31 LOAD_CONST 128
34 BINARY_MULTIPLY (a[0] *128+a[1])*128
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 (a[0] *128+a[1])*128+a[2]
49 LOAD_CONST 128
52 BINARY_MULTIPLY ((a[0] *128+a[1])*128+a[2])*128
53 LOAD_GLOBAL 0 'ord'
56 LOAD_FAST 0 's'
59 LOAD_CONST 3
62 BINARY_SUBSCR ((a[0] *128+a[1])*128+a[2])*128+a[3]
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' 后面才知道原来乘以128就是往后移7位,这样直接从最后一位手动移位可以弄出来flag{5 ,虽然有点繁琐 (微笑.jpg),而我搁哪爆破:
'''for i0 in range(127):
for i1 in range(127):
for i2 in range(127):
for i3 in range(127):
for i4 in range(127):
for i5 in range(127):
if ((((i0*128+i1)*128+i2)*128+i3)*128+i4)*128+i5==3533889469877:
print(i0)
print(i1)
print(i2)
print(i3)
print(i4)
print(i5)'''
关键字节码指令:
BINARY_ADD
实现 TOS = TOS1 + TOS 。
BINARY_SUBSCR
实现 TOS = TOS1[TOS] 。
check3函数:
先调用slice函数,对从第6位开始,30位截至,跨度为3进行解密:
6 9 12 15 18 21 24 27
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 6开始30结束跨度3
21 LOAD_CONST 30
24 LOAD_CONST 3
27 BUILD_SLICE_3 3 slice(TOS2, TOS1, TOS)
30 BINARY_SUBSCR
31 STORE_FAST 2 'a' 2. 满足(a[i]*17684+372511)%257 和 arr0里面的相同
77 BINARY_MODULO (a[i]*17684+372511)%257
78 LOAD_GLOBAL 4 'arr0'
81 LOAD_FAST 3 'i'
84 BINARY_SUBSCR arr0[i]
85 COMPARE_OP 3 !=
3. 接着倒着从倒数第二位取出来到33位置: 37 36 35 34
26 99 LOAD_FAST 1 'arr'
102 LOAD_CONST -2
105 LOAD_CONST 33
108 LOAD_CONST -1
111 BUILD_SLICE_3 3 slice(TOS2, TOS1, TOS)
114 BINARY_SUBSCR
115 LOAD_CONST 5
118 BINARY_MULTIPLY tos*5
119 STORE_FAST 4 'b'
4. 取出arr1的 2 5 8 11 和flag9 12 15 18 异或的四个字母就是最后的几位倒叙的
27 122 LOAD_GLOBAL 0 'map'
125 LOAD_LAMBDA '<code_object <lambda>>'
128 MAKE_FUNCTION_0 0 None
131 LOAD_GLOBAL 6 'c'
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'
5. 28到34 位置:字符同时满足 (?+117)%16 +99=arr2[i] 和 (?+107)/16+77==arr2[i+1]
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 arr[i]
207 LOAD_CONST 107
210 BINARY_ADD arr[i]+107
211 LOAD_CONST 16
214 BINARY_DIVIDE (arr[i]+107)/16
215 LOAD_CONST 77
218 BINARY_ADD (arr[i]+107)/16+77
219 LOAD_GLOBAL 8 'arr2'
222 LOAD_FAST 6 'p'
225 BINARY_SUBSCR arr2[p]
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 arr[i]
239 LOAD_CONST 117
242 BINARY_ADD arr[i]+117
243 LOAD_CONST 16
246 BINARY_MODULO (arr[i]+117)%16
247 LOAD_CONST 99
250 BINARY_ADD (arr[i]+117)%16 +99
251 LOAD_GLOBAL 8 'arr2'
254 LOAD_FAST 6 'p'
257 LOAD_CONST 1
260 BINARY_ADD p+1
261 BINARY_SUBSCR arr2[p]
262 COMPARE_OP 3 !=
265_0 COME_FROM 229 '229'
265 POP_JUMP_IF_FALSE 272 'to 272'
6 最后7 到27位又重新复制循环arr1里面的字符和4解出的四个异或,
然后有一个疑问就是满足
if ((ch + 107) / 16) + 77 == arr2[i] and ((ch + 117) % 16) + 99 == arr2[i+1]:我算只有一个!!!!
官方给的修改版keygen:
flag = [' ']*39
flag[-1] = '}'
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] = arr1[8] ^ ord(flag[15])
key[1] = arr1[5] ^ ord(flag[12])
key[2] = arr1[2] ^ ord(flag[9])
key[3] = arr1[11] ^ ord(flag[18])
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])
flag2=""
arr2 = [90, 100, 87, 109, 86, 108, 86, 105, 90, 104, 88, 102]
for i in range(0, len(arr2), 2):
for ch in range(32, 128):
if ((ch + 107) / 16) + 77 == arr2[i] and ((ch + 117) % 16) + 99 == arr2[i+1]:
flag[28+i/2] += chr(ch)
print(flag)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: