- Регистрация
- Окт 16, 2022
- Сообщения
- 1,233
- Реакции
- 214
- Награды
- 2
Есть ли все-таки методы защиты исходников на python, и какие (относительно вменяемые) методы можно применять для решения этого вопроса?
Заходят как-то в бар .pyo, .pyc, и .pyd…
…а бармен им говорит "как дела в байт-коде, пацаны?"
Перед тем, как разобраться в методах защиты исходных кодов, вспомним как устроено выполнение скриптов в Python.
Реализация Python (в классическом случае это CPython), представляет собой компилятор и виртуальную машину. Скрипт, написанный на Python, преобразуется компилятором в байт-код, коий, в свою очередь, выполняется виртуальной машиной.
Байт-код же состоит из кодов операций (опкодов) виртуальной машины, и сопутствующих опкоду аргументов.
.py-файлы содержат исходный код, и выполняются виртуальной машиной, проходя этап преобразования в байт-код.
Однако, можно каждый раз не преобразовывать .py-файлы в байт-код, да и зачем, если они, например, не меняются? Для хранения и выполнения байт-кода служат .pyc-файлы (их можно, например, наблюдать в директориях __pycache__).
.pyc-файлы содержат готовый байт-код, непосредственно выполняемый виртуальной машиной.
.pyo-файлы также как и .pyc-файлы содержат готовый байт-код, и, по-сути ничем, кроме предварительной оптимизации кода (вырезание assert`ов и docstring`ов) не отличаются.
Кроме хранения байт-кода для виртуальной машины возможен сценарий, при котором исходный код на Python преобразуется в исходный код на языке C, и затем собирается в .pyd-файлы (для Windows) или .so для Linux.
А вот в наше время…
Вы когда-нибудь задумывались, почему на Python не делают crackmes? Вроде бы можно взять скрипт, преобразовать его в байт-код и…с той же легкостью преобразовать обратно в исходный код, каким-нибудь uncompyle. Да и отладка Python-скрипта - дело не сказать что очень сложное. Однако crackmes на python, хоть их и кот наплакал, но все же существуют.
Делятся они приблизительно на следующие группы:
Modus operandi
Зная основную теорию, можно выдвинуть ряд гипотез о точках внедрения защитных механизмов:
Однако обфускация, как процесс изменения исходного кода, может в том числе приводить к изменениям в работе алгоритмов, например в быстродействии, что не есть хорошо.
Единственным методом защиты на данном этапе может быть рекомендация писать настолько некачественный код, чтобы его модификация вошла в число опасных БДСМ-практик.
Структура .pyc-файла достаточно проста:
Для решения задачи невозможности декомпиляции байт-кода так или иначе придется модифицировать используемую реализацию Python, по-сути создавая кастомизированную версию виртуальной машины, поддерживающую привидение байт-кода к выполнимому виду.
Запутать байт-код можно, применяя следующие техники:
Сама сборка .py-файла в библиотеку производится с помощью cython, и достаточно нетривиальна. В результате мы имеем код, который не имеет вообще ничего общего с изначальным исходным кодом, и декомпилирован быть не может (только дизассемблирован и исследован, в результате чего можно делать выводы об алгоритмах и особенностях кода).
Источник: https://habr.com/ru/company/otus/blog/682872/
Заходят как-то в бар .pyo, .pyc, и .pyd…
…а бармен им говорит "как дела в байт-коде, пацаны?"
Перед тем, как разобраться в методах защиты исходных кодов, вспомним как устроено выполнение скриптов в Python.
Реализация Python (в классическом случае это CPython), представляет собой компилятор и виртуальную машину. Скрипт, написанный на Python, преобразуется компилятором в байт-код, коий, в свою очередь, выполняется виртуальной машиной.
Байт-код же состоит из кодов операций (опкодов) виртуальной машины, и сопутствующих опкоду аргументов.
.py-файлы содержат исходный код, и выполняются виртуальной машиной, проходя этап преобразования в байт-код.
Однако, можно каждый раз не преобразовывать .py-файлы в байт-код, да и зачем, если они, например, не меняются? Для хранения и выполнения байт-кода служат .pyc-файлы (их можно, например, наблюдать в директориях __pycache__).
.pyc-файлы содержат готовый байт-код, непосредственно выполняемый виртуальной машиной.
.pyo-файлы также как и .pyc-файлы содержат готовый байт-код, и, по-сути ничем, кроме предварительной оптимизации кода (вырезание assert`ов и docstring`ов) не отличаются.
Кроме хранения байт-кода для виртуальной машины возможен сценарий, при котором исходный код на Python преобразуется в исходный код на языке C, и затем собирается в .pyd-файлы (для Windows) или .so для Linux.
А вот в наше время…
Вы когда-нибудь задумывались, почему на Python не делают crackmes? Вроде бы можно взять скрипт, преобразовать его в байт-код и…с той же легкостью преобразовать обратно в исходный код, каким-нибудь uncompyle. Да и отладка Python-скрипта - дело не сказать что очень сложное. Однако crackmes на python, хоть их и кот наплакал, но все же существуют.
Делятся они приблизительно на следующие группы:
- Код на Python, обернутый вместе с интерпретатором другим компилируемым языком, возможно преобразованный в .pyd
- .pyc-файлы, при создании которых использовался модифицированный интерпретатор, и стандартным интерпретатором они не выполняются
- Единственные найденные мной примеры crackmes на чистом Python. Демонстрируют, что код можно запутать. “Распутывание” сводится к расстановке переносов, удалении неиспользуемых символов, которые валидны синтаксически, однако не несут никакой смысловой нагрузки, и, возможно, недолгой отладке с модификациями на лету.
Modus operandi
Зная основную теорию, можно выдвинуть ряд гипотез о точках внедрения защитных механизмов:
- .py
Однако обфускация, как процесс изменения исходного кода, может в том числе приводить к изменениям в работе алгоритмов, например в быстродействии, что не есть хорошо.
Единственным методом защиты на данном этапе может быть рекомендация писать настолько некачественный код, чтобы его модификация вошла в число опасных БДСМ-практик.
- .pyc \ .pyo
Структура .pyc-файла достаточно проста:
- Первые 2 байта это magic_number, указывающий на версию интерпретатора.
- 2 фиксированных байта 0x0D 0x0A
- 4 байта дата и время последней модификации
- Далее следует байт-код
Для решения задачи невозможности декомпиляции байт-кода так или иначе придется модифицировать используемую реализацию Python, по-сути создавая кастомизированную версию виртуальной машины, поддерживающую привидение байт-кода к выполнимому виду.
Запутать байт-код можно, применяя следующие техники:
- Шифрование. При компиляции дополнительно преобразовать весь байт-код в невыполнимый без стадии расшифровки.
- Обфускация опкодов. Суть метода заключается в дополнительном преобразовании непосредственно опкодов таким образом, чтобы "сдвинуть" опкод относительно его оригинального местоположения в таблице, превратив его в другой опкод, что, в свою очередь, сделает невозможным выполнение такого байт-кода немодифицированной версией виртуальной машины.
- Необходимость поддержки при переходе на новые версии Python
- В случае с шифрованием - хранение ключа для расшифровки на машине с запускаемым кодом, либо имплементации протокола обмена ключами.
- В случае с обфускацией опкодов - возможность анализа сдвигов (при применении простых алгоритмов вроде шифра Цезаря), либо необходимость применения более сложных алгоритмов, с целью усложнения статического анализа.
- .pyd \ .so
Сама сборка .py-файла в библиотеку производится с помощью cython, и достаточно нетривиальна. В результате мы имеем код, который не имеет вообще ничего общего с изначальным исходным кодом, и декомпилирован быть не может (только дизассемблирован и исследован, в результате чего можно делать выводы об алгоритмах и особенностях кода).
Источник: https://habr.com/ru/company/otus/blog/682872/

