使用操作码绕过Python沙箱的方法详解

  


  

  

操作码又称为操作码,是将python源代码进行编译之后的结果,python虚拟机无法直接执行人类可读的源代码,因此python编译器第一步先将源代码进行编译,以此得到码。例如在执行python程序时一般会先生成一个佩克文件,佩克文件就是编译后的结果,其中含有操作码序列。

  

<>强如何查看一个函数的操作码# 63;
  

        def ():   如果1==2:   print(“国旗{* * * *}”)      打印“操作码():”,a.__code__.co_code.encode(十六进制)      

通过此方法我们可以得到一个函数的操作码

  
  

()的操作码:6401006402006 b020072140064030047486e000064000053
  

     

我们可以通过说库获得相应的解析结果。

        进口说      dis.dis (' 6401006402006 b020072140064030047486e000064000053 ' .decode(十六进制))      

得到反编译的结果

  
  

0 LOAD_CONST ,,,,,,,,1 (1)
  ,,,,3 LOAD_CONST ,,,,,,,,2 (2)
  ,,,,6 COMPARE_OP ,,,,,,,,2 (==)
  ,,,,9 POP_JUMP_IF_FALSE ,,20
  ,,,,12 LOAD_CONST ,,,,,,,,3 (3)
  ,,,,15 LOAD_BUILD_CLASS
  ,,,,16 YIELD_FROM ,,,
  ,,,,17 JUMP_FORWARD ,,,,,,0 (20)
  在在,,20 LOAD_CONST ,,,,,,,,0 (0)
  ,,,,23 RETURN_VALUE
  

     

<强>常见的字节码指令
  

  

为了进一步研究操作码,我们可以对dis的disassemble_string函数进行补丁

  

在124行加入

        打印十六进制(op) .ljust (6),      

可以查看具体的字节码。

  
  

0 LOAD_CONST ,,,,,,,,,0 x64 ,,,,,1 (1)
  ,,,,3 LOAD_CONST ,,,,,,,,,0 x64 ,,,,,2 (2)
  ,,,,6 COMPARE_OP ,,,,,,,,,0 x6b ,,,,,2 (==)
  ,,,,9 POP_JUMP_IF_FALSE ,,0 x72 ,,,,20
  ,,,,12 LOAD_CONST ,,,,,,,,,0 x64 ,,,,,3 (3)
  ,,,,15 LOAD_BUILD_CLASS ,,,0 x47 
  ,,,,16 YIELD_FROM ,,,,,,,,,0 x48 
  ,,,,17 JUMP_FORWARD ,,,,,,,0 x6e ,,,,,0 (20)
  在在,,20 LOAD_CONST ,,,,,,,,,0 x64 ,,,,,0 (0)
  ,,,,23 RETURN_VALUE ,,,,,,,,0 x53
  

     

<强>变量
  

  

           指令名   操作               LOAD_GLOBAL   读取全局变量         STORE_GLOBAL   给全局变量赋值         LOAD_FAST   读取局部变量         STORE_FAST   给局部变量赋值         LOAD_CONST   读取常量            

  

<强>如果
  

  

           指令名   操作               POP_JUMP_IF_FALSE   当条件为假的时候跳转         JUMP_FORWARD   直接跳转            

  

<强> CMP_OP
  

        cmp_op=(' & lt; ', ' & lt;=', '==', ' !=薄ⅰ霸凇薄ⅰ白4?薄ⅰ霸凇薄ⅰ安皇恰薄ⅰ笆恰薄ⅰ安皇恰薄ⅰ耙斐Fヅ洹薄ⅰ盎怠?      

其余的指令参考操作码源码

  


  

  

在Python中,我们可以对任意函数的__code__参数进行赋值,通过对其进行赋值,我们可以改变程序运行逻辑。

  

<>强例二
  

        def ():   如果1==2:   print(“国旗{* * * *}”)      

在沙箱环境中我们需要调用这个函数,但是此函数我们无法执行到打印语句。因此我们需要通过某种方法得到国旗

  

<强>解决方案1
  

  

我们直接获取a.__code__.co_consts,查看所有的常量。即可知道旗

        (没有,1、2、国旗{* * * *})      

<强>解决方案2
  

  

更改程序运行逻辑
  

  

CodeType构造函数

        def __init__(自我、argcount nlocals堆栈大小,旗帜,代码,   常量,名称、varnames文件名,名字,   firstlineno、lnotab freevars=None, cellvars=None):      

上述函数其余参数均可通过__code.__。co_xxx获得
  

  

因此我们

     

使用操作码绕过Python沙箱的方法详解