python字节码反编译工具 python字节码逆向_局部变量

前言:


   如果你跟我一样,对python的字节码感兴趣,想了解python的代码在内存中到底是怎么去运行的,那么你可以继续往下看,如果你是python新手,我建议你移步它处,本文适合有点基础的python读者。

   如果你不知道怎么生成python的字节码文件,可以查阅我的 python 代码反汇编  的博文  

 

 

python代码的执行过程:

  1. python代码编译成字节码【类似于汇编指令的中间语言】
  2. 字节码由python虚拟机来执行编译后的字节码

 

说明:

 一个python语句会对应若个字节码指令,每个字节指令又对应着一个函数偏移量,可以理解为指令的ID

 

        虚拟机一条一条执行字节码指令,从而完成程序的执行,而dis模块可以对CPython代码进行反汇编,生成字节码指令

 

 

dis.dis() 转化后的字节码格式如下:

源码行号  |  指令偏移量  | 指令符号 | 指令参数  |  实际参数值

       

说明: 不同版本的CPython 指令长度可能不同,但是 3.7的每条指令是2个字节,所以我们去看dis 生成的字节码指令集的时候,指令偏移量总是从0开始,每增加一条在原来的偏移量上增加2

    故,指令偏移量的值,一般都是: 0 , 2 , 4, 6 , 8 , ... , 2n ( n>=0 )

 

变量指令解析


 

变量 — _const

 

LOAD_CONST :加载const

 

案例一:

test(2,'hello')

  

对应的字节码指令

 

1             0 LOAD_NAME                0 (test)    
              2 LOAD_CONST               0 (2)
              4 LOAD_CONST               1 ('hello')
              6 CALL_FUNCTION            2            
              8 POP_TOP
             10 LOAD_CONST               2 (None)
             12 RETURN_VALUE

 

 

局部变量 — _FAST

 

LOAD_FAST

STORE_FAST

 

案例二:

 

n = n / p

 

对应的字节码指令

1             0 LOAD_NAME                0 (n)
              2 LOAD_NAME                1 (p)
              4 BINARY_TRUE_DIVIDE
              6 STORE_NAME               0 (n)
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

 

 

说明: 函数的形参也是局部变量,那么如何区分局部变量中的形参呢?

    形参是没有初始化的,所以如果发现发现操作的一个局部变量只有 LOAD_FAST 而没有 STORE_FAST,那么这个变量就是形参了。而其它的局部变量在使用之前肯定会使用STORE_FAST进行初始化。

 

案例三:

def test(arg1):
     num = 0
     print(num, arg1)

 

对应的字节码指令

1           0 LOAD_CONST               0 (<code object test at 0x10546c150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('test')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (test)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
Disassembly of <code object test at 0x10546c150, file "code.py", line 1>:
  2           0 LOAD_CONST               1 (0)
              2 STORE_FAST               1 (num)
 
  3           4 LOAD_GLOBAL              0 (print)
              6 LOAD_FAST                1 (num)
              8 LOAD_FAST                0 (arg1).  #只有LOAD_FAST ,没有 STORE_FAST
             10 CALL_FUNCTION            2
             12 POP_TOP
             14 LOAD_CONST               0 (None)
             16 RETURN_VALUE

 

全局变量 — _GLOBAL

 

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

STORE_GLOBAL

 

案例四

def test(arg1):
     global age
     age = 20
     print(age)

  

对应的字节码指令

1           0 LOAD_CONST               0 (<code object test at 0x1056e3150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('test')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (test)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
Disassembly of <code object test at 0x1056e3150, file "code.py", line 1>:
  3           0 LOAD_CONST               1 (20)
              2 STORE_GLOBAL             0 (age)
 
  4           4 LOAD_GLOBAL              1 (print)
              6 LOAD_GLOBAL              0 (age)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

 

常用数据类型


 

1.list

 

BUILD_LIST

 

案例五

a = [1, 2]

对应的字节码指令

1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 BUILD_LIST               2
              6 STORE_NAME               0 (a)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE                      //程序结束

 

案例六

[ x for x in range(4) if x > 2 ]

对应的字节码

1           0 LOAD_CONST               0 (<code object <listcomp> at 0x10bffa150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_NAME                0 (range)
              8 LOAD_CONST               2 (4)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 LOAD_CONST               3 (None)
             20 RETURN_VALUE
 
Disassembly of <code object <listcomp> at 0x10bffa150, file "code.py", line 1>:
  1           0 BUILD_LIST               0               //创建 list , 为赋值给某变量,这种时候一般都是语法糖结构了
              2 LOAD_FAST                0 (.0)        
        >>    4 FOR_ITER                16 (to 22)      //开启迭代循环
              6 STORE_FAST               1 (x)          //局部变量x
              8 LOAD_FAST                1 (x)          // 导入 x
             10 LOAD_CONST               0 (2)          // 导入 2
             12 COMPARE_OP               4 (>)          // x 与 2 进行比较,比较符号为 >
             14 POP_JUMP_IF_FALSE        4              // 不满足条件就跳过 “出栈“ 动作,既,continue 到 " >>  4 FOR_ITER. “ 处
             16 LOAD_FAST                1 (x)          // 读取满足条件的局部变量x
             18 LIST_APPEND              2              // 把满足条件的x 添加到list中
             20 JUMP_ABSOLUTE            4              
        >>   22 RETURN_VALUE                            //程序结束

 

 

2.dict

 

BUILD_MAP

STORE_MAP

 

案例七

k = {'a': 1}

对应的字节码

1           0 LOAD_CONST               0 ('a')
              2 LOAD_CONST               1 (1)
              4 BUILD_MAP                1
              6 STORE_NAME               0 (k)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

 

 

3.slice

 

BUILD_SLICE

BINARY_SUBSCR

STORE_SUBSCR

 

案例八

num = [1, 2, 3]
a = num[1:2]
b = num[0:1:1]
num[1:2] = [10, 11]

  

对应的字节码

1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 LOAD_CONST               2 (3)
              6 BUILD_LIST               3
              8 STORE_NAME               0 (num)
 
  2          10 LOAD_NAME                0 (num)
             12 LOAD_CONST               0 (1)
             14 LOAD_CONST               1 (2)
             16 BUILD_SLICE              2       #创建了一个切片
             18 BINARY_SUBSCR                 #读取切片中的值
             20 STORE_NAME               1 (a)   #将读取切片中的值赋值给变量 a
 
  3          22 LOAD_NAME                0 (num)
             24 LOAD_CONST               3 (0)
             26 LOAD_CONST               0 (1)
             28 LOAD_CONST               0 (1)
             30 BUILD_SLICE              3
             32 BINARY_SUBSCR
             34 STORE_NAME               2 (b)
 
  4          36 LOAD_CONST               4 (10)
             38 LOAD_CONST               5 (11)
             40 BUILD_LIST               2
             42 LOAD_NAME                0 (num)
             44 LOAD_CONST               0 (1)
             46 LOAD_CONST               1 (2)
             48 BUILD_SLICE              2
             50 STORE_SUBSCR
             52 LOAD_CONST               6 (None)
             54 RETURN_VALUE

 

 

4.循环

 

SETUP_LOOP

JUMP_ABSOLUTE: 结束循环

 

案例九

i = 0
while i < 10:
    i += 1

  

对应的字节码

1           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (i)
 
  2           4 SETUP_LOOP              20 (to 26)   // 循环开始处,26表示循环结束点
        >>    6 LOAD_NAME                0 (i)       // “>>" 表示循环切入点
              8 LOAD_CONST               1 (10)
             10 COMPARE_OP               0 (<)
             12 POP_JUMP_IF_FALSE       24
 
  3          14 LOAD_NAME                0 (i)
             16 LOAD_CONST               2 (1)
             18 INPLACE_ADD
             20 STORE_NAME               0 (i)
             22 JUMP_ABSOLUTE            6          // 逻辑上,循环在此处结束
        >>   24 POP_BLOCK                          
        >>   26 LOAD_CONST               3 (None)
             28 RETURN_VALUE

 

案例十

num = 0
for i in range(5):
    num += i

 

1           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (num)
 
  2           4 SETUP_LOOP              24 (to 30)  //开始循环
              6 LOAD_NAME                1 (range)
              8 LOAD_CONST               1 (5)
             10 CALL_FUNCTION            1          //调用range 函数
             12 GET_ITER                            //获取迭代 range 的 iter 
        >>   14 FOR_ITER                12 (to 28)  //开始进行 range 的迭代
             16 STORE_NAME               2 (i)
 
  3          18 LOAD_NAME                0 (num)
             20 LOAD_NAME                2 (i)
             22 INPLACE_ADD
             24 STORE_NAME               0 (num)
             26 JUMP_ABSOLUTE           14
        >>   28 POP_BLOCK
        >>   30 LOAD_CONST               2 (None)
             32 RETURN_VALUE

 

 

5.if

 

POP_JUMP_IF_FALSE

JUMP_FORWARD

COMPARE_OP:             比较指令

 

案例十一

num = 20
if num < 10:
    print('lt 10')
elif num > 10:
    print('gt 10')
else:
    print('eq 10')

对应的字节码

1           0 LOAD_CONST               0 (20)
              2 STORE_NAME               0 (num)
 
  2           4 LOAD_NAME                0 (num)
              6 LOAD_CONST               1 (10)
              8 COMPARE_OP               0 (<)
             10 POP_JUMP_IF_FALSE       22
 
  3          12 LOAD_NAME                1 (print)
             14 LOAD_CONST               2 ('lt 10')
             16 CALL_FUNCTION            1
             18 POP_TOP
             20 JUMP_FORWARD            26 (to 48)
 
  4     >>   22 LOAD_NAME                0 (num)
             24 LOAD_CONST               1 (10)
             26 COMPARE_OP               4 (>)
             28 POP_JUMP_IF_FALSE       40
 
  5          30 LOAD_NAME                1 (print)
             32 LOAD_CONST               3 ('gt 10')
             34 CALL_FUNCTION            1
             36 POP_TOP
             38 JUMP_FORWARD             8 (to 48)
 
  7     >>   40 LOAD_NAME                1 (print)
             42 LOAD_CONST               4 ('eq 10')
             44 CALL_FUNCTION            1
             46 POP_TOP
        >>   48 LOAD_CONST               5 (None)
             50 RETURN_VALUE