-
-
[原创]死磕python字节码-手工还原python源码
-
发表于:
2018-9-6 11:11
17059
-
[原创]死磕python字节码-手工还原python源码
Python 代码先被编译为字节码后,再由Python虚拟机来执行字节码, Python的字节码是一种类似汇编指令的中间语言, 一个Python语句会对应若干字节码指令,虚拟机一条一条执行字节码指令, 从而完成程序执行。
Python dis 模块支持对Python代码进行反汇编, 生成字节码指令。
dis.dis()
将CPython字节码转为可读的伪代码(类似于汇编代码)。结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 7 0 LOAD_CONST 1 ( 0 )
3 STORE_FAST 1 (local1)
8 6 LOAD_CONST 2 ( 101 )
9 STORE_GLOBAL 0 (global1)
9 12 LOAD_FAST 1 (local1)
15 PRINT_ITEM
16 LOAD_FAST 0 (arg1)
19 PRINT_ITEM
20 LOAD_GLOBAL 0 (global1)
23 PRINT_ITEM
24 PRINT_NEWLINE
25 LOAD_CONST 0 ( None )
28 RETURN_VALUE
|
其实就是这样的结构:
1 | 源码行号 | 指令在函数中的偏移 | 指令符号 | 指令参数 | 实际参数值
|
LOAD_CONST
加载const
变量,比如数值、字符串等等,一般用于传给函数的参数
1 2 3 4 | 55 12 LOAD_GLOBAL 1 (test)
15 LOAD_FAST 0 ( 2 )
18 LOAD_CONST 1 ( 'output' )
21 CALL_FUNCTION 2
|
转为python代码就是:
LOAD_FAST
一般加载局部变量的值,也就是读取值,用于计算或者函数调用传参等。
STORE_FAST
一般用于保存值到局部变量。
1 2 3 4 | 61 77 LOAD_FAST 0 (n)
80 LOAD_FAST 3 (p)
83 INPLACE_DIVIDE
84 STORE_FAST 0 (n)
|
这段bytecode转为python就是:
函数的形参也是局部变量,如何区分出是函数形参还是其他局部变量呢?
形参没有初始化,也就是从函数开始到LOAD_FAST
该变量的位置,如果没有看到STORE_FAST
,那么该变量就是函数形参。
而其他局部变量在使用之前肯定会使用STORE_FAST
进行初始化。
具体看下面的实例:
1 2 3 4 5 6 7 8 9 10 | 4 0 LOAD_CONST 1 ( 0 )
3 STORE_FAST 1 (local1)
5 6 LOAD_FAST 1 (local1)
9 PRINT_ITEM
10 LOAD_FAST 0 (arg1)
13 PRINT_ITEM
14 PRINT_NEWLINE
15 LOAD_CONST 0 ( None )
18 RETURN_VALUE
|
对应的python代码如下,对比一下就一目了然。
1 2 3 | def test(arg1):
local1 = 0
print local1, arg1
|
LOAD_GLOBAL
用来加载全局变量,包括指定函数名,类名,模块名等全局符号。
STORE_GLOBAL
用来给全局变量赋值。
1 2 3 4 | 8 6 LOAD_CONST 2 ( 101 )
9 STORE_GLOBAL 0 (global1)
20 LOAD_GLOBAL 0 (global1)
23 PRINT_ITEM
|
对应的python代码
1 2 3 4 | def test():
global global1
global1 = 101
print global
|
BUILD_LIST
用于创建一个list结构。
1 2 3 4 | 13 0 LOAD_CONST 1 ( 1 )
3 LOAD_CONST 2 ( 2 )
6 BUILD_LIST 2
9 STORE_FAST 0 (k)
|
对应python代码是:
另外再看看一种常见的创建list的方式如下:
1 | [x for x in xlist if x! = 0 ]
|
一个实例bytecode如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 22 235 BUILD_LIST 0 / / 创建 list ,为赋值给某变量,这种时候一般都是语法糖结构了
238 LOAD_FAST 3 (sieve)
241 GET_ITER
>> 242 FOR_ITER 24 (to 269 )
245 STORE_FAST 4 (x)
248 LOAD_FAST 4 (x)
251 LOAD_CONST 2 ( 0 )
254 COMPARE_OP 3 (! = )
257 POP_JUMP_IF_FALSE 242 / / 不满足条件contine
260 LOAD_FAST 4 (x) / / 读取满足条件的x
263 LIST_APPEND 2 / / 把每个满足条件的x存入 list
266 JUMP_ABSOLUTE 242
>> 269 RETURN_VALUE
|
转为python代码是:
1 | [ for x in sieve if x ! = 0 ]
|
BUILD_MAP
用于创建一个空的dict。STORE_MAP
用于初始化dict的内容。
1 2 3 4 5 | 13 0 BUILD_MAP 1
3 LOAD_CONST 1 ( 1 )
6 LOAD_CONST 2 ( 'a' )
9 STORE_MAP
10 STORE_FAST 0 (k)
|
对应的python代码是:
再看看修改dict的bytecode:
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!