Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
RGZ_zakhist_program_ta_danikh_Nelasa (1).doc
Скачиваний:
2
Добавлен:
01.05.2025
Размер:
144 Кб
Скачать
☆

1.3 «Изощренное» программирование

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

Для этого необходимо сделать программу высокочитабельной для нас, но малопонят­ной в дизассемблированном виде, а под отладчиком - создающей впечатление хаотично­го набора условных и безусловных переходов. Эта задача решается применением так называемого "изощренного" программирования.

Можно выделить несколько основных направлений:

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

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

  • засорение кода "мусором" - командами, не влияющими на обработку наших данных (кроме некоторого увеличения времени обработки на "засоренных" участках).

Рассмотрим эти приемы подробнее.

Экзотическая реализация алгоритмов. Допустим, у нас есть некоторый флаг (или переменная), для которого критически важна проверка на 0. Однако мы не желаем явно писать команду СМР АХ, 0 и вообще по возможности хотим обойтись без команд пере­дачи управления.

Первое, что приходит в голову - использовать команды, пригодные для неявной про­верки на 0. Например, использовать команды двоично-десятичной арифметики.

mov ах, OurFlag

daa

pushf

pop ax ; Неявная проверка флага нуля

and ах, 40h

jz FlaglsZero

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

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

Реализация эквивалентных ветвей. Для затруднения исследования программы под отладчиком польза от этого приема очевидна. В самом деле, если мы, находясь в отладчике, попадаем то на одну команду, то на несколько, это явно не упростит пони­мание алгоритма программы.

Приведем простой пример. Операция NEG (преобразование числа в дополнительный

код) эквивалентна исключающему ИЛИ со "всеми единицами" и инкременту результата

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

XNEG16 MACRO Reg

Local XNEG2, XNEGQ

push ax ;Используется

;процедурой Random

call Random ;Некоторая

;подпрограмма

;генерации

;случайных или

;псевдослучайных

;чисел

cmp al, 30

ja XNEG2

pop ax

neg Reg

jmps XNEGQ

XNEG2:

xor Reg, 0FFFFh

inc Reg

XNEGQ:

ENDM

Это лишь простейший пример, относительно легко поддающийся анализу. Для затруднения анализа возможно:

  • увеличить число ветвей (реализуется не для всех алгоритмов);

  • реализовать ветви в виде обработчиков прерываний (INT 1, INT 3, INT 4, INT6 и т.д.) и обращаться к ним не напрямую, а путем создания соответствующих ситуаций (взведе­нием флага TF, засылкой команды INT 3 на место заранее поставленного NOP, делени­ем на 0 и пр.), что, кстати, еще и расширит противоотладочную подсистему;

  • увеличить число проверок случайного числа.

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

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]