python字节码

从一道CTF题学习python字节码到源码逆向 - nLesxw - 博客园

前文

先了解python的字节码结构,如下:

源码行号 | 指令在函数中的偏移 | 指令符号 | 指令参数 | 实际参数值

第一个为源码行号,从上述题目中我们可以了解到,本题只有5行源码,但是只给了从第3行开始的字节码

第二个指令在函数中的偏移和第四个指令参数对于做题来说不是太过重要,我们在做题的时候主要还是看指令符号和实际参数值

在第3行的字节码指令符号中,有LOAD_CONST ,BUILD_LIST ,STORE_FAST 三种类型

LOAD_CONST 加载常量,通常为整数值

BUILD_LIST 创建一个列表

STORE_FAST 一般用于保存值到局部变量

SETUP_LOOP,用于开始循环,括号里的189表示循环退出点(字节码结构中的第二个指令在函数中偏移)

LOAD_GLOBAL,用来加载全局变量,包括指定函数名,类名,模块名等全局符号

CALL_FUNCTION,用来表示前面加载全局变量的参数个数

GET_ITER,FOR_ITER ,获取参数,开始迭代。这两个不需要过多理解,属于for-in结构特有的,它们通常同时出现。

BINARY_SUBSCR ,读取迭代器中某个下标的值

BINARY_RSHIFT,进行右移运算

BINARY_LSHIFT ,左移运算

BINARY_OR,或运算

BINARY_AND ,与运算

STORE_SUBSCR ,修改迭代器中某个下标的值

JUMP_ABSOLUTE ,回到循环起点

RETURN_VALUE ,函数结束标志

POP_BLOCK,特有的,不用特别理解,对转换回源码不重要,通常和LOAD_CONST 0 (None)一起出现。

例题

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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
ezRe (Python 3.9)
[Code]
File Name: flag_checker.py
Object Name: <module>
Arg Count: 0
Pos Only Arg Count: 0
KW Only Arg Count: 0
Locals: 0
Stack Size: 7
Flags: 0x00000040 (CO_NOFREE)
[Names]
'base64'
'input'
'text'
'key'
'list'
'range'
's'
'j'
'i'
'len'
'data'
'_'
'append'
'result'
'zip'
'c'
'k'
'chr'
'ord'
'b64encode'
'encode'
'decode'
'enc'
'print'
[Var Names]
[Free Vars]
[Cell Vars]
[Constants]
0
None
'Flag: '
'7e021a7dd49e4bd0837e22129682551b'
[Code]
File Name: flag_checker.py
Object Name: <listcomp>
Arg Count: 1
Pos Only Arg Count: 0
KW Only Arg Count: 0
Locals: 2
Stack Size: 4
Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
[Names]
'ord'
[Var Names]
'.0'
'i'
[Free Vars]
[Cell Vars]
[Constants]
102
[Disassembly]
0 BUILD_LIST 0
2 LOAD_FAST 0: .0
4 FOR_ITER 16 (to 22)
6 STORE_FAST 1: i
8 LOAD_GLOBAL 0: ord
10 LOAD_FAST 1: i
12 CALL_FUNCTION 1
14 LOAD_CONST 0: 102
16 BINARY_XOR
18 LIST_APPEND 2
20 JUMP_ABSOLUTE 4
22 RETURN_VALUE
'<listcomp>'
256
50
1
''
51
'w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg=='
'yes!'
'try again...'
[Disassembly]
0 LOAD_CONST 0: 0
2 LOAD_CONST 1: None
4 JUMP_FORWARD 0 (to 6)
6 JUMP_FORWARD 0 (to 8)
8 JUMP_FORWARD 0 (to 10)
10 IMPORT_NAME 0: base64
12 STORE_NAME 0: base64
14 LOAD_NAME 1: input
16 LOAD_CONST 2: 'Flag: '
18 CALL_FUNCTION 1
20 STORE_NAME 2: text
22 LOAD_CONST 3: '7e021a7dd49e4bd0837e22129682551b'
24 STORE_NAME 3: key
26 LOAD_CONST 4: <CODE> <listcomp>
28 LOAD_CONST 5: '<listcomp>'
30 MAKE_FUNCTION 0
32 LOAD_NAME 3: key
34 GET_ITER
36 CALL_FUNCTION 1
38 STORE_NAME 3: key
40 LOAD_NAME 4: list
42 LOAD_NAME 5: range
44 LOAD_CONST 6: 256
46 CALL_FUNCTION 1
48 CALL_FUNCTION 1
50 STORE_NAME 6: s
52 LOAD_CONST 0: 0
54 STORE_NAME 7: j
56 LOAD_NAME 5: range
58 LOAD_CONST 6: 256
60 CALL_FUNCTION 1
62 GET_ITER
64 FOR_ITER 62 (to 128)
66 STORE_NAME 8: i
68 LOAD_NAME 7: j
70 LOAD_NAME 6: s
72 LOAD_NAME 8: i
74 BINARY_SUBSCR
76 BINARY_ADD
78 LOAD_NAME 3: key
80 LOAD_NAME 8: i
82 LOAD_NAME 9: len
84 LOAD_NAME 3: key
86 CALL_FUNCTION 1
88 BINARY_MODULO
90 BINARY_SUBSCR
92 BINARY_ADD
94 LOAD_CONST 6: 256
96 BINARY_MODULO
98 STORE_NAME 7: j
100 LOAD_NAME 6: s
102 LOAD_NAME 7: j
104 BINARY_SUBSCR
106 LOAD_NAME 6: s
108 LOAD_NAME 8: i
110 BINARY_SUBSCR
112 ROT_TWO
114 LOAD_NAME 6: s
116 LOAD_NAME 8: i
118 STORE_SUBSCR
120 LOAD_NAME 6: s
122 LOAD_NAME 7: j
124 STORE_SUBSCR
126 JUMP_ABSOLUTE 64
128 LOAD_CONST 0: 0
130 DUP_TOP
132 STORE_NAME 8: i
134 STORE_NAME 7: j
136 BUILD_LIST 0
138 STORE_NAME 10: data
140 LOAD_NAME 5: range
142 LOAD_CONST 7: 50
144 CALL_FUNCTION 1
146 GET_ITER
148 FOR_ITER 88 (to 238)
150 STORE_NAME 11: _
152 LOAD_NAME 8: i
154 LOAD_CONST 8: 1
156 BINARY_ADD
158 LOAD_CONST 6: 256
160 BINARY_MODULO
162 STORE_NAME 8: i
164 LOAD_NAME 7: j
166 LOAD_NAME 6: s
168 LOAD_NAME 8: i
170 BINARY_SUBSCR
172 BINARY_ADD
174 LOAD_CONST 6: 256
176 BINARY_MODULO
178 STORE_NAME 7: j
180 LOAD_NAME 6: s
182 LOAD_NAME 7: j
184 BINARY_SUBSCR
186 LOAD_NAME 6: s
188 LOAD_NAME 8: i
190 BINARY_SUBSCR
192 ROT_TWO
194 LOAD_NAME 6: s
196 LOAD_NAME 8: i
198 STORE_SUBSCR
200 LOAD_NAME 6: s
202 LOAD_NAME 7: j
204 STORE_SUBSCR
206 LOAD_NAME 10: data
208 LOAD_METHOD 12: append
210 LOAD_NAME 6: s
212 LOAD_NAME 6: s
214 LOAD_NAME 8: i
216 BINARY_SUBSCR
218 LOAD_NAME 6: s
220 LOAD_NAME 7: j
222 BINARY_SUBSCR
224 BINARY_ADD
226 LOAD_CONST 6: 256
228 BINARY_MODULO
230 BINARY_SUBSCR
232 CALL_METHOD 1
234 POP_TOP
236 JUMP_ABSOLUTE 148
238 LOAD_CONST 9: ''
240 STORE_NAME 13: result
242 LOAD_NAME 14: zip
244 LOAD_NAME 2: text
246 LOAD_NAME 10: data
248 CALL_FUNCTION 2
250 GET_ITER
252 FOR_ITER 32 (to 286)
254 UNPACK_SEQUENCE 2
256 STORE_NAME 15: c
258 STORE_NAME 16: k
260 LOAD_NAME 13: result
262 LOAD_NAME 17: chr
264 LOAD_NAME 18: ord
266 LOAD_NAME 15: c
268 CALL_FUNCTION 1
270 LOAD_NAME 16: k
272 BINARY_XOR
274 LOAD_CONST 10: 51
276 BINARY_XOR
278 CALL_FUNCTION 1
280 INPLACE_ADD
282 STORE_NAME 13: result
284 JUMP_ABSOLUTE 252
286 LOAD_NAME 0: base64
288 LOAD_METHOD 19: b64encode
290 LOAD_NAME 13: result
292 LOAD_METHOD 20: encode
294 CALL_METHOD 0
296 CALL_METHOD 1
298 LOAD_METHOD 21: decode
300 CALL_METHOD 0
302 STORE_NAME 22: enc
304 LOAD_NAME 22: enc
306 LOAD_CONST 11: 'w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg=='
308 COMPARE_OP 2 (==)
310 POP_JUMP_IF_FALSE 324
314 LOAD_NAME 23: print
316 LOAD_CONST 12: 'yes!'
318 CALL_FUNCTION 1
320 POP_TOP
322 JUMP_FORWARD 8 (to 332)
324 LOAD_NAME 23: print
326 LOAD_CONST 13: 'try again...'
328 CALL_FUNCTION 1
330 POP_TOP
332 LOAD_CONST 1: None
334 RETURN_VALUE
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
import base64

# 原始密钥和加密的目标输出
key = '7e021a7dd49e4bd0837e22129682551b'
encoded_target = 'w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg=='

# 处理密钥
processed_key = [ord(i) ^ 102 for i in key]

# RC4 类似的流密码算法构建
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + processed_key[i % len(processed_key)]) % 256
s[i], s[j] = s[j], s[i]

# 生成数据流 `data`
i = j = 0
data = []
for _ in range(50): # 生成50个密钥流字节
i = (i + 1) % 256
j = (j + s[i]) % 256
s[i], s[j] = s[j], s[i]
data.append(s[(s[i] + s[j]) % 256])

# 解码 `encoded_target` 并转换为原始字符串
target_bytes = base64.b64decode(encoded_target).decode()
decoded_text = ''

# 使用 `data``target_bytes` 进行解码
for c, k in zip(target_bytes, data):
decoded_text += chr((ord(c) ^ k) ^ 51)

print("Decoded text (flag):", decoded_text)

python字节码
http://example.com/2024/06/03/python字节码/
Author
chaye
Posted on
June 3, 2024
Licensed under