Содержание статьи
Постановка проблемы
Структурные исключения представляют собой мощное антиотладочное средство, в чем мы уже убедились на примере предыдущих выпусков. Там же мы познакомились и с техникой исследования программ, играющихся исключениями, работу с которыми достаточно трудно замаскировать.
Всякий раз, когда в тексте программы встречается конструкция MOV
, хакер сразу встает торчком — раз это FS:[
, значит, программа устанавливает собственный SEH-обработчик и, судя по всему, сейчас будет бросать исключения. Теоретически возможно засунуть MOV
в самомодифицирующийся код, убрав его из дизассемблерных листингов, однако против аппаратной точки останова по записи на MOV
ничто не спасет. В момент установки нового SEH-обработчика отладчик тут же «всплывет», демаскируя защитный механизм. А SetUnhandledExceptionFilter
вообще представляет собой API-функцию, экспортируемую KERNEL32.DLL, которую легко обнаружить любым API-шпионом, даже без анализа всего дизассемблерного кода!
Задача: установить собственный обработчик структурных исключений, но так, чтобы это как можно меньше бросалось в глаза и не палилось тривиальной установкой точек останова. Решением мы сейчас, собственно, и займемся, предложив широкий ассортимент антиотладочных трюков, один интереснее другого.
Перезапись существующего обработчика
Вместо того чтобы устанавливать новый обработчик структурных исключений, некоторые (и достаточно многие) защиты предпочитают модифицировать указатель на существующий. Даже если приложение и не устанавливает никаких SEH-обработчиков, система все равно впихивает ему SEH-обработчик по умолчанию, смотрящий куда‑то в дебри KERNEL32.DLL. На этом, кстати говоря, основан популярный примем поиска базового адреса загрузки KERNEL32.DLL, в котором нуждается shell-код, а также программы, написанные без использования таблицы импорта (из‑за ошибки в системном загрузчике они работают только на XP и более поздних версиях).
Обработчик по умолчанию не делает ничего полезного, и потому без него можно обойтись, «позаимствовав» указатель — на время или навсегда. Конкретный пример реализации приведен ниже.
Установка своего SEH-обработчика без перезаписи ячейки FS:[0]
souriz(){ printf("hello, nezumi\n"); ExitProcess(0);}main(){ int *p=0; __asm{ mov eax, fs:[0] lea ecx, souriz add eax, 4 mov [eax], ecx } return *p;}
Внешне код очень похож на классический способ установки SEH-обработчика, но, присмотревшись внимательнее, мы видим, что в нашем примере модифицируется отнюдь не ячейка FS:[
, а то, на что она указывает. Точка останова по записи на FS:[
уже не сработает, однако сегментный регистр FS режет глаз, да и бряк на FS:[
по доступу продолжает работать, а потому для эффективного противодействия хакеру требуются дополнительные уровни маскировки. Ну и чего мы сидим? Вперед!
Прячем FS
Ослепить дизассемблеры совсем не трудно. Перезаписать указатель на системный SEH-обработчик можно и без явного использования сегментного регистра FS. Самое простое, что можно сделать, — скопировать его в любой другой сегментный регистр (например, GS). С точки зрения процессора, регистры FS и GS совершенно равноправны. Главное, чтобы в регистре содержался «правильный» селектор, а его название — уже дело десятое. Создавать новые селекторы мы не можем (точнее, можем, но это тема отдельного разговора), а вот загружать существующие — почему бы и нет?
Усиленный фрагмент защиты приведен ниже.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»