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

Posted

技术标签:

【中文标题】将 python 反汇编从 dis.dis 转换回 codeobject【英文标题】:Convert python disassembly from dis.dis back to codeobject 【发布时间】:2019-11-11 00:52:10 【问题描述】:

有什么方法可以通过dis.dis 获得的反汇编创建代码对象?

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

【问题讨论】:

dis.dis 以人类可读的形式反汇编字节码。它是用来阅读的,而不是用来行动的。 (dis.dis 进行打印,并返回 None)。 @heemayl,问题是是否可以重新组装这种人类可读的形式。我理解dis.dis的目的。 【参考方案1】:

令人惊讶的是,确实有 - 有点。

但是,您需要了解一些注意事项。第一个警告是 Python 字节码以及扩展的汇编指令可以更改每个版本。要理解的第二个警告是,就 Python 解释器的需求而言,dis.dis() 以文本形式发出的信息是不完整的。所以你需要一种方法来以某种方式填写缺失的信息。

我写了一个bytecode assembler,它将一个类似于你上面的文本文件程序集转换成一个python字节码。

在您的示例中,您有一个代码对象,而不是创建字节码文件所需的全部信息,但xasm 的内容当然会在将代码对象与字节码文件中所需的其他信息一起写出之前创建代码对象。这是在 https://github.com/rocky/python-xasm/blob/master/xasm/assemble.py 的函数 create_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

但如果我将你的 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

请注意,在字节码文件中,有一些额外的信息并不在严格的代码对象中:

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

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

  $ pyc-xasm foo2.pyasm
  Wrote foo2.pyc
  $ python foo2.pyc
  lol

我在2018 lighting talk at PyColumbia 2018 中演示了所有这些

我应该注意,在xasmxdis 的下一个版本之前,Python 3.7 及更高版本不起作用,但 3.6 及更早版本可以。

【讨论】:

令人印象深刻,但问题意味着只有 dis.dis 输出可用,不是代码对象甚至是用另一个工具反汇编它的源。这种方法是否也适用于裸 dis.dis 输出? 是的,确实如此 - 有点。我试图传达的一件事是dis.dis() 提供的信息本身并不完整,需要了解更多内容才能运行。特别是您需要知道传递给代码对象的参数、代码标志、所需的最大堆栈等等。函数 create_code() github.com/rocky/python-xasm/blob/… 是只处理代码对象的部分。

以上是关于将 python 反汇编从 dis.dis 转换回 codeobject的主要内容,如果未能解决你的问题,请参考以下文章

Python使用Python将Shellcode转换成汇编

我们可以将十六进制文件转换回 .c 文件吗?

Python 对象的序列和反序列化

汇编与反汇编工具

ida pro能反汇编成c语言吗

P3345 [ZJOI2015]幻想乡战略游戏