Часто приходится писать небольшие утилиты, которым необходима поддержка со стороны ядра. Для этого нужно писать отдельный драйвер. Но "таскать" драйвер с файлом утилиты некрасиво. Поэтому есть довольно простой способ - слинковать модуль драйвера с PE-файлом user mod'ного exe-шника.
Что бы не писать постоянно один и тот же код по распаковке модуля драйвера на носитель и его загрузке в систему я написал небольшой класс TResourceDrv. Основные особенности класса:
- класс использует ATL-обёртки описателей
- класс не генерирует исключений
- класс работает с кучей по умолчанию текущего процесса
Класс содержит 2-а основных публичных метода. Метод LoadDriver:
ULONG LoadDriver( IN PCWSTR wszResourceName, IN PCWSTR wszResourceType, IN PCWSTR wszDriverName, IN DWORD dwDrvRegType = SERVICE_KERNEL_DRIVER, IN DWORD dwDrvRegStart = SERVICE_DEMAND_START, IN PCWSTR wszDrvRegDisplayName = NULL, IN DWORD dwDrvRegErrorControl = SERVICE_ERROR_NORMAL ) throw();
Параметры метода:
- wszResourceName - имя ресурса модуля драйвера
- wszResourceType - имя типа ресурса модуля драйвера.
- wszDriverName - короткое имя службы драйвера. Фактически это имя ключа реестра драйвера.
- dwDrvRegType - тип драйвера. По умолчанию 1 - SERVICE_KERNEL_DRIVER.
- dwDrvRegStart - тип запуска драйвера. По умолчанию 3 - SERVICE_DEMAND_START.
- wszDrvRegDisplayName - отображаемое имя дравера. По умолчанию NULL.
- dwDrvRegErrorControl - уровень контроля ошибок запуска драйвера. По умолчанию 1 - SERVICE_ERROR_NORMAL.
Возвращаемое значение:
ERROR_SUCCESS в случае, если загрузка драйвера произведена успешно. Или иной код Win32-ошибки в случае неудачи.
Данный метод извлекает модуль драйвера из ресурсов в файл. Созданный файл располагается в директории "%WINDIR%\System32\Drivers\". Далее формируется ключ драйвера в реестре, записывая указанные параметры. Если действия по формированию файла и ключа реестра драйвера завершены успешно, то метод загружает драйвер вызовом функции ntdll!NtLoadDriver(...). Перед загрузкой драйвера, если это необходимо, метод пытается разрешить текущему процессу привилегию загрузки/выгрузки драйверов SE_LOAD_DRIVER_NAME.
Второй метод - UnloadDriver:
ULONG UnloadDriver() throw();
Возвращаемое значение:
ERROR_SUCCESS в случае, если выгрузка драйвера произведена успешно. Или иной код Win32-ошибки в случае неудачи.
Метод выгружает драйвер, который был загружен успешным вызовом метода LoadDriver.
Updated (28.04.2011)
Класс загрузки драйвера из ресурсов был мною немного переработан до версии 0.1.1.0. В частности, в список изменений входит:
- Интерфейс IProcessBeforeWrite был удален.
- Работа с ntdll.dll переписана на динамический импорт.
- Объявление нативных функций/структур обзавелись префиксом для избежания конфликта с другими файлами проекта.
- Работа с памятью полностью переписана на ATL. Использован CAtlArray, что сохранило отсутствие генерации исключений.
- Добавлена опция: не выгружать драйвер при уничтожении объекта.
Для задания опции, указывающей объекту класса TResourceDrv не выгружать драйвер в деструкторе, появился конструктор с bool-параметром:
TResourceDrv( bool bUnloadOnDestroy ) throw();
И отдельный метод установки опции:
void SetUnloadOnDestroy( __in bool bUnloadOnDestroy = true ) throw();
Описанный класс в исходном коде можно скачать здесь.
ΞρεΤΙκ