如何执行Python中dis.dis()输出的反汇编代码?
执行Python反汇编代码的方法
首先得明确一点:Python标准库的dis模块并没有内置你期望的dis.run()函数,但我们可以自己实现类似的功能——把反汇编的文本指令转换成可执行的字节码,让Python虚拟机执行。
为什么不能直接执行反汇编文本?
反汇编输出是字节码的人类可读表示,Python解释器只能执行二进制格式的字节码(对应CodeObject对象)。打个比方,反汇编文本就像是字节码的“说明书”,你得照着说明书还原出真实的“机器零件”(字节码),才能让解释器运行它。
实现步骤与示例代码
下面是一个针对你给出的示例,专门编写的解析并执行反汇编文本的函数:
import dis import types def run_disassembly(disasm_text): # 解析反汇编文本,提取每一行的指令信息 instructions = [] for line in disasm_text.strip().split('\n'): line_parts = line.split() if len(line_parts) < 3: continue # 提取操作码名称(比如LOAD_GLOBAL) op_name = line_parts[2] # 转换成对应的字节码数值 op_code = dis.opmap[op_name] # 处理指令参数(如果有的话) arg = None if len(line_parts) > 3: arg_raw = line_parts[3] # 去掉参数外层的括号,比如(print) -> print if arg_raw.startswith('(') and arg_raw.endswith(')'): arg_content = arg_raw[1:-1] # 区分字符串常量和索引值 if arg_content.startswith("'") and arg_content.endswith("'"): arg = arg_content[1:-1] else: arg = int(arg_content) instructions.append((op_code, arg)) # 构建对应常量池和全局变量表(和你的反汇编示例匹配) const_pool = (None, 'hello') global_names = ('print',) # 生成可执行的CodeObject code_obj = types.CodeType( 0, # 位置参数数量 0, # 仅位置参数数量 0, # 仅关键字参数数量 0, # 本地变量数量 256, # 栈大小 0, # 标志位 # 把指令转换成二进制字节码 b''.join([ op_code.to_bytes(1, byteorder='little') + (arg.to_bytes(2, byteorder='little') if isinstance(arg, int) else b'') for op_code, arg in instructions ]), const_pool, # 常量池 global_names,# 全局变量名表 (), # 本地变量名表 '<disasm>', # 文件名标识 '<run_disasm>', # 函数名标识 1, # 起始行号 b'' # 行号映射表 ) # 执行生成的CodeObject exec(code_obj) # 测试你的示例反汇编代码 sample_disasm = ''' 3 0 LOAD_GLOBAL 0 (print) 2 LOAD_CONST 1 ('hello') 4 CALL_FUNCTION 1 6 POP_TOP 8 LOAD_CONST 0 (None) 10 RETURN_VALUE ''' run_disassembly(sample_disasm)
关于反汇编代码与.pyc文件的关系
.pyc文件是Python源码编译后生成的序列化CodeObject,本质上和我们上面构建的code_obj是同一类东西,只是以二进制文件的形式存储。- 反汇编代码是
.pyc文件(或CodeObject)的文本“翻译版”,所以只要能把反汇编文本准确转换回CodeObject,就可以像执行.pyc文件一样执行它——甚至你可以把生成的CodeObject序列化保存为.pyc文件,之后直接加载执行。
注意事项
- 上面的示例是针对你的特定场景简化的,实际开发中需要处理更多指令类型、参数类型(比如本地变量、闭包引用等),以及更复杂的常量池和变量表。
- 不同Python版本的字节码指令可能有差异,所以解析反汇编文本时需要对应版本的
dis.opmap字典。
内容的提问来源于stack exchange,提问作者USERNAME GOES HERE




