跳转到主要内容

Python跨版本字节码反汇编器和打包程序

项目描述

PyPI Installs Latest Version Supported Python Versions

Packaging Status

xdis

一个跨Python字节码反汇编器,字节码/wordcode和魔术数字操作库/包。

简介

Python dis 模块允许您从与您运行的Python相同版本的Python反汇编字节码。但不同版本的字节码怎么办呢?

这正是这个包的目的。它可以“打包加载”不同版本的Python的字节码。命令行程序 pydisasm 将使用用户指定的各种格式显示使用最现代Python反汇编约定的反汇编输出。其中一些格式(如“extended”和“extended-format”)是我所知的任何Python反汇编器中最先进的,因为它们可以显示操作符的表达式树。请参阅下面的[反汇编器示例][#disassembler-example]。

此外,如果您需要修改和编写字节码,这里提供的例程可以帮助您。这里提供了打包和解包 Python 代码类型中的只读元组的例程。为了实现多年来 Python CodeType 变更的互操作性,我们提供了自己的 Code 类型版本以允许互操作性,并提供了一些减少编写字节码文件繁琐性的例程。

此包还广泛了解 Python 字节码魔术数字,包括 PyPy 等,以及如何将 sys.sys_info 的主要、次要和发布号转换为相应的魔术值。

因此,如果您想编写跨版本汇编器、字节码级分析器或优化器,此包也可能很有用。除了 dis 提供的指令分类之外,我们还有一些在字节码汇编器、优化器或反汇编器中可能有用的额外类别。

这里提供的程序接受从 Python 1.0 到 3.11 或左右的版本的字节码。该代码需要 Python 2.4 或更高版本,并在运行多个 Python 版本的 Python 上进行了测试。

在安装时,除了最新的 Python 版本外,请使用与该版本匹配的 Python egg 或 wheel,例如 xdis-6.0.2-py3.3.eggxdis-6.0.2-py33-none-any.whl。当然,对于像 Python 2.6 这样的 wheel 之前的版本,您将不得不使用 eggs。

要使用 git 从源代码安装旧版本,请使用分支 python-2.4-to-2.7 以处理 2.4 到 2.7 的 Python 版本,python-3.1-to-3.2 以处理 3.1 到 3.2 的 Python 版本,python-3.3-to-3.5 以处理 3.3 到 3.5 的 Python 版本。主分支处理 3.6 及以后的 Python 版本。

安装

标准 Python 例程

$ pip install -e .
$ pip install -r requirements-dev.txt

还提供了一个 GNU makefile,以便 make install(可能作为 root 或 sudo 执行)将执行上述步骤。

反汇编器示例

这里打包的跨版本反汇编器可以生成优于 Python dis 模块中通常找到的汇编列表。以下是一个示例:

pydisasm -S -F extended bytecode_3.8/pydisasm-example.pyc
# pydisasm version 6.1.1.dev0
# Python bytecode 3.8.0 (3413)
# Disassembled from Python 3.11.8 (main, Feb 14 2024, 04:47:01) [GCC 13.2.0]
# Timestamp in code: 1693155156 (2023-08-27 12:52:36)
# Source code size mod 2**32: 320 bytes
# Method Name:       <module>
# Filename:          simple_source/pydisasm-example.py
# Argument count:    0
# Position-only argument count: 0
# Keyword-only arguments: 0
# Number of locals:  0
# Stack size:        3
# Flags:             0x00000040 (NOFREE)
# First Line:        4
# Constants:
#    0: 0
#    1: None
#    2: ('version_info',)
#    3: 1
#    4: (2, 4)
#    5: 'Is small power of two'
# Names:
#    0: sys
#    1: version_info
#    2: print
#    3: version
#    4: len
#    5: major
#    6: power_of_two
             # import sys
  4:           0 LOAD_CONST           (0) ; TOS = 0
               2 LOAD_CONST           (None) ; TOS = None
               4 IMPORT_NAME          (sys) ; TOS = import_module(sys)
               6 STORE_NAME           (sys) ; sys = import_module(sys)

             # from sys import version_info
  5:           8 LOAD_CONST           (0) ; TOS = 0
              10 LOAD_CONST           (('version_info',)) ; TOS = ('version_info',)
              12 IMPORT_NAME          (sys) ; TOS = import_module(sys)
              14 IMPORT_FROM          (version_info) ; TOS = from sys import version_info
              16 STORE_NAME           (version_info) ; version_info = from sys import version_info
              18 POP_TOP

             # print(sys.version)
  7:          20 LOAD_NAME            (print) ; TOS = print
              22 LOAD_NAME            (sys) ; TOS = sys
              24 LOAD_ATTR            (version) ; TOS = sys.version
              26 CALL_FUNCTION        (1 positional argument) ; TOS = print(sys.version)
              28 POP_TOP

             # print(len(version_info))
  8:          30 LOAD_NAME            (print) ; TOS = print
              32 LOAD_NAME            (len) ; TOS = len
              34 LOAD_NAME            (version_info) ; TOS = version_info
              36 CALL_FUNCTION        (1 positional argument) ; TOS = len(version_info)
              38 CALL_FUNCTION        (1 positional argument) ; TOS = print(len(version_info))
              40 POP_TOP

             # major = sys.version_info[0]
  9:          42 LOAD_NAME            (sys) ; TOS = sys
              44 LOAD_ATTR            (version_info) ; TOS = sys.version_info
              46 LOAD_CONST           (0) ; TOS = 0
              48 BINARY_SUBSCR        TOS = sys.version_info[0]
              50 STORE_NAME           (major) ; major = sys.version_info[0]

             # power_of_two = major & (major - 1)
 10:          52 LOAD_NAME            (major) ; TOS = major
              54 LOAD_NAME            (major) ; TOS = major
              56 LOAD_CONST           (1) ; TOS = 1
              58 BINARY_SUBTRACT      TOS = major - (1)
              60 BINARY_AND           TOS = major & (major - (1))
              62 STORE_NAME           (power_of_two) ; power_of_two = major & (major - (1))

             # if power_of_two in (2, 4):
 11:          64 LOAD_NAME            (power_of_two) ; TOS = power_of_two
              66 LOAD_CONST           ((2, 4)) ; TOS = (2, 4)
              68 COMPARE_OP           (in) ; TOS = power_of_two in ((2, 4))
              70 POP_JUMP_IF_FALSE    (to 80)

             # print("Is small power of two")
 12:          72 LOAD_NAME            (print) ; TOS = print
              74 LOAD_CONST           ("Is small power of two") ; TOS = "Is small power of two"
              76 CALL_FUNCTION        (1 positional argument) ; TOS = print("Is small power of two")
              78 POP_TOP
         >>   80 LOAD_CONST           (None) ; TOS = None
              82 RETURN_VALUE         return None

在上面的示例中,请注意对堆栈中的项目执行了一些操作数解释。例如,在

24 LOAD_ATTR            (version) | sys.version

从指令中可以看到 sys.version 是加载的解析属性。

同样在

68 COMPARE_OP           (in) | power_of_two in (2, 4)

中,我们看到我们可以解析 in 操作的两个参数。最后,在某些 CALL_FUNCTIONS 中,我们可以确定函数的名称以及传递给它的参数。

测试

$ make check

添加了一个 GNU makefile,以简化设置运行正确命令,并按从快到慢的顺序运行测试。

如果您已安装 remake,您可以通过 remake --tasks 查看包括测试在内的所有任务列表。

用法

运行

$ ./bin/pydisasm -h

获取用法帮助。

作为 dis 的替代品

xdis 还提供了一些支持,作为 Python 库 dis 模块的替代品。当您想从较旧的 Python 版本中使用 Python 3.4 或更高版本的改进 API 时,这可能很有用。

例如

>>> # works in Python 2 and 3
>>> import xdis.std as dis
>>> [x.opname for x in dis.Bytecode('a = 10')]
['LOAD_CONST', 'STORE_NAME', 'LOAD_CONST', 'RETURN_VALUE']

对于格式化反汇编或如何显示编译器标志,输出可能存在一些细微差异。但我们期望您会发现 xdis 的输出更具信息量。

另请参阅

发布历史 发布通知 | RSS 源

下载文件

下载适用于您平台的应用文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

xdis-6.1.1.tar.gz (425.1 kB 查看哈希值)

上传时间 源代码

构建分发

xdis-6.1.1-py312-none-any.whl (183.7 kB 查看哈希值)

上传时间 Python 3.12

xdis-6.1.1-py311-none-any.whl (176.7 kB 查看哈希值)

上传时间 Python 3.11

xdis-6.1.1-py310-none-any.whl (201.1 kB 查看哈希值)

上传时间 Python 3.10

xdis-6.1.1-py2-none-any.whl (196.0 kB 查看哈希值)

上传时间 Python 2

支持者