当前位置: 首页 > 面试题库 >

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

羊城
2023-03-14
问题内容

我已经在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:我记得几年前做过同样的观察,但是在经过更深入的研究之后,我再也找不到它了:是否可以反编译.dll /
.pyd文件以提取Python源代码?


问题答案:

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

查看生成的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代码进行逆向工程-
因此,虽然cythonizing可以使代码难以理解,但它不是隐藏密钥或安全算法的正确工具。



 类似资料:
  • 即便你已经用 Babel 编译了你的代码,但这还不算完。 babel-polyfill Babel 几乎可以编译所有时新的 JavaScript 语法,但对于 APIs 来说却并非如此。 比方说,下列含有箭头函数的需要编译的代码: function addAll() { return Array.from(arguments).reduce((a, b) => a + b); } 最终会变成这

  • 问题内容: 我有一个纯Python脚本,我想分发给具有未知Python配置的系统。因此,我想将Python代码编译为独立的可执行文件。 我奔波没有问题。那我跑 哪里给 并给 通过这种方式,我可以获得一个动态链接的可执行文件,该文件可以正常运行。产量 现在,我尝试将选项添加到gcc,但这会导致错误: 我检查了ldd给定的所有共享库是否也都安装为静态库。 那么,这与python3-config提供的选

  • 问题内容: 一直在玩cython。通常使用Python进行编程,但前世曾使用C。我不知道如何制作一个独立的可执行文件。 我已经下载了cython,并可以创建一个.pyx文件(这是一个带有.pyx扩展名的普通Python文件),可以使用以下命令在Python Shell中执行:import pyximport; pyximport.install() 我可以使用以下命令在命令行中生成.c文件:cyt

  • 问题内容: 我需要大致了解一下在高性能数字代码中使用Cython可以获得的性能。我感兴趣的一件事是找出优化的C编译器是否可以向量化Cython生成的代码。因此,我决定编写以下小示例: 我知道有Numpy函数可以完成这项工作,但是我想编写一个简单的代码来了解Cython的功能。事实证明,生成的代码是: 并致电: 生成一个看起来像这样的C代码循环: 此代码的主要问题是,编译器在编译时不知道数组的元素在

  • 情况如下: 在gradle构建期间,我从依赖项下载并解压缩资源 项目中的一个类将处理这些资源,并生成要包含在项目中的新资源(作为生成的资源) 我设法想出了一个简单的解决方案,在“classes”任务之后运行生成器,并将资源写入: 这很好,生成的资源随后包含在JAR中 但是当上传人工制品时,它会上传JAR,而不会上传生成的资源。 我试图用正确的方法来做: 但我最终得到了一个循环依赖,因为Gradle