Действительно ли исполняемые файлы, созданные с помощью Cython, свободны от исходного кода?

Я прочитал " Создание исполняемого файла в Cython" и ответ BuvinJ на вопрос " Как эффективно запутать код Python?" и хотел бы проверить, действительно ли исходный код, скомпилированный с помощью Cython, "больше не существует" после компиляции. Действительно, популярно мнение, что использование Cython - это способ защиты исходного кода Python, см., Например, статью Защита источников Python с помощью 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!

Тогда воспользуемся 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

Оно работает! Он производит 140 КБ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?

1 ответ

Решение

Код находится в исходном pyx-файле рядом с вашим exe. Удалите / не распространяйте этот 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 байт-код не требуется, потому что результирующий код напрямую использует C-API Python, что исключает необходимость иметь / оценивать коды операций - эти модули пропускают интерпретацию, что является причиной их большей скорости. Таким образом, в исполняемом файле не будет байт-кода.

Одно важное замечание: следует убедиться, что компоновщик не включает отладочную информацию (и, следовательно, C-код, в котором содержимое pyx-файла можно найти в виде комментариев). MSVC с/Z7 options является таким примером.


Однако полученный исполняемый файл может быть разобран на ассемблер, а затем сгенерированный C-код может быть подвергнут обратному проектированию - так что, хотя цитонизация подходит для затруднения понимания кода, это не тот инструмент, который позволяет скрывать ключи или алгоритмы безопасности.

Другие вопросы по тегам