Cython生成的可执行文件是否真的不包含源代码?

22
我已经阅读了如何在Cython中创建可执行文件和BuvinJ对如何有效地混淆Python代码?的回答,并想测试使用Cython编译后源代码是否真的“不存在”了。 实际上,使用Cython保护Python源代码是一种流行的观点,例如 用Cython保护Python源代码一文。
我们以这个简单的例子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!

那么让我们使用Cython:

cython test.pyx --embed

这会生成一个名为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

没问题!它生成了一个大小为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

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

问题:有没有一种通过Cython编译代码的方法,使得声明“源代码不再被揭示”成立?

注意:我正在寻找一种既没有源代码也没有字节码(.pyc)的解决方案(如果嵌入了字节码/.pyc,则使用uncompyle6可以轻松恢复源代码)。


PS:我记得几年前我做了同样的观察,但我找不到它了,在更深入的研究后,它在这里:Is it possible to decompile a .dll/.pyd file to extract Python Source Code?


1
请注意,即使代码被“混淆”,最多也只是被翻译成另一种语言,例如机器语言。仍然完全有可能从编译后的代码中反向工程出逻辑和所有值——因为该代码需要执行您告诉它要执行的操作。 - deceze
2
@deceze 这是真的,但是“这里是机器语言代码,你可能可以反向工程它”和“这里是原始源文件和原始注释!”之间仍然存在很大的差异! - Basj
我认为问题在于您的exe文件旁边有一个pyx文件。如果您删除/重命名它,Python将不再找到该代码。如果我没记错的话,一定有一个重复的地方... - ead
我还建议使用cythonize -i test.pyx使用的编译器/链接器标志(它将记录在控制台中) - ead
2
其中一个应该被关闭为重复。我个人认为这个问题有稍微更好的答案(因此另一个问题应该被关闭,尽管它更早)。 - DavidW
1个回答

25

代码可以在您的exe旁边的原始pyx文件中找到。删除/不要将此pyx文件与您的exe一起分发。


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

对于引发的错误,Cython将生成类似以下代码:

__PYX_ERR(0, 11, __pyx_L3_error) 

其中__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; \
}

并且变量__pyx_f被定义为

static const char *__pyx_f[] = {
  "test.pyx",
  "stringsource",
};

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

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

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

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


然而,生成的可执行文件可以反汇编为汇编语言,然后生成的C代码可以被反向工程-因此,尽管使用cython使代码难以理解是可以的,但它并不是隐藏密钥或安全算法的正确工具。


再次感谢@ead提供的精彩答案。在特定情况下,我们编写“普通的Python代码”(不带类型,因此不需要Cython编译),然后使用Cython生成exe文件,会发生什么?这是一个关于此问题的问题:https://dev59.com/E7v4oIgBc1ULPQZFkXqc - Basj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接