操作码又称为操作码,是将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沙箱的方法详解