жонглирование ядром ФЛЕНОВ МИХАИЛ AKA HORRIFIC Спецвыпуск: Хакер, номер #071, стр. 071-030-3 Каждая программа должна иметь точку входа. Программисты C++ знакомы с такой точкой хорошо и привыкли, что ее имя WinMain. У драйвера такую точку называют DriverEntry, и она имеет следующий вид: NTSTATUS STDCALL DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) Эта процедура получает в качестве параметра два значения: 1 PDRIVER_OBJECT — УКАЗАТЕЛЬ НА СОЗДАННЫЙ ДРАЙВЕР. 2 PUNICODE_STRING – СТРОКА, СОДЕРЖАЩАЯ РАЗДЕЛ РЕЕСТРА, ГДЕ ПРОПИСАН ДРАЙВЕР. Конечно же, имя функции DriverEntry не является обязательным, и ты можешь ее назвать по-другому, но лучше следовать этому правилу, потому что читабельность кода никто не отменял. А вот количество и типы параметров менять вообще не желательно. Вот так вот может выглядеть простейший драйвер на С: #include <ntos.h> NTSTATUS STDCALL DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { return STATUS_UNSUCCESSFUL; } [загрузка драйвера.] Драйверы, как и сервисы, прописаны в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services. Здесь для каждого драйвера прописаны его параметры, и ты можешь прочитать их. Здесь же желательно сохранять параметры работы драйвера. Для хранения параметров необходимо использовать ветку реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Имя\Parameters, где «Имя» – имя драйвера. В качестве результата функция возвращает тип данных NTSTATUS. Если результат равен STATUS_SUCCESS, то драйвер считается загруженным верно и может обрабатывать ввод/вывод информации. Иначе драйвер не загружается в память и не может использоваться. При выгрузке драйвера вызывается функция Dispatch, которая выглядит следующим образом: NTSTATUS STDCALL Dispatch( IN PDEVICE_OBJECT DriverObject, IN PIRP Irp) Если драйвер может быть выгружен во время работы системы, то необходимо реализовать еще и функцию Unload, которая должна выглядеть следующим образом: VOID Unload ( IN DRIVER_OBJECT DeriverObject ); Многоуровневые драйвера должны реализовывать функцию IoCompletion, в которой необходимо освобождать структуру Irp: NTSTATUS IoCompletion ( IN PDEVICE_OBJECT DeriverObject, IN PIRP Irp, IN VOID Contex ); [ввод/вывод.] Драйвера ввода/вывода должны создавать логическое, виртуальное или физическое устройство, с которым будет происходить обмен ввода/вывода. Такое устройство создается с помощью функции IoCreateDevice. Описывать эту функцию не будем, потому что она содержит аж 7 параметров и имеет кучу особенностей. Если ты будешь писать драйвера устройств, то обратись к MSDN. Для удаления устройства используется функция IoDeleteDevice. Создав устройство, можно создавать символическую ссылку на него с помощью функции IoCreateSymbolicLink. Если ты создашь ссылку, к примеру, с именем «xakep», драйвер будет виден в системе /device/xakep. [приоритеты прерываний.] Исполняемый код имеет определенный уровень прерывания IRQL (interrupt request levels), по которому определяется, что позволено делать, а что нет. Это не уровень потока, это именно уровень прерывания. Всего таких прерываний 32. Прерывание с нулевым номером обладает низшим приоритетом, а №31, соответственно, наивысшим. Наивысшим уровнем обладают прерывания устройств, эти IRQL соответствуют аппаратным прерываниям. Два низших прерывания реализованы программно. |