用 Cython 生成的可执行文件真的没有源代码吗?

Bas*_*asj 17 python cython

我已阅读在 Cython 中制作可执行文件和 BuvinJ 对如何有效地混淆 Python 代码的回答并想测试编译后用 Cython 编译的源代码是否真的“不再存在”。确实流行使用 Cython 是一种保护 Python 源代码的方法,例如参见文章Protecting Python Sources With Cython

让我们以这个简单的例子为例test.pyx

import json, time  # this will allow to see what happens when we import a library
print(json.dumps({'key': 'hello world'}))
time.sleep(3)
print(1/0)  # division error!
Run Code Online (Sandbox Code Playgroud)

然后让我们使用 Cython:

cython test.pyx --embed
Run Code Online (Sandbox Code Playgroud)

这会产生一个test.c. 让我们编译它:

call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
cl test.c /I C:\Python37\include /link C:\Python37\libs\python37.lib
Run Code Online (Sandbox Code Playgroud)

有用!它生成了一个 140KB 的test.exe可执行文件,不错!

但是在这个答案中如何有效地混淆 Python 代码?据说这个“编译”会隐藏源代码。这似乎不是真的,如果你运行test.exe,你会看到:

Traceback (most recent call last):
  File "test.pyx", line 4, in init test
    print(1/0)  # division error!         <-- the source code and even the comments are still there!
ZeroDivisionError: integer division or modulo by zero
Run Code Online (Sandbox Code Playgroud)

这表明人类可读形式的源代码仍然存在

问题:有没有办法用 Cython 编译代码,这样“源代码不再公开”的说法是正确的?

注意:我正在寻找一种既不存在源代码也不存在字节码 (.pyc) 的解决方案(如果嵌入了字节码/.pyc,则使用uncompyle6恢复源代码很简单


PS:我记得我几年前做过同样的观察,但我找不到了,经过深入研究后,这里是:是否可以反编译 .dll/.pyd 文件以提取 Python 源代码?

ead*_*ead 15

该代码位于 exe 旁边的原始 pyx 文件中。删除/不要使用您的 exe 分发此 pyx 文件。


当您查看生成的 C 代码时,您将了解为什么您的可执行文件会显示错误消息:

对于引发的错误,Cython 将发出类似于以下内容的代码:

__PYX_ERR(0, 11, __pyx_L3_error) 
Run Code Online (Sandbox Code Playgroud)

其中__PYX_ERR是一个宏定义为:

#define __PYX_ERR(f_index, lineno, Ln_error) \
{ \
  __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \
}
Run Code Online (Sandbox Code Playgroud)

变量__pyx_f定义为

static const char *__pyx_f[] = {
  "test.pyx",
  "stringsource",
};
Run Code Online (Sandbox Code Playgroud)

基本上__pyx_f[0]告诉在哪里可以找到原始代码。现在,当引发异常时,(嵌入式)Python 解释器会查找您的原始 pyx 文件并找到相应的代码(可以在__Pyx_AddTraceback其中查找在引发错误时调用的代码)。

一旦这个 pyx 文件不存在,原始源代码将不再为 Python 解释器/其他任何人所知。但是,错误跟踪仍将显示函数名称和行号,但不再显示任何代码片段。

生成的可执行文件(或扩展名,如果创建了一个)不包含任何字节码(如在 pyc 文件中)并且不能使用以下工具进行反编译uncompyle:当 py 文件被转换为 Python 操作码时,会生成字节码,然后在中的一个巨大循环ceval.c。然而,对于内置/cython 模块,不需要字节码,因为生成的代码直接使用 Python 的 C-API,无需拥有/评估操作码——这些模块跳过解释,这是它们更快的原因。因此,可执行文件中不会有字节码。

一个重要的注意事项:应该检查链接器是否不包含调试信息(因此可以在其中找到 pyx 文件内容作为注释的 C 代码)。带有/Z7选项的MSVC就是一个例子。


但是,生成的可执行文件可以反汇编为汇编程序,然后可以对生成的 C 代码进行逆向工程 - 因此,虽然 cythonizing 可以使其难以理解代码,但它不是隐藏密钥或安全算法的正确工具。