Как защитить код Python? - PullRequest
       111

Как защитить код Python?

585 голосов
/ 04 ноября 2008

Я занимаюсь разработкой программного обеспечения на Python, которое будет распространяться среди клиентов моего работодателя. Мой работодатель хочет ограничить использование программного обеспечения файлом лицензии с ограниченным сроком действия.

Если мы распространяем файлы .py или даже файлы .pyc, будет легко (декомпилировать и) удалить код, проверяющий файл лицензии.

Другой аспект заключается в том, что мой работодатель не хочет, чтобы код читался нашими клиентами, опасаясь, что этот код может быть украден или, по крайней мере, «новых идей».

Есть ли хороший способ справиться с этой проблемой? Желательно с готовым решением.

Программное обеспечение будет работать в системах Linux (поэтому я не думаю, что py2exe справится с задачей).

Ответы [ 27 ]

5 голосов
/ 07 июня 2010

Идея иметь ограниченную по времени лицензию и проверить ее в локальной программе не будет работать. Даже при идеальном запутывании, проверка лицензии может быть удалена. Однако, если вы проверите лицензию на удаленной системе и запустите значительную часть программы на своей закрытой удаленной системе, вы сможете защитить свой IP.

Не позволяя конкурентам использовать исходный код как свой собственный или писать свою вдохновленную версию того же кода, один из способов защиты - это добавить сигнатуры в логику вашей программы (некоторые секреты, чтобы доказать, что код был украден у вас) и запутывать исходный код на python, поэтому его трудно читать и использовать.

Хорошая запутанность добавляет к вашему коду в основном ту же защиту, что и компиляция его в исполняемый файл (и бинарный двоичный код). Выяснить, как работает запутанный сложный код, может быть даже сложнее, чем написать собственную реализацию.

Это не поможет предотвратить взлом вашей программы. Даже с запутанным кодом лицензионный материал будет взломан, и программа может быть изменена, чтобы иметь немного другое поведение (так же, как компиляция кода в двоичный файл не помогает защитить нативные программы).

В дополнение к запутыванию символов может быть хорошей идеей нерефакторизовать код, что делает все еще более запутанным, если, например, графы вызовов указывают на множество разных мест, даже если на самом деле эти разные места в конечном итоге делают одно и то же.

Логическая подпись внутри обфусцированного кода (например, вы можете создать таблицу значений, которые используются программной логикой, но также используются в качестве подписи), которая может использоваться для определения того, что код произошел от вас. Если кто-то решит использовать ваш обфусцированный модуль кода как часть своего собственного продукта (даже после того, как его повторно обфусцируют, чтобы он выглядел иначе), вы можете показать, что код украден с вашей секретной подписью.

4 голосов
/ 04 ноября 2008

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

С учетом сказанного я просто проверял Google на предмет обмана в Python и не обнаруживал много чего-либо. В решении .Net, obsfucation будет первым подходом к вашей проблеме на платформе Windows, но я не уверен, есть ли у кого-нибудь решения для Linux, которые работают с Mono.

Следующим шагом будет написать ваш код на скомпилированном языке или, если вы действительно хотите идти до конца, то на ассемблере. Удаленный исполняемый файл будет намного сложнее декомпилировать, чем интерпретируемый язык.

Все сводится к компромиссам. С одной стороны у вас есть простота разработки программного обеспечения на Python, в котором также очень трудно скрыть секреты. С другой стороны, у вас есть программное обеспечение, написанное на ассемблере, которое гораздо сложнее написать, но гораздо проще скрыть секреты.

Ваш босс должен выбрать точку в этом континууме, которая отвечает его требованиям. И тогда он должен дать вам инструменты и время, чтобы вы могли построить то, что он хочет. Однако я держу пари, что он будет возражать против реальных затрат на разработку против потенциальных денежных потерь.

3 голосов
/ 22 мая 2013

Возможно иметь байт-код py2exe в зашифрованном ресурсе для модуля запуска C, который загружает и выполняет его в памяти. Некоторые идеи здесь и здесь .

Некоторые также подумали о самоизменяющейся программе , чтобы сделать обратный инжиниринг дорогим.

Вы также можете найти учебные пособия по предотвращению отладчиков , вызвать сбой дизассемблера, установить ложные точки останова отладчика и защитить свой код контрольными суммами. Ищите ["зашифрованный код" выполнить "в памяти"] для получения дополнительных ссылок.

Но, как уже говорили другие, если ваш код того стоит, обратные инженеры в конце добьются успеха.

2 голосов
/ 29 января 2019

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

На GitHub имеется библиотека с открытым исходным кодом, которая может помочь вам с битом проверки лицензии.

Вы можете установить его по pip install licensing, а затем добавить следующий код:

pubKey = "<RSAKeyValue><Modulus>sGbvxwdlDbqFXOMlVUnAF5ew0t0WpPW7rFpI5jHQOFkht/326dvh7t74RYeMpjy357NljouhpTLA3a6idnn4j6c3jmPWBkjZndGsPL4Bqm+fwE48nKpGPjkj4q/yzT4tHXBTyvaBjA8bVoCTnu+LiC4XEaLZRThGzIn5KQXKCigg6tQRy0GXE13XYFVz/x1mjFbT9/7dS8p85n8BuwlY5JvuBIQkKhuCNFfrUxBWyu87CFnXWjIupCD2VO/GbxaCvzrRjLZjAngLCMtZbYBALksqGPgTUN7ZM24XbPWyLtKPaXF2i4XRR9u6eTj5BfnLbKAU5PIVfjIS+vNYYogteQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"

res = Key.activate(token="WyIyNTU1IiwiRjdZZTB4RmtuTVcrQlNqcSszbmFMMHB3aWFJTlBsWW1Mbm9raVFyRyJd",\
                   rsa_pub_key=pubKey,\
                   product_id=3349, key="ICVLD-VVSZR-ZTICT-YKGXL", machine_code=Helpers.GetMachineCode())

if res[0] == None not Helpers.IsOnRightMachine(res[0]):
    print("An error occured: {0}".format(res[1]))
else:
    print("Success")

Подробнее о том, как настроен открытый ключ RSA и т. Д., Можно узнать здесь .

2 голосов
/ 30 июля 2018

Короче говоря:

  1. Зашифруйте ваш исходный код
  2. Напишите свой собственный загрузчик модулей Python для расшифровки кода при импорте
  3. Реализация загрузчика модулей в C / C ++
  4. Вы можете добавить дополнительные функции в загрузчик модулей, например, анти-отладчик, контроль лицензий, привязку аппаратных отпечатков пальцев и т. Д.

Для более подробной информации, посмотрите этот ответ .

Если вам интересна тема, вам поможет этот проект - pyprotect .

1 голос
/ 03 марта 2012

с использованием cxfreeze (py2exe для linux) сделает эту работу.

http://cx -freeze.sourceforge.net /

доступно в репозиториях Ubuntu

0 голосов
/ 14 декабря 2017

Используйте тот же способ защиты двоичного файла c / c ++, то есть обфусцируйте каждое тело функции в исполняемом файле или двоичном файле библиотеки, вставьте инструкцию «jump» в начале каждой записи функции, перейдите к специальной функции для восстановления запутанный код. Байт-код - это двоичный код скрипта Python, поэтому

  • Первый сценарий Python для компиляции объекта кода
  • Затем итерируйте каждый объект кода, зашифруйте co_code каждого объекта кода, как показано ниже
    0   JUMP_ABSOLUTE            n = 3 + len(bytecode)

    3
    ...
    ... Here it's obfuscated bytecode
    ...

    n   LOAD_GLOBAL              ? (__pyarmor__)
    n+3 CALL_FUNCTION            0
    n+6 POP_TOP
    n+7 JUMP_ABSOLUTE            0
  • Сохранить объект обфусцированного кода как файл .pyc или .pyo

Эти запутанные файлы (.pyc или .pyo) могут использоваться обычным интерпретатором python, когда эти объекты кода вызываются впервые

  • Первая операция JUMP_ABSOLUTE, она перейдет к смещению n

  • При смещении n инструкция вызывает функцию PyCFunction. Эта функция восстановит обфусцированный байт-код между смещением 3 и n и поместит оригинальный байт-код в смещение 0. Обфусцированный код можно получить с помощью следующего кода

        char *obfucated_bytecode;
        Py_ssize_t len;
        PyFrameObject* frame = PyEval_GetFrame();
        PyCodeObject *f_code = frame->f_code;
        PyObject *co_code = f_code->co_code;      
        PyBytes_AsStringAndSize(co_code, &obfucated_bytecode, &len)
    
  • После возврата этой функции последняя инструкция должна перейти к смещение 0. Теперь выполняется настоящий байт-код.

Существует инструмент Pyarmor , позволяющий таким образом запутывать скрипты Python.

...