可以从脚本执行Python字节码吗?

ide*_*n42 6 cpython python-3.x

假设我有一个正在运行的CPython会话,

有没有办法直接bytespyc文件中运行data()? (必须没有磁盘上的数据,而不必编写临时的pyc文件)

显示简单用例的示例脚本:

if foo:
    data = read_data_from_somewhere()
else:
    data = open("bar.pyc", 'rb').read()

assert(type(data) is bytes)

code = bytes_to_code(data)

# call a method from the loaded code
code.call_function()
Run Code Online (Sandbox Code Playgroud)

确切的使用并不重要,但动态生成代码并通过网络复制执行是一个用例(为了考虑这个问题).


以下是一些示例用例,这让我很想知道如何做到这一点:

  • 检查Python脚本是否存在恶意代码.
    如果单个命令可以访问隐藏在二进制数据中的更大代码,那么该命令会是什么样的?
  • 动态生成代码并将其缓存以供重用(不一定在磁盘上,例如可以使用数据库).
  • 能够将预编译的字节码发送到进程,控制嵌入Python的应用程序.

Tho*_*mas 8

有没有办法直接从pyc文件运行数据?

可以使用保存已编译的代码对象 marshal

import marshal
bytes = marshal.dumps(eggs)
Run Code Online (Sandbox Code Playgroud)

字节可以转换回代码对象

eggs = marshal.loads(bytes)
exec(eggs)
Run Code Online (Sandbox Code Playgroud)

pyc文件是具有报头一封代码对象

对于Python3,标题是需要跳过的12个字节,其余数据可以通过读取marshal.loads.


Ned Batchelder的博文:

在简单级别,.pyc文件是一个二进制文件,只包含三件事:

  • 一个四字节的幻数,
  • 一个四字节的修改时间戳,和
  • 编组的代码对象.

注意,链接引用Python2,但它在Python3中几乎相同,pyc标头大小只有12而不是8字节.