Главная

Программы

OSProtector

Реализация
Примеры
OSa

Активация

Контакт

Ссылки


Описание реализации функций протектора.


Многослойная защита - идея.

     Вначале протектор пытается найти и корректно дизассемблировать созданные компилятором функции. Для этого необходимо в опциях настройки проекта, перед компиляцией релизной версии бинарного файла, позволить компилятору создать map-файл. Map-файл - текстовый файл, который содержит имена, а также адреса точек входа (адреса первых инструкций) созданных компилятором функций. Все современные компиляторы позволяют создавать map-файлы. Использование map-файлов позволит минимизировать наличие возможных ошибок дизассемблирования, также позволит отображать корректные имена функций.

     По окончанию дизассемблирования у протектора имеется список, созданных компилятором функций. При анализе этих функций протектор присваивает каждой из них статус, принимающий одно из двух значений:

  • Функции, которые протектор считает корректно дизассемблированными.
  • Функции, в корректности дизассемблирования которых протектор не уверен, или точно уверен, что функция не была корректно дизассемблирована.

     По окончании первого этапа работы протектора программист, для защиты своей программы, должен создать слои. Слой - это объект, с которым можно ассоциировать данные или код. Слоев должно быть, как минимум два. С первым слоем могут быть ассоциированы любые данные (последовательности байт - как правило, это ASCII и UNICODE строки) и любой программный код. Со вторым и последующими слоями можно ассоциировать только корректно дизассемблированные (по мнению протектора) функции. Каждая из функций, ассоциированная со вторым и последующими слоями будет изменена протектором. Код этих функций будет мутирован - часть машинных команд этих функций будет "похищена" и перенесена в новую, созданную протектором секцию защищаемого файла. Перенесенные машинные команды будут перемешаны с кодом, проверяющим неизменность кода (или данных) ассоциированных с предыдущими слоями.

     Важно осознавать, что при каждой проверке корректности кода, проверяющий код предыдущих слоев будет терять драгоценные такты микропроцессорного времени, следовательно, функции ассоциированные со вторым и последующими слоями не должны вызываться из глубоко вложенных функций, а так же содержать циклы, имеющие большое количество итераций - иначе программа будет конкретно "тормозить". Программист, при защите своего софта, должен выбрать те функции, которые могут позволить приостанавливать исполняемые потоки защищенного бинарного файла на время 0.001 - 0.1 сек, и ассоциировать эти функции со вторым и последующими слоями. Также важно понимать, что при использовании слишком большого количества слоев (функций) размер выходного файла может существенно увеличиться.

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

Автоматизация защиты. Имена функций, маркеры, метки.

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

  • По именам функций (для этого необходимо наличие корректного map-файла, дабы протектор смог определить имя каждой, созданной программистом, функции). Необходимо всего один раз ассоциировать имена функций со слоями, чтобы протектор смог сохранить эту информацию в файл проекта. Если же прототип или имя функции изменилось, то при загрузке файла-проекта протектор проинформирует программиста об этом.
  • По наличию в функциях маркеров. Маркер - вызов из искомой функции, функции с заголовком "void __stdcall CreateOSProtectorMarker(const char*)" из заголовочного файла OSProtectorSDK.h (для языка C/C++). Протектор, проведя анализ листинга всех дизассемблированных функций, сможет узнать, что в той или иной функции была вызвана функция CreateOSProtectorMarker и, прочитав строчный параметр этой функции (имя маркера), он сможет ассоциировать все функции, содержащие маркеры с данным именем с тем или иным слоем.
  • По наличию в функциях меток. Метка - набор машинного кода (машинных команд), не изменяющая окружение исполняемого потока. Пример метки __asm{ push eax; mov eax, 1; pox eax}. Для возможности использования меток программист должен определить в какой машинный код компилятор преобразует данную последовательность инструкций, кроме того необходимо наличие поддержки компилятором ассемблерных вставок. Это не всегда приемлемо. Группировка по меткам считается устаревшей, но конечно будет поддерживаться протектором для обеспечения обратной совместимости.

Система лицензирования.

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

В созданный протектором серийный номер может быть включена следующая информация о пользователе:

  • Имя покупателя (не более 256 символов в однобайтовой кодировке)
  • Адрес электронной почты (не более 256 символов в однобайтовой кодировке)
  • Идентификатор компьютера (рассчитывается в зависимости от микропроцессора и [или] жесткого диска)
  • Дату, после которой станет невозможно использовать данный серийный номер
  • Время, с момента запуска программы, в течении которого система защиты позволит выполняться программе.
  • Какие-либо пользовательские данные (не более 256 байт)

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

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

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

     При использовании стороннего протектора, у создателя (продавца) программного обеспечения может возникнуть следующая ситуация: имеется некоторое количество уже проданных валидных, но не криптостойких серийных номеров. Создатель ПО хочет перейти на новую систему создания серийных номеров, при этом все старые серийные номера должны считаться валидными. Для данной ситуации, в протекторе реализована возможность добавлять в защищаемый бинарный файл список так называемых "ключей-разработчика". Список хэшей этих ключей перемешивается с байт-кодом стековой машины и также сохраняется в защищаемом файле. Модули защиты, проверяющие валидность серийных номеров без труда смогут опознать как старые, так и новые серийные номера. Неизменность списока хэшей этих ключей также будет проверяться во втором и последующих слоях.

Интеграция в защищаемый бинарный файл кода исполняемого на стековой машине.

     Бывают ситуации, когда необходимо вставить в защищаемый бинарник исполняемый код, анализ алгоритма которого должно быть максимально затруднен. Для реализации этой возможности, в протектор была встроена возможность вставлять в защищаемый файл функции, исполняемые на своей стековой (виртуальной машине) - так называемые OS-функции. При добавлении OS-функции программист должен определиться с ее атрибутами - прежде всего это исходный код, исполняемый на C-подобном языке, размер стека и точка входа. Анализ, созданного транслятором, вставленного протектором в защищаемый бинарный файл байт-кода становится для крякера достаточно нетривиальной задачей. При обусфикации некого алгоритма подобным образом, существенным плюсом можно считать достаточно существенный выигрыш в производительности (по сравнению с мутацией кода - некоторые современные, правильные протекторы позволяют "виртуализировать" часть машинного кода в код, исполняемый на виртуальных машинах). Минусом - необходимость программисту писать алгоритм на новом, "достаточно синтаксически скудном" языке. Подробнее с описаниями конструкций OS-языка можно ознакомиться в примерах использования протектора.

Отладочный режим работы протектора.

     При защите исполняемого файла протектором доступен отладочный режим работы. При данном режиме работы протектор создает бинарный файл, позволяющий проследить последовательность вызовов функций, ассоциированных со вторым и последующими слоями. Информация о них (вызовах) будет помещена в окно лога протектора. Также, при использовании отладочного режима работы протектора, в листингах OS-функций полезно использовать системные функции void WriteToProtectorLog(char*) ,void WriteToProtectorLog(int), которые также посылают отладочную строку (число) в окно лога протектора.

© 2009—2011 «OS-Lab.ru»