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

2022-04-16 00:00:00 python reverse-engineering bytecode

问题描述

有没有办法通过dis.dis获取的反汇编来创建代码对象?

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


解决方案

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

但是,您需要了解一些注意事项。第一点需要注意的是,每个发行版的Python字节码和汇编指令都会有所不同。要理解的第二个警告是,dis.dis()以文本形式发出的信息相对于Python解释器所需的信息是不完整的。因此,您需要以某种方式填充缺失的信息。

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

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

中完成的

若要了解代码对象中的内容与其如何适应Python字节码文件之间的区别,我将使用您的示例,然后介绍如何创建字节码文件。

如果我在Python3.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的下一个版本之前,Python3.7和更高版本不能运行,但3.6和更早版本可以。

相关文章