Операционная система MS DOS (том 2)

Защита программ от трассировки


Защищая свои программы от несанкционированного копирования, не следует забывать о таких средствах "взлома", как пошаговые отладчики - CodeView, Advanced Fullscreen Debug, AT86 и другие.

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

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

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

Соответственно, требуются отдельные средства для борьбы с дизассемблером и для защиты от отладчиков.

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

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

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

Задача второй части - перемещение третьей части программы на место уже использованной первой части и расшифровка ее там.


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

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

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



Объем листинга, получающегося при дизассемблировании программы размером в 30-40 килобайтов, достигает 1-1,5 мегабайтов. Поэтому большие размеры инсталляционной программы могут сильно увеличить время обнаружения средств защиты.

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

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

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

К первой группе средств относится:

  • блокировка специальных "отладочных" прерываний процессора;


  • блокировка прерываний от клавиатуры;


  • замер времени выполнения контрольных участков программы;


  • использование прерывания таймера.


  • Напомним, что прерывание INT 1 и INT 3

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



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

    Эти обработчики прерываний могут не делать ничего, т.е. состоять из одной команды IRET, или выполнять какие-либо действия, фиксирующие факт работы программы под контролем отладчика.

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

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

    Если программа работает не под контролем отладчика, прерывания во время этого участка программы невозможны (они запрещены командой CLI).

    Если же используется режим пошагового выполнения программы под управлением отладчика, отладчик разрешает клавиатурные прерывания, невзирая на то, что была выдана команда CLI. Наш обработчик клавиатурного прерывания в этом случае зафиксирует работу в режиме трассировки.

    Аналогично можно воспользоваться прерыванием таймера.

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

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

    Последний метод, который мы рассмотрим, основан на использовании архитектурной особенности процессоров 8086, 80286, 80386 и 80486 - наличии конвейера команд.

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



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

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

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

    Приведем программу, демонстрирующую описанный выше метод:

    ; Эта программа демонстрирует способ защиты от ; отладки, основанный на использовании архитектурной ; особенности процессоров 8086, 80286, 80386, 80486 - ; наличии внутреннего конвейера команд

    TITLE BUG

    .MODEL tiny

    .STACK 100h

    .DATA

    msg DB "Программа работает без отладчика!", 13, 10, "$"

    .CODE .STARTUP

    ; Запрещаем прерывания

    cli

    ; Вызываем программу проверки

    call _TEST

    ; Разрешаем прерывания

    sti

    .EXIT 0

    ; -------------------------------

    ; Программа проверки

    _TEST PROC near

    ; Выполняем модификацию команды с меткой next. ; Вместо команды ret записываем команду nop.

    mov BYTE PTR next, 90h next: ret

    ; Если модификация не произошла, это означает, что ; программа выполняется под управлением отладчика. ; Выводим сообщение о работе под контролем отладчика.

    mov ah, 9h mov dx, OFFSET msg int 21h

    ret

    _TEST ENDP

    END

    Эта программа выводит сообщение о работе без отладчика, если происходит изменение команды, и не выводит ничего, если изменения команды не происходит (т.е. если программа работает под управлением отладчика).

    Метод был проверен для отладчиков Code View, AFD, AT86, утилиты отладки MS-DOS DEBUG и дал положительные результаты.


    Содержание раздела