Блог → Защищаем программу, находящуюся в оперативной памяти

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

К сожалению, и это нужно признать, в данном случае существует достаточно мало способов защиты. Тем не менее, я всё же попытаюсь дать некоторые рекомендации на этот счёт. Начну с защиты нерезидентных программ. В данном случае возможны 2 основных ситуации:
- нападение на дополненный модуль к защищаемой программе;
- нападение на защищенную программу после отработки антиотладочных средств и передача на неё управления.

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

Например, в первом случае возможно, что после окончания всех проверок дополненный модуль принял решение о нелегальности данной копии и решил завершить работу, вызвав прерывание int 21h, функцию 4Ch. Тогда, при остановке в этом месте, структура дополненного модуля будет хорошо видна, если просмотреть область младших адресов от точки останова.

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

Для защиты от подобных действий можно предложить следующее:
- стараться по минимуму использовать любые прерывания в теле дополненного модуля;
- в обязательном порядке бороться с трассировкой прерываний int 13h, int 40h, int 21h;
- после отработки существенно значимого фрагмента кода приводить его в нерабочее состояние.

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

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

Первый способ применяется, например, в таких системах как CERBERUS и Scorpion (разработка фирмы "Элиас"), но полная защита невозможна, хотя процесс локализации незащищённой программы в памяти сильно затруднен. Второй способ достаточно трудоёмок, и по сути, широко не применяется, поскольку его успешная реализация сильно зависит от структуры защищаемой программы. Третий способ применён, в частности, в системе PROTECT-SUPER, но он контролирует лишь процесс записи, ведущийся через прерывание 13h, поэтому может быть обойден при помощи использования записи "мимо" этого прерывания.

Ну и, пара слов о защите резидентных программ. В данном случае возможны следующие виды нападения:
- прохождение отладочными средствами в режиме "Resident", с простановкой точек останова;
- трассировка прерывания, с которым связана резидентная программа;
- дисассемблирование участка оперативной памяти, занимаемого резидентной программой.

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

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