Python 3反编译器
项目描述
pygetsource
pygetsource
是一个Python 3的反编译器,旨在将编译后的字节码指令转换回Python代码。
概述
当Python读取代码时,它首先将指令转换为字节码。例如
a = 2
转换为
LOAD_CONST 1
STORE_FAST 0
后者通常存储在 .pyc
文件中以及函数对象的 __code__
属性中。 pygetsource
的目标是反转此过程。
该项目名称来源于 inspect.getsource
函数,该函数返回函数的源代码,但如上所述,它并不总是适用。
pygetsource
仍在开发中。它应该能够从Python 3.7到Python 3.11的各种程序中恢复简单函数的源代码。它尚不能恢复类的源代码、导入语句、try/except/match/with块,并且不支持Python 2。虽然功能齐全,但代码库尚未优化,需要进行重大重构。
最后,此软件在MIT许可证下分发。
安装
使用pip安装包
pip install pygetsource
用法
import pygetsource
def func():
a = 5
while i < 10:
if a == 2:
break
elif a == 4:
return 3
a = i // 5
d = 3
e = 4
return e + d
print(pygetsource.getsource(func.__code__))
产生以下输出
a = 5
while i < 10:
if a == 2:
break
elif a == 4:
return 3
else:
a = i // 5
d = 3
e = 4
return e + d
注意如何将 else
语句添加到 elif
语句中,但两个程序在功能上是等效的。
什么时候这很有用?
pygetsource
在需要从 .pyc
文件恢复源代码,或者想要获取通过 eval 语句或 lambda 语法创建的函数的源代码时很有用。实际上,在后者的情况下,由于函数的原始文件不可用,或者 Python 不提供所需的精确边界,运行 inspect.getsource
会失败,尤其是在 lambda 函数的情况下。
替代方案
uncompyle6 是一个支持 Python 2 和 3(至 Python 3.8)的 Python 反编译器。它使用基于语法的途径通过字节码模式重建代码。对于引入了各种字节码优化(特别是关于复杂控制结构,如循环或上述示例)的高级版本,这种方法效果较差。目前,它支持更广泛的 Python 语法(如 with 块或 try/except)。它还根据 copyleft GPL 许可证授权,使得它对于具有宽松许可证的大型项目不太合适。
decompyle++ (pycdc) 使用状态机方法通过处理字节码指令迭代地构建 AST。它是用 C++ 编写的,支持比 uncompyle6 更多的 Python 版本,但在反编译复杂控制结构(如嵌套循环、break 模式、列表推导或上述示例)方面有更多问题。它还使用 copyleft GPL 许可证。
它是如何工作的?
pygetsource
使用一种独特的方法。首先将字节码指令转换为表示程序流程的有向图。然后迭代地减少此图,根据其操作码、参数和位置处理每个节点,并在过程中生成 AST。这种方法允许我们在重新创建复杂结构(如嵌套循环或 break/return 语句)时更多地依赖于高级模式,而较少依赖于 Python 的特性,并能够使用相同的代码库处理从 3.7 到 3.11 的 Python 版本。
与 uncompyle6 和 pycdc 不同,pygetsource
使用 ast
和 astunparse
库从生成的 AST 生成源代码。
以下是一个图被减少的示例
反编译何时成功?
由于编译过程是注入的,因此无法恢复确切的原始源代码。多个 Python 程序可以产生相同的字节码指令。此外,原始源代码通常不可用于比较(否则你会使用这个软件做什么?)。
如果我们重新编译生成的程序,我们可以比较两组字节码指令以确保功能等效。然而,Python 可能会引入无操作码(如 'NOP'),这可能导致验证失败,尽管两个代码对象在功能上是等效的。
相反,pygetsource
在修剪步骤后比较原始代码对象的图与恢复的代码对象的图。在此步骤中,删除了无操作码,修剪了跳转指令(同时保持源节点和目标节点之间的边),并消除了死代码。
贡献
欢迎贡献。请随意打开一个问题或提交一个 pull 请求。与反编译过程相关的任何问题都应包括生成字节码所使用的 Python 解释器的版本、函数的源代码以及由 dis.dis(code)
打印的字节码指令。
要在开发模式下安装项目,请克隆仓库并在根目录下运行 pip install -e '.[dev]'
。然后,您可以使用 pytest
运行测试。请确保首先安装了 graphviz
。如果您在 MacOS 上遇到 Python 的 pygraphviz
包问题,请尝试使用以下命令安装:
pip install \
--global-option=build_ext \
--global-option="-I$(brew --prefix graphviz)/include/" \
--global-option="-L$(brew --prefix graphviz)/lib/" \
pygraphviz
要检查失败案例,请使用 getsource
函数的 debug=True
参数。这将显示在缩减过程的各个阶段中的图,以及各种调试信息。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源分发
构建分发
pygetsource-0.3.0.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 12afe0ae8169f5118b7db0424af84214bdb53bf0cc5d9ec22ccd9f368b650394 |
|
MD5 | a6eca5a53974ed664affbb3f7da62927 |
|
BLAKE2b-256 | dea0e74bf873d8458a6772be17545038c6eea24b58b9a5e56a1caf4272307661 |
pygetsource-0.3.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | bc257afe9907ef6723b259848bf80a23b227964c26cde1663a1ecd6430016be8 |
|
MD5 | c3d4e2f59c4f3c944b0973183a11bbd6 |
|
BLAKE2b-256 | 2c29a053039e58f750e00291158218cde2d08624f1d1e2f582ab8599ebad57f8 |