Отладчики обоих уровней — как ядерного, так и прикладного — совершенно не приспособлены для исследования программ, интенсивно использующих структурные исключения (они же structured exceptions, более известные как SEH, где последняя буква досталась в наследство от слова handling — обработка). И хотя OllyDbg делает некоторые шаги в этом направлении, без написания собственных скриптов/макросов не обойтись. Генерация исключения «телепортирует» нас куда‑то внутрь NTDLL.DLL, в толщу служебного кода, выполняющего поиск и передачу управления на SEH-обработчик, который нас интересует больше всего. Как в него попасть? Отладчик не дает ответа, а тупая трассировка требует немало времени.
Впрочем, SEH — это ерунда. Начиная с XP появилась поддержка обработки векторных исключений (VEH), усиленная в Server 2003 и, соответственно, в Висте / Server 2008. Отладчики об этом вообще не знают, открывая разработчикам защит огромные возможности для антиотладки и обламывая начинающих хакеров косяками. Я покажу, как побороть SEH/VEH-штучки в любом отладчике типа Syser, Soft-Ice или WinDbg. К сожалению, OllyDbg содержит грубую ошибку в «движке» и для отладки SEH/VEH-программ не подходит. Ну не то чтобы совсем не подходит, но повозиться придется (секс будет — и много).
SEH fundamentals
Архитектура структурных исключений подробно описана в десятках книг и сотнях статей. Настолько подробно, что, читая их, можно уснуть. Поэтому краткое изложение основных концепций, выполненное в моем фирменном стиле, не помешает.
Исключение, сгенерированное процессором, тут же перехватывается ядром операционной системы, которое его долго и нудно мутузит, но в конце концов возвращает управление на прикладной уровень, вызывая функцию NTDLL.
. При пошаговой трассировке отладчики прикладного/ядерного уровня пропускают ядерный код, сразу же оказываясь в NTDLL.
. То есть при трассировке кода XOR
/MOV
следующей выполняемой командой оказывается первая инструкция функции NTDLL.
. Сюрприз, да?
При выполнении KiUserCallbackDispatcher
извлекает указатель на цепочку обработчиков структурных исключений, хранящийся по адресу FS:[
, и вызывает первый обработчик через функцию ExecuteHandler, передавая ему специальные параметры.
В зависимости от значения, возвращенного обработчиком, функция KiUserCallbackDispatcher
либо продолжает «раскручивать» список структурных исключений, либо останавливает «раскрутку», возвращая управление коду, породившему исключение. Исходя из типа исключения (trap или fault) управление передается либо машинной команде, сгенерировавшей исключение, либо следующей инструкции (подробнее об этом можно прочитать в мануалах Intel).
Список обработчиков структурных исключений представляет собой простой односвязный список.
Формат списка обработчиков структурных исключений
_EXCEPTION_REGISTRATION struc
prev dd ? ; // Предыдущий обработчик, -1 — конец списка
handler dd ? ; // Указатель на SEH-обработчик
_EXCEPTION_REGISTRATION ends
Обработка структурных исключений имеет следующий прототип и возвращает одно из трех значений, описанных в MSDN: EXCEPTION_CONTINUE_SEARCH
, EXCEPTION_CONTINUE_EXECUTION
или EXCEPTION_EXECUTE_HANDLER
.
Прототип обработчика структурных исключений
handler(PEXCEPTION_RECORD pExcptRec, PEXCEPTION_REGISTRATION pExcptReg,
CONTEXT * pContext, PVOID pDispatcherContext, FARPROC handler);
Обработчики структурных исключений практически полностью реентерабельны — обработчик также может генерировать исключения, корректно подхватываемые системой и начинающие раскрутку списка обработчиков с нуля. «Практически» — потому что, если исключение возникает при попытке вызова обработчика (например, из‑за исчерпания стека), ядро просто молчаливо прибивает процесс. Но это уже дебри технических деталей, в которые мы пока не будем углубляться.
После установки своего собственного обработчика не забывай его снимать, иначе есть шанс получить весьма неожиданный результат. Причем система игнорирует попытку снять обработчик внутри самого обработчика, и это нужно делать только за пределами его тела.
Вот абсолютный минимум знаний, который нам понадобится для брачных игр со структурными исключениями.
VEH fundamentals
Начиная с XP появилась поддержка векторных исключений — разновидность SEH, однако реализованная независимо от нее и работающая параллельно. Другими словами, добавление нового векторного обработчика никак не затрагивает SEH-цепочку, и, соответственно, наоборот.
Механизм обработки векторных исключений работает по тому же принципу, что и SEH, вызывая уже знакомую нам функцию NTDLL.
. В свою очередь, она вызывает NTDLL.
, раскручивающую список векторных обработчиков с последующей передачей управления.
SEH и VEH концептуально очень схожи. Они предоставляют одинаковые возможности, и вся разница между ними в том, что вместо ручного манипулирования со списками обработчиков теперь у нас есть API-функции AddVectoredExceptionHandler
и RemoveVectoredExceptionHandler
, устанавливающие векторные обработчики и удаляющие их из списка, указатель на который хранится в неэкспортируемой переменной _RtlpCalloutEntryList
внутри NTDLL.DLL (по одному экземпляру на каждый процесс). Плюс упростилось написание локальных/глобальных обработчиков исключений, что в случае с SEH — большая проблема. Но по‑прежнему векторная обработка придерживается принципа «социального кодекса»: все обработчики должны следовать определенным правилам и ничто не мешает одному из них объявить себя самым главным и послать других на хрен.
Поскольку 9x/W2K-системы еще достаточно широко распространены, пользоваться векторной обработкой без особой на то нужды могут только дураки. Во всяком случае, необходимо использовать динамическую загрузку векторных функций, экспортируемых библиотекой KERNEL32.DLL, и, если их там не окажется, либо выдать сообщение об ошибке, либо дезактивировать защитный модуль, работающий на базе VEH.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»