3.1. Использование недокументированных команд и недокументированных возможностей процессора
Один из методов, используемый для затруднения отладки и дизассемблировании программ, заключается в привлечении редко используемых инструкций процессора, недокументированных инструкций, или инструкций имеющих скрытый результат. В данном случае, не все злоумышленники хорошо знакомы с такого рода командами и скрытыми возможностями процессора. Недостаток данных методов – жесткая привязка к процессору. Кроме этого, не гарантируется поддержка недокументированных инструкций в будущих модулях процессорах, а значит и совместимость с ними разработанных защит.В качестве примеров «сокрытия» реальных инструкций можно привести примеры, приведенные в таблице 2.1.Рассмотрим особенности записи кодов инструкций в процессоре INTEL.
Реализация процессора INTEL предполагает следующий формат инструкций для него:
Префикс | Опкод | ModR / M | SIB | Смещение | Непосредственный операнд
Детальное рассмотрение данной структуры выходит за пределы данного пособия. Остановимся только на механизмах, которые могут быть использованы при защите ПО.Префиксы в кодах инструкций делятся на следующие типы.
Префиксы блокировки и повторения – говорят о том, что код инструкции относится к действиям блокировки или повторения.
Префиксы переопределения сегмента. В данном случае, префикс указывает на то, с каким сегментом должна осуществляться работа команды. Соответствия между значениями префиксов и сегментами приведены в таблице 2.2.
Таблица 2.2. Соответствия префиксов и кодируемых ими сегментов
Значение префикса | Сегмент |
2Eh | CS |
36h | SS |
3Eh | DS |
26h | ES |
64h | FS |
65h | GS |
3. Префиксы переопределения размеров операндов (префикс 66h). Данный префикс используется в 16-разрядном режиме для манипулирования с 32-битными операндами и наоборот.
4. Префиксы переопределения размеров адреса (префикс 67h).
Если в процессорной команде используется более одного префикса из одной группы, то действие команды неопределено и по-разному реализовано на различных типах процессоров.
Приведем наиболее типичные приемы использования недокументированных команд и недокументированных возможностей процессора INTEL.
1. В качестве одной из недокументированных возможностей процессора INTEL можно использовать недокументированную возможность использования префиксов, например, префикса переопределения размеров операндов. Согласно стандарту, он используется только при наличии в команде каких-либо операндов. Однако, на практике для реального процессора, данный префикс может быть поставлен совершенно перед любой командой, и это будет работать на реальном процессоре. Например, как это ни странно, реальный процессор воспримет инструкцию 0x66 CLI (использование префикса перед оператором запрещения прерываний). В связи с тем, что данная особенность не документирована (предполагается, что никому в голову писать подобные вещи), , то как правило, отладчики и дизассемблеры не воспринимают подобные инструкции и отказываются корректно интерпретировать данный код.
Тоже самое следует сказать и про префиксы переопределения размеров адреса. Данные префиксы согласно документации используются только в командах, оперирующих с адресами памяти. Их использование в других командах не документировано, но процессор будет эти команды выполнять. В качестве примера такой инструкции можно привести инструкцию 0x67 STI.
Приведенные методы позволяют противостоять, также, и виртуальным эмуляторам процессоров (см. п. 4).
2. Использование префикса переопределения размеров операндов совместно с инструкцией RETN
Достаточно мощным приемом противодействия отладчикам и дизассемблерам, основанным на использовании недокументированных возможностей, является использование префикса переопределения размеров операндов совместно с командой RETN. Казалось бы, раз команда RETN не имеет операндов, то префикс 66 процессор игнорирует, но это не так. Дело в том, что RETN работает с неявным операндом-регистром ip/eip. Именно этот операнд и изменяет префикс. В реальном и 16-разрядном режиме указатель команд всегда обрезается до 16 бит и на первый взгляд все сработает корректно, однако, при записи префикса, стек окажется несбалансированным. Из него вместо одного слова возьмется два. Как правило, это приводит к возникновению исключительной ситуации 0Ch – исчерпание стека. Это приводит к зависанию большинства отладчиков, а дизассемблеры на смогут отследить стек. Однако, данный пример будет работать только в реальном режиме. Под Windows перехватить прерывание 0Ch не представляется возможным.
3. Префиксы переопределения сегментов также могут встречаться перед любой командой, в том числе и в командах, не обращающихся к памяти. Например, команда CS:NOP корректно выполняется, а вот некоторые дизассемблеры сбиваются при этом.
4. Использование дублирующих префиксов, то есть записи префиксов вида 0x66,0x66 непосредственно перед командой. Хотя фирма INTEL не гарантирует корректную работу своих процессоров при обнаружении такого рода инструкций, но фактически все процессоры правильно интерпретируют данные ситуации. Иное дело – отладчики и дизассемблеры, которые спотыкаются и начинают некорректно вести себя.
Следует отметить, также, что процессором INTEL корректно выполняются и инструкции вида DS:FS:CS:Mov ax, [100] (последний префикс перекрывает все остальные), а отладчики и дизассемблеры сбиваются при их анализе. Данный пример хорошо работает под Windows и другими операционными системами.
5. Обращение к недокументированным регистрам. В процессорах INTEL регистры в настоящее время кодируются 3-мя битами следующим образом (таблица 2.3).
Таблица 2.3. Кодирование регистров в инструкциях
Код | Инструкция |
000 | ES |
001 | CS |
010 | SS |
011 | DS |
100 | FS |
101 | GS |
110 | Зарезервирован |
111 | Зарезервирован |
Две последние кодовые комбинации (110 и 111) в настоящее время зарезервированы и не используются. При попытке их использования вызывается исключительная ситуация 06h, которую можно перехватить (под ДОС). Отладчики же и дизассемблеры при встрече с такого рода инструкциями начинают вести себя странно и непредсказуемо. Одни не генерируют при этом прерывания, чем и выдают себя, другие начинают некорректно работать. Поведение де дизассемблеров в этом случае тоже разнообразно. Ниже приведен пример того, как различные дизассемблера воспринимают такого рода инструкции.
HIEW
8E ???
F8 clc
C3 retn
Qview
8EF8 mov !s, ax
C3 ret
IDA Pro
Db 8E
Db 0F8
DB C3
Несуществующие регистры можно эмулировать в обработчике прерывания int 06h, однако данная защита не будет работать под Win32.
6. Изменение длины команды.
Данный прием направлен на противодействие отладчикам и основан на том, что реальный процессор при выполнении команд вычисляет адрес следующей до выполнения предыдущей. Многие же отладчики, вычисляют адрес следующей команды после выполнения предыдущей (это проще реализуемо). Модифицировав программу в процессе работы (работает только в реальном режиме), можно воспользоваться данной особенностью для реализации защиты.
00000100: | 810600010200 | add word ptr [0100],01 |
00000106: | B406 | mov ah,06 |
00000108: | B207 | mov dl,07 |
0000010A: | CD21 | int 21 |
0000010C: | C3 | Ret |
Эта защита основана на том, что после отработки первой команды, она станет сразу же другой, и, при этом, на байт короче. Реальный процессор, в отличие от многих отладчиков, перейдет не на ячейку 106, а на ячейку 105 и будет выполнять следующий код:
00000100: | 810600010200 | add word ptr [0100],01 |
00000105: | 00B406B2 | add [si] [0B206],dh |
С помощью данного способа можно строить защиты на эмуляторы процессоров (см. п. 4).
- Модульная архитектура технических средств защиты по от несанкционированного использования
- Функционирование подсистем и модулей системы защиты по от несанкционированного использования
- Электронные ключи hasp
- Глава 1. Методы и средства обратного проектирования.
- 1.1. Понятие обратного проектирования
- 1.2. Основные приемы, используемые злоумышленником при отладке и дизассемблировании программного обеспечения
- 1.2.1. Специфика атак на модули проверки корректности ключевой информации
- 1.2.2. Специфика атак на модули проверки истечения временного срока работы программы или ограничения по количеству ее запусков
- 1.2.3. Отлов злоумышленником вызова WinApi функций при взломе по
- 1.3. Мониторинг событий
- Глава 2. Методы противодействия обратному проектированию
- 2.1. Методы противодействия отладчикам
- 2.1.1. Защита от отладчиков реального режима
- 2.1.2. Защита от отладчиков защищенного режима
- 2.1.3. Методы, основанные на невозможности полного эмулирования отладчиком среды загрузки программы
- 2.2. Методы противодействия дизассемблированию программного обеспечения
- 2.3. Защита, основанная на человеческом факторе злоумышленника
- Глава 3. Общие методы защиты программ от отладки и дизассемблирования
- 3.1. Использование недокументированных команд и недокументированных возможностей процессора
- 3.2. Шифрование кода программы
- Глава 4. Эмуляторы процессоров. Использование эмуляторов для взлома и защиты программного обеспечения.
- Глава 5. Защита исходных текстов программного обеспечения
- Глава 6. Идентификация и аутентификация субъектов
- 6.1. Идентификация и аутентификация пользователей с использованием технических устройств
- 6.2. Идентификация и аутентификация с использованием индивидуальных биометрических характеристик пользователя
- 7. Защита от разрушающих программных воздействий
- 7.1. Понятие разрушающего программного воздействия
- 7.2 Модели взаимодействия прикладной программы и рпв
- 7.3 Компьютерные вирусы как класс рпв
- 7.4. Защита от рпв. Изолированная программная среда
- Глава 8. Руководящие документы России
- Приложение
- 6.1. Отладка программ в отладчике SoftIce
- 6.2. Дизассемблирование программ с помощью интерактивного дизассемблера Ida Pro
- 6.3. Редактор кода hiew
- Лабораторные работы