将 python 反汇编从 dis.dis 转换回 codeobject

pom*_*nto 6 python bytecode reverse-engineering

有什么方法可以从使用 获得的反汇编中创建代码对象吗dis.dis

例如,我使用编译了一些代码co = compile('print("lol")', '<string>', 'exec'),然后使用打印反汇编dis.dis(co),现在我想将反汇编“编译”回代码对象(因为它保存所有相同的数据并且没有丢失任何内容)。

roc*_*cky 5

令人惊讶的是,是的——有点。

但是,您需要了解许多注意事项。第一个需要注意的是,Python 字节码以及扩展的汇编指令可以更改每个版本。第二个需要理解的警告是,仅以文本形式发出的信息dis.dis()对于 Python 解释器的需要来说是不完整的。因此,您需要一种方法来填补缺失的信息。

我编写了一个字节码汇编器,它将类似于上面的文本文件程序集转换为 python 字节码。

在您的示例中,您有一个代码对象,而不是创建字节码文件所需的完整信息,但在使用xasm字节码文件中所需的附加信息将其写出之前,当然会创建代码对象。这是在https://github.com/rocky/python-xasm/blob/master/xasm/assemble.pycreate_code()的函数中完成的

为了了解代码对象中的内容以及它如何适合 Python 字节码文件之间的区别,我将使用您的示例,然后完成如何创建字节码文件。

如果我在 Python 3.6.10 中运行你的示例,我会得到:

  1           0 LOAD_NAME                0 (print)
              2 LOAD_CONST               0 ('lol')
              4 CALL_FUNCTION            1
              6 POP_TOP
              8 LOAD_CONST               1 (None)
             10 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

但是,如果我将你的Python代码放入一个文件中,比如说foo.py,使用字节编译它py_compile.compile(source, bytecode, source)并使用xdis的跨版本Python反汇编程序,pydisasm我得到:

  # pydisasm version 4.2.4
  # Python bytecode 3.6 (3379)
  # Disassembled from Python 3.6.10 (default, Jan 23 2020, 16:43:38) 
  # [GCC 7.4.0]
  # Timestamp in code: 1586703495 (2020-04-12 10:58:15)
  # Source code size mod 2**32: 13 bytes
  # Method Name:       <module>
  # Filename:          foo.py
  # Argument count:    0
  # Kw-only arguments: 0
  # Number of locals:  0
  # Stack size:        2
  # Flags:             0x00000040 (NOFREE)
  # First Line:        1
  # Constants:
  #    0: 'lol'
  #    1: None
  # Names:
  #    0: print
    1:           0 LOAD_NAME                 0 (print)
                 2 LOAD_CONST                0 ('lol')
                 4 CALL_FUNCTION             1
                 6 POP_TOP
                 8 LOAD_CONST                1 (None)
                10 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

请注意,在字节码文件中,有一些严格意义上不属于代码对象的附加信息:

  • 正在使用哪个字节码(3.6,幻数 3379),
  • 创建代码的时间戳,
  • 源代码的大小 (mod 2**32),
  • 方法名称,
  • 一个文件名,
  • 代码的参数,
  • 方法标志,以及
  • 各种名称:常量、变量。

现在让我们把它放到一个像foo2.pyasm. 要将其写入字节码文件,只需运行pyc-xasm

  $ pyc-xasm foo2.pyasm
  Wrote foo2.pyc
  $ python foo2.pyc
  lol
Run Code Online (Sandbox Code Playgroud)

我在PyColumbia 2018 的 2018 年照明演讲中演示了所有这一切

xasm我应该指出,在和的下一个版本之前xdis,Python 3.7 及更高版本无法工作,但 3.6 及更早版本可以。