Как писать драйвера (часть 5)
Как писать драйвера (часть 5)
Итак, мы возвращаемся к драйверам.
Справедливости ради, стоит отметить, что на сайте эта тема – одна из самых популярных, так что, кому нужны более глубокие знания, может обращаться к нам на форум, там обсуждаются конкретные проблемы.
Сегодня мы поговорим о коммуникации программы с драйвером.
В одной из предыдущих статей описаны были функции типа Filter:
Вот они:
extern NTSTATUS FilterOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
extern NTSTATUS FilterClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
extern NTSTATUS FilterRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
extern NTSTATUS FilterWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
extern NTSTATUS FilterIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
В любом драйвере необходима система управления, для указания самому драйверу, какого типа операцию стоит выполнить в текущий момент времени.
Скажем для нашего примера, драйверу фильтра потока данных по сети стоит указывать степень фильтрации, типы портов для перехвата, адреса, запрещенные к обращению и т.п.
Для этого используются вышеназванные функции.
FilterOpen вызывается когда в программе вызвано обращение к драйверу с помощью функции CreateFile
FilterClose – CloseHandle()
FilterRead/FilterWrite – ReadFile/WriteFile
FilterIoControl – DeviceIoControl() соответственно.
Для правильного завершения работы каждой из этих функций – нужно обеспечить передачу в программу необходимых данных.
NTSTATUS FilterOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
// инициализация любых управляющих параметров, например структуры управляющих данных
Irp->IoStatus.Status = NDIS_STATUS_SUCCESS; // Возращаемое значение – ошибка или нормальное. При нормальном завершении – будет передан HANDLE на устройство, в нашем случае на драйвер.
Irp->IoStatus.Information = 0; // Количество переданных вверх байт – в нашем случае 0 потому как нет передаваемых параметров.
IoCompleteRequest(Irp, IO_NO_INCREMENT); // Завершение работы.
return NDIS_STATUS_SUCCESS; // Нормальный код возврата.
}
Эта форма будет использоваться в том или ином виде в каждой из этих функций.
Точно так же выглядит и функция закрытия:
NTSTATUS FilterClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
// Код окончания работы с драйвером.
Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return NDIS_STATUS_SUCCESS;
}
В драйвере можно создать например просто элемент для нашего примера – например, описать глобальную переменную DWORD Port; Ее будем испрользовать для задания номера порта для перехвата.
Определим Default значение для порта равное 80 (стандартный порт http протокола) и проведем его инициализацию в функции Open и де инициализацию в Close. Так мы сможем контролировать старт активной фазы работы драйвера и ее окончание.
Функции Write & Read можно использовать для передачи любого количества информации в драйвер и обратно.
Для сложных случаев и частой передачи необходимо использовать именно эти функции, из-за того, что переключение контекста драйвера не происходит. При использовании для этих целей DeviceIoControl приведет к постоянному переключению контекста драйвера и замедлит работу системы.
В нашем примере передавать в драйвер и назад нечего поэтому напишем Write/Read функции в виде готовых болванок, но так как наша цель построить работающий пример – то передадим абстрактную последовательность вверх в аппликацию.
Для этого создайте в этом же месте глобальную переменную вот такого вида:
unsigned char TestStr[10] = "abcdefghi";
NTSTATUS FilterRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG BytesReturned = 0;
////////////////////////////////////////////////////////////////////////
// Get input parameters
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation( Irp ); // Содержит стек Irp
ULONG BytesRequested = IrpStack->Parameters.Read.Length; // Длина принятых данных –равна параметру максимально запрошенной длины в функции ReadFile
if (BytesRequested <10) // Если запрошено меньше нашей тестовой длины – вернуть ошибку
{
BytesReturned = 0;
Status = STATUS_INVALID_BUFFER_SIZE;
} else {
// Если все в порядке – копировать буфер в выходной буфер стека.
NdisMoveMemory(Irp->AssociatedIrp.SystemBuffer, TestStr, 10);
BytesReturned = 10;
Status = NDIS_STATUS_SUCCESS;
}
// Отправить
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesReturned;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
///////////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS FilterWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG BytesReturned = 0;
// Здесь все работает аналогично.
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesReturned;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
Функции симметричны.
Теперь мы подошли к функции управления.
Она сама работает точно также как и все функции перечисленные выше – с одной разницей: В ней принимаемым параметром является код операции, который надо установить в драйвер.
Можно конечно придумать свой формат данных – передаваемых в WriteFile, который расшифровывать внутри драйвера и так решать, что делать или не делать, однако стоит использовать уже готовый механизм, предоставленный Microsoft-ом.
Описание кода комманды выглядит так:
#define IOCTL_SET_COMMAND1 // наш код управления
CTL_CODE ( FILE_DEVICE_UNKNOWN, // Тип кода
0xF07, // Цифровое значение
METHOD_BUFFERED, // Метод операции
FILE_ANY_ACCESS ) // Права доступа.
Итак мы описали код управления, вызов которого будет выглядеть в программе так:
res = DeviceIoControl(
hFile, // Handle драйвера из функции CreateFile
(DWORD) IOCTL_SET_COMMAND1, // Комманда
(LPVOID)0, (DWORD)0, (LPVOID)NULL, (DWORD)0, (LPDWORD)&bytesReturned, NULL
);
Вызов такой функции приведет к обращению драйвером к функции FilterIoControl!
NTSTATUS FilterIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG BytesReturned = 0;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
PVOID InfoBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG InputBufferLen = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG OutputBufferLen = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch(IoControlCode) {
case IOCTL_SET_COMMAND1:
// Здесь мы можем сменить наш номер порта с 80 на, к примеру, 25.
break;
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesReturned;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
Описания Input/Output буферов привожу для того, чтобы при необходимости получения и еще каких либо сопутствующих параметров, было ясно, где их получать, скажем, в драйвере нашего примера, команда 1 может нести в качестве параметра новый номер порта для перехвата.
Давайте теперь опишем логику управления драйвером перехватчиком.
Для перехвата определяются в начале параметры перехвата, адрес, порт и т.д.
Далее вносится тип рабочего состояния – перехват – прозрачный режим.
Вносится список возможных портов к перехвату (по необходимости).
В процессе работы системы, пока управляющая аппликация не запущена, то драйверу необходимо указать стартовые параметры.
Например, тип режима – прозрачный, в этом случае не перехватывается ничего.
Когда стартует управляющая программа – то она открывает драйвер CreateFile() и запускает, если это необходимо, другие стартовые условия, например перевод в режим перехвата и номер порта для этого.
Затем по желанию клиента из программы выставляются любые нужные условия от отключения перехвата, до перехвата всех номеров портов и всех адресов.
По завершению работы контрольной программы, можно выставить спец код управления, который укажет, как жить драйверу, когда управление не запущено, отключить все настройки и вернуться к прозрачному режиму, или остаться в необходимом режиме до дальнейших указаний.
На сегодня пока все.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
О чем писать не нужно
О чем писать не нужно Не следует искажать данные: умышленно указывать больший опыт работы, сильно преувеличивать свои возможности, кривить душой относительно образования. Тайное, как правило, становится явным. В итоге и вы, и работодатель просто впустую потеряете
Что писать?
Что писать? Мост длиною в блог Метки: блоговедение, темы блога, что такое блогПисать обо всем сразу – это как плыть в броуновском движении, не сдвигаясь с места. Блог должен быть похож на мост: когда по нему идешь или едешь, то понимаешь, что рано или поздно окажешься на
Как писать
Как писать 33 буквы в руках мастера Метки: блогословие, приманкиВ любом учебнике по журналистике написано о том, что статья теряет читателей после каждого абзаца. А абзац, встречающий читателя, – это заголовок. В некоторых RSS-агрегаторах вообще не видно ничего, кроме
О чем, когда и как много писать
О чем, когда и как много писать Текстовый формат — основной для блогов и самый простой в реализации, поэтому каждый блогер должен владеть искусством написания текстов.Вопросы: о чем, через какой промежуток времени и в каком объеме писать в блог — волнуют очень многих
На каком языке писать сообщения?
На каком языке писать сообщения? Если ваш бизнес ориентирован на одну страну или языковую группу, то эта проблема перед вами не стоит. Другой вопрос, если группа международная. Вот скриншот (см. рис. 49), демонстрирующий подобный пример. В группе из 70 тысяч друзей 40 %
§ 55. Как писать слово «интернет»?
§ 55. Как писать слово «интернет»? — Ну что, Знайка? — стали спрашивать коротышки, подбегая к нему. — Как ты объяснишь это? — Что же тут объяснять? — развел Знайка руками?… Н. Носов. Незнайка на Луне В Академии наук Заседает князь Дундук. Говорят, не подобает Дундуку
Как писать драйвера (часть 1)
Как писать драйвера (часть 1) Предисловие. Драйвера под Windows являются для большей массы программистов, "тайной за семью печатями". И вовсе не потому, что это что-то архисложное, сколько по причине абсолютной недокументированности идеологии.Начав заниматься этой темой я
Часть первая: "Что нужно для компиляции простейшего драйвера?"
Часть первая: "Что нужно для компиляции простейшего драйвера?" Для разных типов Windows вам понадобиться разный набор программ.В любом случае надо скачать Win DDK (Driver Development Kit), для той платформы, под которую пишется драйвер. Его можно брать с разных источников, лично я
Как писать драйвера (часть 2)
Как писать драйвера (часть 2) Прежде, чем хвататься за описание самого драйвера, давайте определимся с типами существующих драйверов.По существующему в DDK разделению сам Microsoft подразделяет драйвера на следующие типы:– Kernel-Mode Drivers;– Kernel Streaming Drivers;– Graphics Drivers;– Network
Как писать драйвера (часть 5)
Как писать драйвера (часть 5) Итак, мы возвращаемся к драйверам.Справедливости ради, стоит отметить, что на сайте эта тема – одна из самых популярных, так что, кому нужны более глубокие знания, может обращаться к нам на форум, там обсуждаются конкретные проблемы.Сегодня мы
Часть 2. API для WDM драйвера.
Часть 2. API для WDM драйвера. Большинство функций драйверного API, которые нас интересуют, предоставляются модулем ntoskrnl.exe.Для их использования надо сделать следующее:1) Объявить типы данных и определить константы.Большинство определений для C находятся в файлах ntdef.h и wdm.h.2)
Совет 3 Умения писать код мало
Совет 3 Умения писать код мало Недостаточно выбрать технологию, на которую стоит сделать ставку. В конце концов, разве знание технологии — не товар, который нужно продать? Ты не сможешь расслабленно совершенствовать навыки программирования, оставив связанные с бизнесом
ПИСЬМОНОСЕЦ: Писать или дарить?
ПИСЬМОНОСЕЦ: Писать или дарить? Здравствуйте!Пишу двумя пальцами, ибо остальные: забинтованы…Эх, люди, вы наивно думаете, что судный день еще далеко, и всякие там толпы киборгов-убийц, бродящих по догорающим развалинам в поисках остатков человеческого рода, - сценарий для
Писать в периодические издания
Писать в периодические издания Хороший материал ищут многие газеты, журналы и бюллетени, освещающие вопросы безопасности. Если у вас есть что рассказать о технической поддержке, о продуктах, инструментах и т. п., то поделитесь своей информацией с другими. Это прекрасный