Содержание статьи
Какие бывают хуки
Ловушки (hook) могут быть режима пользователя (usermode) и режима ядра (kernelmode). Установка хуков режима пользователя сводится к методу сплайсинга и методу правки таблиц IAT. Ограничения этих методов очевидны: перехватить можно только userspace API, а вот до функций с префиксом Zw*, Ki* и прочих «ядерных» из режима пользователя дотянуться нельзя.
Установка хуков режима ядра позволяет менять любую информацию, которой оперирует Windows на самом низком уровне. Для перехватов подобного типа необходимо модифицировать таблицы SSDT/IDT либо менять само тело функции (kernel patch). Надо сказать, что в Windows на архитектуре x64 ядро контролирует свою целостность при помощи механизма KPP (Kernel Patch Protection), который является частью PatchGuard и просто так подобные манипуляции с системными таблицами сделать не позволит.
Почему хуки работают?
Когда Windows запускает приложение, создается его процесс и потоки, загрузчик ОС ищет зависимости динамических библиотек, которые нужны для работы программы. Поиск ведется сначала в папке, где находится исполняемый файл, далее в нескольких системных папках. После того как нужные библиотеки найдены, определяются необходимые для работы функции, составляется таблица зависимостей функций и библиотек, где они находятся. Программа помнит все эти данные и пользуется ими при вызове функций. Наша задача — загрузить в адресное пространство приложения нашу библиотеку и исправить таблицу зависимостей в программе таким образом, чтобы она думала, будто функции, которые ей нужны, находятся именно в нашей библиотеке, а не в той, где они были раньше.
Сплайсинг функций WinAPI
Пролог функций, трамплин и дизассемблер длин инструкций
Функции WinAPI начинаются с пролога — это стандартный код, отвечающий за балансировку стека для корректного доступа к локальным переменным, которые использует функция. Обычно пролог выглядит таким образом:
mov edi,edi
push ebp
mov ebp,esp
В большинстве функций он одинаков, и поэтому на его место можно добавить инструкцию безусловного перехода jmp, которая передаст управление на наш код. Это называется «трамплин» — мы просто уводим поток выполнения функции в наш код, где делаем все, что хотим: можем подменить результат выполнения функции, можем вызвать какой-то другой код, запустить процесс — одним словом, массу всего. Но чтобы грамотно реализовать перехватчик функций методом сплайсинга, нам нужен дизассемблер длин инструкций.
![](/wp-content/themes/engine/img/info-icon.jpg)
INFO
Дизассемблер длин позволяет вычислять длины команд процессора. Часто используется для анализа прологов функций.
Зачем нам использовать дизассемблер длин, если мы и так знаем пролог функций? Дело в том, что прологи функций отличаются. Не хотелось бы постоянно заглядывать в дизассемблер и проверять, подходит ли пролог очередной перехватываемой функции под наш сплайсер. В нем ведь четко прописано, какое количество байтов мы будем использовать.
В том случае, если мы «настроим» нашу функцию сплайсинга на стандартный пролог, а он окажется другим, то после реализации перехвата выполнение может пойти не с начала машинной команды, а с какой-то ее части. Одним словом, мы повредим код программы, она вызовет исключение и будет аварийно завершена операционной системой. Если же использовать дизассемблер длин инструкций, то сплайсер всегда точно будет знать, где начинается следующая инструкция, и корректно встраивать трамплин.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»