coding Deeoni$ / DeeoniS@gmail.com / Реестр Ядерный перехват. Часть первая Перехват обращений к реестру в Windows Vista Новая ОС от Майкрософт постепенно начинает занимать свою нишу на рынке. Основным аргументом MS в пользу Windows Vista является ее безопасность. Однако в погоне за этой безопасностью сотрудники мегакорпорации перекрыли кислород производителям антивирусов и файрволов. Случайно это было сделано или преднамеренно, судить не нам. А мы разберемся с тем, как жить при подобной несправедливости. / 124 xàêåð 05 /101/ 07
coding Официальный отладчик режима ядра от MS Внутреннее устройство Windows се, наверное, знают замечательную В утилиту от Марка Руссиновича под названием RegMon. Эта тузла показывает, какой процесс к какому ключу реестра хочет обратиться. В ОС семейства NT это было реализовано с помощью драйвера, который перехватывал соответствующие системные сервисы. Подобной технологией пользовались практически все антивирусы и персональные файрволы, но с выходом Windows Vista эту «дыру» (по мнению Майкрософт) прикрыли. Официальная причина — чтобы противостоять действию руткитов, однако еще до выхода релиза знаменитый PatchGuarg (так называется технология защиты ядерного кода от патча) поломали раз десять. Разработчики серьезного ПО, естественно, не станут ломать эту «защиту», а воспользуются альтернативными способами. Инструментарий Итак, мы собрались писать драйвер, а для этого нам понадобятся некоторые дополнительные инструменты. Хочу сразу предупредить, что этот материал ориентирован на людей, которые достаточно хорошо программируют на прикладном уровне, но ни разу не сталкивались с кодом для ядра. Поэтому, если ты имеешь подобный опыт, можешь просто просмотреть текст, так как что-то новое в нем ты вряд ли найдешь. Первым делом нам понадобится компилятор. Стандартом здесь является пакет от MS — DDK (Driver Development Kits). В него входит много всего полезного, но, к сожалению, нет оболочки для редактирования кода, так что об этом надо тоже позаботиться. Когда мы начнем писать более-менее серьезные драйверы, нам понадобится отладчик режима ядра. Самыми известными являются SoftICE и WinDbg. SoftICE хорош тем, что драйверы можно отлаживать прямо на своей машине, а вот для WinDbg нужен второй компьютер. Но отлаживать драйвер на своей машине — это то же самое, что самому делать операцию на собственном мозге. Так что советую использовать WinDbg в тандеме с виртуальной машиной. Еще нам пригодится DbgView — утилита от уже упомянутого здесь Руссиновича, которая позволяет просматривать отладочные сообщения от драйвера в реальном времени без отладчика. Писать драйвер мы будем под Висту, поэтому, чтобы избежать лишних проблем, нужно найти последние версии всего упомянутого выше. Основа драйвера Теперь приступим непосредственно к программированию. Написать минимальный драйвер, оказывается, очень просто. Надо всего лишь определить тело функции DriverEntry(). Чтобы наш драйвер успешно загрузился и не вызвал при этом голубого экрана смерти (BsoD), нужно написать следующие строки: Код минимального драйвера NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status = STATUS_ DEVICE_CONFIGURATION_ERROR; return status; } Если мы скомпилируем драйвер и попробуем его загрузить (о том, как это сделать, я расскажу чуть позже), он завершит свою работу и будет выгружен из памяти, поскольку мы вернули код ошибки. Если бы мы не сделали этого, драйвер висел бы в памяти бесконечно, так как пока у нас нет функции DriverUnload, ответственной за выгрузку драйвера. Теперь надо разобраться с параметрами, передаваемыми в функцию, и их типами, так как некоторые уже могли заметить, что, например, PUNICODE_STRING никогда раньше не встречался в программировании для юзер-мода. Сама функция DriverEntry — это входная точка в модуль, именно этой функции передается управление при загрузке драйвера. Первый параметр pDriverObject — это указатель на объект только что созданного драйвера. Windows является объектно-ориентированной системой; загружая драйвер, система создает объект «драйвер» (driver object), представляющий для нее образ драйвера в памяти. Через этот объект система управляет драйвером. На самом деле, это вовсе не объект в классическом понимании, а просто некая структура данных типа DRIVER_OBJECT, определение которой можно посмотреть здесь: \include\w2k\ntddk.inc. Некоторые поля этой структуры заполняет система, некоторые придется заполнять нам самим. Обращаясь к этой структуре, система и управляет драйвером. Следующий параметр — это pRegistryPath. Он является указателем на unicode-строку, которая, в свою очередь, указывает на путь к разделу реестра, содержащему параметры инициализации драйвера. Структуру этого раздела, как xàêåð 05 /101/ 07 / 125