虎符-RE-game
基本指令
点击查看详细内容
- 阅读下文代码前基本须知
LOAD_CONST 加载常量 1
STORE_NAME 将变量储存为常量值 a=1 局部变量
STORE_GLOBAL同上功能 全局变量
BUILD_LIST 生成list
BUILD_MAP声明字典元素数量
STORE_MAP生成键值对 并储存
LOAD_NAME加载局部变量
BINARY_ADD加法
BINARY_SUBTRACT减法
BINARY_MULTIPLY乘法
BINARY_DIVIDE除法
BINARY_MODULO取余
BINARY_SUBSCR()
BUILD_SLICE切片
POP_TOP将结果从堆栈顶部弹出,以保证堆栈平衡
SETUP_LOOP表明循环开始 (to 28)参数说明此循环知道字节码偏移28字节的指令结束(也就是28字节开始不是循环)。
FOR_ITER调用堆栈 声明generator作用到字节码偏移位置27字节。
PRINT_ITEM为一个print函数。
COMPARE_OP指令对堆栈中两个常量进行比较
POP_JUMP_IF_FALSE指令,判断栈顶值来决定程序运行顺序实现判断功能。
基本查看
打开是一个txt文档。里面的内容是,python字节码。python的字节码只能靠自己硬读,没有什么其他方法。
python逆向或者反汇编的目的就是在没有源码的基础上,通过字节码来理解源代码的运行内容
分析
# Python 2.7
# Embedded file name: game.py
#源码行号|指令在函数中的偏移|指令符号|指令参数|实际参数值
1 0 LOAD_CONST 249
3 LOAD_CONST 91
6 LOAD_CONST 149
9 LOAD_CONST 113
12 LOAD_CONST 16
15 LOAD_CONST 91
18 LOAD_CONST 53
21 LOAD_CONST 41
24 BUILD_LIST_8 8
27 STORE_NAME 0 'arr0'
#arr0=[249,91,149,113,16,91,53,41]
2 30 LOAD_CONST 43
33 LOAD_CONST 1
36 LOAD_CONST 6
39 LOAD_CONST 69
42 LOAD_CONST 20
45 LOAD_CONST 62
48 LOAD_CONST 6
51 LOAD_CONST 44
54 LOAD_CONST 24
57 LOAD_CONST 113
60 LOAD_CONST 6
63 LOAD_CONST 35
66 LOAD_CONST 0
69 LOAD_CONST 3
72 LOAD_CONST 6
75 LOAD_CONST 44
78 LOAD_CONST 20
81 LOAD_CONST 22
84 LOAD_CONST 127
87 LOAD_CONST 60
90 BUILD_LIST_20 20
93 STORE_NAME 1 'arr1'
#arr1=[43,1,6,69,20,62,6,44,24,113,6,35,0,3,6,44,20,22,127,60]
3 96 LOAD_CONST 90
99 LOAD_CONST 100
102 LOAD_CONST 87
105 LOAD_CONST 109
108 LOAD_CONST 86
111 LOAD_CONST 108
114 LOAD_CONST 86
117 LOAD_CONST 105
120 LOAD_CONST 90
123 LOAD_CONST 104
126 LOAD_CONST 88
129 LOAD_CONST 102
132 BUILD_LIST_12 12
135 STORE_NAME 2 'arr2'
#arr2=[90,100,87,109,86,108,86,105,90,104,88,102]
5 138 LOAD_CODE <code_object check0>
141 MAKE_FUNCTION_0 0 None
144 STORE_NAME 3 'check0'
#check0()
8 147 LOAD_CODE <code_object check1>
150 MAKE_FUNCTION_0 0 None
153 STORE_NAME 4 'check1'
#check1()
14 156 LOAD_CODE <code_object check2>
159 MAKE_FUNCTION_0 0 None
162 STORE_NAME 5 'check2'
#check2()
20 165 LOAD_CODE <code_object check3>
168 MAKE_FUNCTION_0 0 None
171 STORE_NAME 6 'check3'
#check3()
37 174 LOAD_NAME 7 'raw_input'
177 CALL_FUNCTION_0 0 None
180 STORE_NAME 8 'flag'
#flag=raw_input()
38 183 LOAD_NAME 3 'check0'
186 LOAD_NAME 8 'flag'
189 CALL_FUNCTION_1 1 None
192 POP_JUMP_IF_FALSE 239 'to 239'
195 LOAD_NAME 4 'check1'
198 LOAD_NAME 8 'flag'
201 CALL_FUNCTION_1 1 None
204 POP_JUMP_IF_FALSE 239 'to 239'
207 LOAD_NAME 5 'check2'
210 LOAD_NAME 8 'flag'
213 CALL_FUNCTION_1 1 None
216 POP_JUMP_IF_FALSE 239 'to 239'
219 LOAD_NAME 6 'check3'
222 LOAD_NAME 8 'flag'
225 CALL_FUNCTION_1 1 None
228_0 COME_FROM 216 '216'
228_1 COME_FROM 204 '204'
228_2 COME_FROM 192 '192'
228 POP_JUMP_IF_FALSE 239 'to 239'
#if check0(flag):
#if check1(flag):
# if check2(flag):
# if check3(flag):
# print 'no'
# else print'ok'
39 231 LOAD_CONST 'ok'
234 PRINT_ITEM
235 PRINT_NEWLINE_CONT
236 JUMP_FORWARD 5 'to 244'
41 239 LOAD_CONST 'no'
242 PRINT_ITEM
243 PRINT_NEWLINE_CONT
244_0 COME_FROM 236 '236'
244 LOAD_CONST None
247 RETURN_VALUE
# 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
#all='<code_object <genexpr>>'
# 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'
#if len(s)<100:
# if (len(s)*len(s))%777)^233==513
# return True
# else:
# False
#else:
# False
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
# 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'
#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:
# if ord(s[-1])==125:
# return True
# else:
# return False
#else:
# return False
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
# 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'
#arr=map(ord,s)
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'
#a=arr[6:30:3]
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'
#for i in range(len(a))
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'
#if (a[i]*17684+372511)%257!=arr0[i]
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'
#return Flase
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'
#b=arr[-2:33:-1]*5
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'
#c=map('<code_object <lambda>>' zip(b,arr[7,27]))
28 156 LOAD_FAST 5 'c'
159 LOAD_GLOBAL 7 'arr1'
162 COMPARE_OP 3 !=
165 POP_JUMP_IF_FALSE 172 'to 172'
#if c!=arr1
29 168 LOAD_GLOBAL 5 'False'
171 RETURN_END_IF
172_0 COME_FROM 165 '165'
#else:return False
30 172 LOAD_CONST 0
175 STORE_FAST 6 'p'
#p=0
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'
#for i in range(28,34)
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'
#if (arr[i]+107)/16+77!=arr2[p]:
#if (arr[i]+117)/16+99!=arr2[p+1]:
33 268 LOAD_GLOBAL 9 'false'
271 RETURN_END_IF
272_0 COME_FROM 265 '265'
#else:return False
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'
#p+=2
35 286 LOAD_GLOBAL 10 'True'
289 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
#for x in range(ord(x))
# <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
#lambda x[0]^x[1]
整理后
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]
def check0()
def check1()
def check2()
def check3()
flag=raw_input()
if check0(flag):
if check1(flag):
if check2(flag):
if check3(flag):
print 'ok'
else:
print'no'
def check0():
all=ord(x) for x in range(32,128)
iter(s)
def check1():
if len(s)<100:
if (len(s)*len(s))%777)^233==513:
return True
else:
False
else:
False
def check2():
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:
if ord(s[-1])==125:
return True
else:
return False
else:
return False
def check3():
arr=map(ord,s)
a=arr[6:30:3]
for i in range(len(a))
if (a[i]*17684+372511)%257!=arr0[i]:
return Flase
b=arr[-2:33:-1]*5
c=map(lambda x[0]:x[0]^x[1] zip(b,arr[7,27]))
if c!=arr1:
p=0
for i in range(28,34):
if (arr[i]+107)/16+77!=arr2[p]:
if (arr[i]+117)/16+99!=arr2[p+1]:
p+=2
else:
return False
#<genexpr> ord(x) for x in range(32,128)
#<lambda> x[0]^x[1]
这只能看个大概...不一定完全准确...有不同意见欢迎指正留言QAQ事实上非常期望得到指教。毕竟这是我第一次读这种。
分析代码
结合官方的wp分析
flag需经过check0,check1,check2,check3四个函数的检查
check0,flag字符均在32, 128范围内
check1,条件l < 100 and ((l*l) % 777) ^ 233 == 513获得flag长度为39
check2,通过128进制得到flag的开头为“flag{5”以及结尾为“}”
check3,其中对三段flag进行了计算,第一部分可以爆破运算式得到,第二部分需要通过第一部分的结果异或得到,第三部分类似16进制编码,可以直接恢复
解题脚本
爆破
flag = [' ']*39
x = 3533889469877
t = ''
while x != 0:
t += chr(x%128)
x/=128
flag[:6] = t[::-1]
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])
arr2 = [90, 100, 87, 109, 86, 108, 86, 105, 90, 104, 88, 102]
z3脚本解
from z3 import *
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]
k = Solver()
s = [BitVec('s[%d]'%i,64)for i in range(39)]
for i in range(39):
k.add(32<=s[i])
k.add(s[i]<128)
k.add(((((s[0]*128+s[1])*128+s[2])*128+s[3])*128+s[4])*128+s[5] == 3533889469877)
k.add(s[-1]== ord('}'))
arr = list(s)
a = arr[6:30:3]
for i in range(len(a)):
k.add((a[i]*17684+372511)%257==arr0[i])
b = arr[-2:33:-1]*5
c = list(map(lambda x:x[0]^x[1] ,zip(b,arr[7:27])))
for i in range(len(c)):
k.add(c[i]==arr1[i])
p = 0
for i in range(28,34):
k.add(arr2[p] == (arr[i]+107)/16+77)
k.add((arr[i]+117)%16+99==arr2[p+1])
p+=2
print(k.check())
print(k.model())
z3脚本二次转换
s = [0]*39
s[5]=53
s[4]=123
s[34]=117
s[7]=90
s[6]=76
s[30]=52
s[18]=86
s[35]=51
s[33]=78
s[24]=80
s[12]=120
s[11]=101
s[20]=69
s[15]=105
s[3]=103
s[25]=76
s[23]=101
s[2]=97
s[16]=55
s[29]=53
s[17]=53
s[22]=89
s[36]=70
s[21]=53
s[8]=71
s[13]=53
s[28]=108
s[26]=73
s[14]=89
s[0]=102
s[37]=113
s[31]=49
s[10]=48
s[1]=108
s[9]=53
s[27]=75
s[32]=112
s[19]=113
s[38]=125
for i in range(39):
print(chr(s[i]),end="")
z3很好用。z3这部分脚本详细参考于CX-330的博文。
第一次知道有这种东西,值得学习嗷!