"С.П.Расторгуев, А.Е.Долгин "Как защитить информацию" (пособие по борьбе с хакерами)" - читать интересную книгу автора Предварительное архивирование также не представляет особых
затруднений для хакера, но является более эффективным по сравнению с шифрованием, так как решает сразу две задачи: уменьшает размер защищаемого модуля и скрывает код от дизассемблера. Как это делается? Возьмем файл рисунка. Он содержит поточечное описание всех строк экрана (цифры - это точки определенного цвета, ноль - ее отсутствие). Например, рисунок красной линии на экране, состоящей из 200 точек, записывается в файл в виде 200 байт, а значение каждого байта равно 4 (код для красного цвета). Архиватор заменяет перечисление одинаковых цифр (эти 200 четверок) элементарным шифром - двумя байтами (первый - количество повторов, второй - значение цвета), и размер файла резко уменьшается (в примере - с 200 до 2 байт). Для других типов записей существуют свои методы сжатия. Большинство из них описано в литературе, поэтому не будем останавливаться. Метод самогенерируемых кодов наиболее сложен в реализации, но очень эффективен. Суть его такова. В программу вложен массив данных, который сам по себе может быть исполняемым кодом (реально получающим управление) или смысловым текстом, но после некоторых арифметических или логических операций преобразуемый в участок программы, выполняющий иные, не менее важные функции. Нужно быть виртуозом программирования, чтобы заметить самомодифицирующуюся ловушку. Ведь при анализе листинга и с явными алгоритмами разбираться сложно (автор комментарии не оставляет), так что уж говорить о потайном смысле вроде бы расшифрованного участка. Впрочем, и новичок-разработчик создать такие ловушки не сможет. придется осваивать изощренный стиль программирования, который запутывает дизассемблер нестандартной интерпретацией некоторых команд и нарушает общепринятые соглашения. Например, использование необычной структуры программы (совмещение стекового и кодового сегментов ). Интеллектуальные дизассемблеры, как правило, это плохо воспринимают. А перекрестные вызовы процедур, многократные переходы из модуля в модуль и увеличение количества точек входа в них - не позволяют выявить блочную структуру программы. Замена команд переходов, вызовов подпрограмм и прерываний направляет дизассемблер по ложному следу. Здесь вместо стандартного оператора вставляется группа других, в конечном счете выполняющих то же самое. Для неискушенных программистов на рисунке 4.1 (а-д) приведены такие варианты. Впрочем, для аналогичных эффектов достаточно в команде перехода изменить значение операнда (примеры е-ж). И еще проще модифицировать косвенные переходы (з-и). Кстати, и саму команду можно модифицировать. Например, на рис. 4.1 (к) дизассемблер по адресу m: покажет PUSH AX (запись регистра AX в стек), поскольку этот байт имеет код 50h (01010000b), но перед ее выполнением один бит (4-й) меняется, в результате получается INC AX с кодом 40h (01000000b, увеличение содержимого регистра AX на 1) - то есть совсем другая команда, не отраженная в листинге. Кропотливая работа преобразует участок до неузнаваемости. А "умный" дизассемблер (например, Sourcer), отслеживая "явную" передачу управления (в другое место), не найдет спрятанный блок и, |
|
|