对于uncompyle6 的作用存在一些混淆。它以 Python bytecode 开头,如果是 Python 3.6 或更高版本,则更准确地说是“wordcode”。或者,它通常用于反编译包含字节码的 Python 编译文件。
从您上面显示的内容来看,我相信您想要做的是从版本特定的反汇编程序生成的字节码的 text 表示开始,该反汇编程序附带(并且仅完全适用) Python 正在运行的版本。
这就是您从 uncompyle6 收到上述奇怪的“导入错误”消息的原因。它查看您奇怪地称为 Python 编译文件的文本文件的开头。该文件以 ASCII 编码字符串“1”开头,uncompyle6 根据特定的format for Python compiled file 进行解释,其中文件的开头包含某种 Python 编码的版本字符串,技术上称为“幻数” .
不过,不要害怕,我已经编写了更多工具来让您更接近您想要到达的地方。具体来说,我写了一个 Python 跨版本的 assembler 来匹配 Python 的内置 disassembler。
这是在我的 github 项目中python-xasm。
使用它,您可以生成可以运行的真正 Python 字节码。如果你写的代码确实像 Python 吐出的东西,它可能可以被反编译回高级 Python。
但是,xasm 目前确实需要比您上面的帮助更多的帮助。具体来说,它不会从操作码名称中猜测它们可以属于哪个 Python 版本。将操作码名称与可接受的 Python 版本匹配比您想象的还要困难。如果您看到LOAD_CONST,您还需要考虑这是指令占用 2 个字节还是 3 个字节。如果为 2,则它是 Python 3.6 或更高版本,否则它是 Python 哪个 Python 解释器。但我假设你不在乎,只要你想出的东西是一致的。
所以有了上面的内容,现在回来解决你的问题。
首先产生真正的字节码。你可以这样做
import py_compile
py_compile.compile("/tmp/test.py", "/tmp/test.pyc", 'exec')
现在不要使用内置的 python 反汇编器,而是使用我编写的跨版本反汇编器,它带有 xdis,称为 pydisasm,并使用 --asm 选项,它将在xasm-友好的方式:
$ pydisasm --asm
# pydisasm version 4.0.0-git
# Python bytecode 3.6 (3379)
# Disassembled from Python 3.6.5 (default, Aug 12 2018, 16:37:27)
# [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)]
# Timestamp in code: 1554492841 (2019-04-05 15:34:01)
# Source code size mod 2**32: 23 bytes
# Method Name: <module>
# Filename: exec
# Argument count: 0
# Kw-only arguments: 0
# Number of locals: 0
# Stack size: 3
# Flags: 0x00000040 (NOFREE)
# First Line: 1
# Constants:
# 0: 1
# 1: 2
# 2: None
# Names:
# 0: a
# 1: b
# 2: print
1:
LOAD_CONST (1)
STORE_NAME (a)
2:
LOAD_CONST (2)
STORE_NAME (b)
3:
LOAD_NAME (print)
LOAD_NAME (a)
LOAD_NAME (b)
BINARY_ADD
CALL_FUNCTION 1
POP_TOP
LOAD_CONST (None)
RETURN_VALUE
请注意文件顶部 cmets 中的所有其他信息,其中包含一些非常神秘的内容,例如“堆栈大小”和“标志”。这个
并且大多数其他内容需要存储在 Python 字节码文件中。
所以把它保存到一个文件中,然后然后你可以把它组装成字节码。然后反编译。
$ ./xasm/xasm_cli.py /tmp/test.pyasm
Wrote /tmp/test.pyc
$ uncompyle6 /tmp/test.pyc
# uncompyle6 version 3.2.6
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.5 (default, Aug 12 2018, 16:37:27)
# [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)]
# Embedded file name: exec
# Compiled at: 2019-04-05 15:34:01
# Size of source mod 2**32: 23 bytes
a = 1
b = 2
print(a + b)
# okay decompiling /tmp/test.pyc
我在哥伦比亚麦德林的 Pycon2018 上发表了与此相关的闪电演讲。很抱歉你错过了,但你可以在这里找到它的视频http://rocky.github.io/pycon2018-light.co
它展示了如何:
- 从 ASCII 编码的 Python 源文本生成 Python 编译文件,
- 修改它以去除尾递归,
- 将其写回 Python 编译文件,然后
- 运行代码。
当然,你不能反编译它,因为 没有 Python 可以轻易地模仿它——它是手工修改的。
最后,您似乎还对字节码和源代码之间的关系感兴趣。所以我会提到 uncompyle6 有选项 --tree 和更详细的 --grammar ,它将显示从 Python 字节码重建 Python 所采取的步骤。