如果执行未编译的 Python 代码,在使用 Cython 构建的可执行文件中可以看到什么?
What is visible in an executable built with Cython, in case non-compiled Python code is executed?
当我们编写 Cython 代码时(with types),这最终将像 C 编译代码一样被编译,我们无法恢复源代码(除了反汇编,但随后类似于反汇编 C 代码),如 .
所示
但是当我们在 Cython .pyx 文件中编写“正常 Python 代码”(解释代码 没有类型 )并生成可执行文件时会发生什么?其中有多少将在可执行文件的字符串中可见?
示例:
import bottle, random, json
app = bottle.Bottle()
@bottle.route('/')
def index():
return 'hello'
@bottle.route('/random')
def testrand():
return str(random.randint(0, 100))
@bottle.route('/jsontest')
def testjson():
x = json.loads('{ "1": "2" }')
return 'done'
bottle.run()
在这种情况下,我在 test.c
中看到:
static const char __pyx_k_1_2[] = "{ \"1\": \"2\" }";
static const char __pyx_k_json[] = "json";
static const char __pyx_k_main[] = "__main__";
static const char __pyx_k_name[] = "__name__";
static const char __pyx_k_test[] = "__test__";
static const char __pyx_k_loads[] = "loads";
static const char __pyx_k_import[] = "__import__";
static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback";
所以在示例 2 中,所有这些字符串在可执行文件中不是很容易看到吗?
通常,您将无法避免在生成的可执行文件中包含这些字符串,这正是 python 的工作方式 - 在 运行 时需要它们。
如果我们看一个简单的 C-code:
void do_nothing(){...}
int main(){
do_nothing();
return 0;
}
静态编译和link它。 linker 完成后,do_nothing
的调用(假设它没有内联或优化)只是跳转到 memory-address - 函数的名称不再是需要并且可以从生成的可执行文件中删除。
Python 的工作方式不同:没有 linker,我们在 运行 期间不使用原始 memory-addresses 来调用某些功能,而是使用Python-machinery 根据 package/module 和函数的名称为我们找到它 - 因此我们需要这些信息 - 在 运行 时间内的名称。因此必须在 运行 时间内提供。
但是,如果您正在改变所产生的游戏规则 c-file,您可能会使“黑客”的生活变得更加艰难。
当调用Python-functionality需要字符串时,会产生如下代码(如import json
):
static const char __pyx_k_json[] = "json";
static PyObject *__pyx_n_s_json;
static __Pyx_StringTabEntry __pyx_string_tab[] = {
...
{&__pyx_n_s_json, __pyx_k_json, sizeof(__pyx_k_json), 0, 0, 1, 1},
...
{0, 0, 0, 0, 0, 0, 0}
};
static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) {
if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
...
}
...
__pyx_t_1 = __Pyx_Import(__pyx_n_s_json, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
所以可以将 "json"
保存为 "irnm"
(每个字符移动 -1),然后在调用 __Pyx_InitStrings
之前的 运行 时间内恢复真实姓名在 __Pyx_InitGlobals
.
所以现在,只要将字符串转储到 exe 中,就不会出现字符组合。如果值得的话,甚至可以更进一步,在程序启动后从某处加载真实姓名。
当我们编写 Cython 代码时(with types),这最终将像 C 编译代码一样被编译,我们无法恢复源代码(除了反汇编,但随后类似于反汇编 C 代码),如
但是当我们在 Cython .pyx 文件中编写“正常 Python 代码”(解释代码 没有类型 )并生成可执行文件时会发生什么?其中有多少将在可执行文件的字符串中可见?
示例:
import bottle, random, json
app = bottle.Bottle()
@bottle.route('/')
def index():
return 'hello'
@bottle.route('/random')
def testrand():
return str(random.randint(0, 100))
@bottle.route('/jsontest')
def testjson():
x = json.loads('{ "1": "2" }')
return 'done'
bottle.run()
在这种情况下,我在 test.c
中看到:
static const char __pyx_k_1_2[] = "{ \"1\": \"2\" }";
static const char __pyx_k_json[] = "json";
static const char __pyx_k_main[] = "__main__";
static const char __pyx_k_name[] = "__name__";
static const char __pyx_k_test[] = "__test__";
static const char __pyx_k_loads[] = "loads";
static const char __pyx_k_import[] = "__import__";
static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback";
所以在示例 2 中,所有这些字符串在可执行文件中不是很容易看到吗?
通常,您将无法避免在生成的可执行文件中包含这些字符串,这正是 python 的工作方式 - 在 运行 时需要它们。
如果我们看一个简单的 C-code:
void do_nothing(){...}
int main(){
do_nothing();
return 0;
}
静态编译和link它。 linker 完成后,do_nothing
的调用(假设它没有内联或优化)只是跳转到 memory-address - 函数的名称不再是需要并且可以从生成的可执行文件中删除。
Python 的工作方式不同:没有 linker,我们在 运行 期间不使用原始 memory-addresses 来调用某些功能,而是使用Python-machinery 根据 package/module 和函数的名称为我们找到它 - 因此我们需要这些信息 - 在 运行 时间内的名称。因此必须在 运行 时间内提供。
但是,如果您正在改变所产生的游戏规则 c-file,您可能会使“黑客”的生活变得更加艰难。
当调用Python-functionality需要字符串时,会产生如下代码(如import json
):
static const char __pyx_k_json[] = "json";
static PyObject *__pyx_n_s_json;
static __Pyx_StringTabEntry __pyx_string_tab[] = {
...
{&__pyx_n_s_json, __pyx_k_json, sizeof(__pyx_k_json), 0, 0, 1, 1},
...
{0, 0, 0, 0, 0, 0, 0}
};
static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) {
if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
...
}
...
__pyx_t_1 = __Pyx_Import(__pyx_n_s_json, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
所以可以将 "json"
保存为 "irnm"
(每个字符移动 -1),然后在调用 __Pyx_InitStrings
之前的 运行 时间内恢复真实姓名在 __Pyx_InitGlobals
.
所以现在,只要将字符串转储到 exe 中,就不会出现字符组合。如果值得的话,甚至可以更进一步,在程序启动后从某处加载真实姓名。