Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #57, АВГУСТ 2005 г.

Борьба с отладчиком

Mario555

Спецвыпуск: Хакер, номер #057, стр. 057-084-6


Такие бряки очень удобны для поиска OEP в запакованных программах, если протектор не украл начальные байты. Поэтому во многих статьях по относительно простому софту советуют ставить BreakPoint memory on access на секцию кода. Эти бряки основаны на изменении атрибутов доступа страницы памяти, к которой относится адрес, на который установлен BPM. Когда ставится memory on access, Olly, используя функцию VirtualProtect, меняет доступ к странице на PAGE_NO_ACCESS, а когда memory on write, то на PAGE_EXECUTE_READ. Соответственно, при нарушении прав доступа к странице (попытке чтения, выполнения или записи) управление переходит к отладчику, который уже смотрит, к тому ли адресу происходит обращение. Минимальный размер страницы памяти в Windows равен 1000h. Если ты поставил BPM на доступ всего к одному байту, то отладчик все равно будет внутренне обрабатывать обращение ко всей странице, на которой расположен этот байт, поэтому BPM, особенно on access, может сильно замедлить выполнение программы. Такой отладочный метод обнаруживается проверкой атрибутов доступа с помощью VirtualQueryEx. Соответственно, если обнаружено, что доступ к странице не такой, каким должен быть, то протектор, используя VirtualProtect, либо меняет его (что фактически означает отключение установленного BMP - не стоит сильно удивляться, если он не сработает), либо выдаст сообщение об обнаруженном отладчике и т.п.

Защита от Hardware Breakpoints (HW)

HW-бряки, пожалуй, самые удобные при исследовании программ. Они работают на отладочных DRx-регистрах, прямой доступ к которым из ринг3 невозможен. Установленные HW-бряки не меняют код программы и доступ к страницам памяти, но все равно обнаружить их очень просто... Для начала немного информации о DRx. Есть всего шесть доступных регистров отладки: DR0-DR3 хранят адреса установленных бряков (отсюда и ограничение количества оных - всего четыре штуки), DR6 и DR7 предназначены для контроля и задания параметров первым четырем, DR4 и DR5 - не используются (зарезервированы). Формат регистров DR6 и DR7 ты можешь увидеть на картинке.

DR6 показывает текущее состояние бряков, поэтому не слишком интересен, а вот DR7, можно сказать, управляет ими: L0-L3 - биты, означающие, активирован или деактивирован соответствующий DR0-3 в контексте данного потока; RW0-RW3 - биты, определяющие условие соответствующего бряка DR0-3:

00 - on execute,

01 - on write,

10 - обращение к порту ввода-вывода,

11 - on access;

LEN0-LEN3 - длина бряка:

00 Byte,

01 Word,

10 не определено,

11 Dword.

Видно, что в DRx заключены широкие возможности для отладки программы, и ко всем этим возможностям имеет доступ сама программа! Дело в том, что в обработчике исключений она получает доступ к структуре CONTEXT (которой, кстати, и пользуется отладчик через функции SetThreadContext и GetThreadContext). CONTEXT содержит информацию о текущем состоянии потока, то есть значения регистров и т.п., включая отладочные DRx-регистры. Если изменить значение какого-либо регистра в CONTEXT, то при возвращении из обработчика исключений оно окажется в самом этом регистре. Таким образом, программа может косвенно читать и писать в DRx. Поэтому почти во всех протекторах практически бессмысленно устанавливать такой удобный для нахождения OEP (или начала краденых байт) HW-бряк на восстановление стека [esp-4] на EP - протекторы в обработчиках искусственно сделанных исключений записывают в CONTEXT.DRx нули или мусор.

Назад на стр. 057-084-5  Содержание  Вперед на стр. 057-084-7