Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
192
Добавлен:
20.02.2016
Размер:
86.02 Кб
Скачать

Отключение фильтра от устройства

Для отключения фильтра от устройства (при получении запроса на отключение фильтра, либо при вызове функции выгрузки драйвера) необходимо:

  • С помощью вызова ObDereferenceObject() уменьшить счетчик ссылок на объект-файл, полученный в результате вызова IoGetDeviceObjectPointer(). Этот указатель мы помещали в структуру DeviceExtension объекта-устройства фильтра.

  • Для отключаемого объекта-устройство вызвать IoDetachDevice() и IoDeleteDevice().

В случае выгрузки драйвера мы должны повторить эту последовательность действий для каждого устройства-фильтра из списка устройств драйвера. Напомним, что список принадлежащих драйверу устройств организуется с помощью полей DriverObject->DeviceObject(первое устройство в списке) и

DeviceObject->NextDevice(следующее устройство в списке). Если значение поляDeviceObject->NextDeviceравно NULL, то достигнут конец списка.

Обработка запроса в/в устройством-фильтром

При получении устройством-фильтром пакета IRPмы выводим вDbgPrintинформацию для известных нам типов запросов (IRP_MJ_CREATE,IRP_MJ_CLOSE,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_DEVICE_CONTROL,IRP_MJ_INTERNAL_DEVICE_CONTROL) и код ввода/вывода для всех остальных типов запросов, после чего передаем пакет в/в фильтруемому устройству.

Подготовку стека в/в для фильтруемого устройства можно сделать двумя способами: не очень правильный и правильный.

Не очень правильный способ – использование того же элемента стека, который бы передан для фильтра.

Правильный – заполнение элемента стека нижележащего (фильтруемого) устройства.

Для использования элемента стека самого фильтрамы должны установить текущий стек размещения в/в в пакетеIRPна предыдущий стек размещения в/в и передатьIRPфильтруемому устройству:

Irp->CurrentLocation++;

Irp->Tail.Overlay.CurrentStackLocation++;

NtStatus = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);

Установка функции завершения в/в (CompletionRoutine)

Для установки функции завершения (см. лекцию 9 п. [9.2.2.5] Получение драйвером вышележащего уровня уведомления о завершении обработки IRP драйвером нижележащего уровня). В этом случае перед отправкой пакета IRPдрайверу нижележащего уровня (см. предыдущий раздел) необходимо установить вIRPфункцию завершения, предварительно сделав текущим предыдущий элемент стека размещения в/в:

Irp->CurrentLocation++;

Irp->Tail.Overlay.CurrentStackLocation++;

IoSetCompletionRoutine(Irp, FilterDevDispatchComplete, FilterDeviceObject, TRUE, TRUE, TRUE);

NtStatus = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);

В приведенном примере мы использовали для нижележащего драйвера тот же стек размещения в/в, который использовали в фильтре. Это может быть не очень хорошо. Более корректная реализация использует дополнительный элемент стека размещения в/в:

CurStack = IoGetCurrentIrpStackLocation(Irp);

NextStack = IoGetNextIrpStackLocation;

*NextStack = *CurStack;

IoSetCompletionRoutine(Irp, FilterDevDispatchComplete, FilterDeviceObject, TRUE, TRUE, TRUE);

NtStatus = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);

Такое присваивание можно делать, только если способы передачи буферов у фильтра и фильтруемого устройства совпадают.

Когда драйвер нижележащего уровня завершит обработку переданного ему пакета IRPс установленной функцией завершения, будет вызвана эта функция. Прототип функции завершения:

NTSTATUS FilterDevDispatchComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)

Следует иметь ввиду, что первым параметром является указатель на объект-устройство, которое завершило обработку IRP, т.е. адрес объекта-устройстванижележащего уровня. Чтобы в функции завершения получить доступ к объекту-устройству фильтра, следует передавать его адрес в параметре Context. Его значение устанавливается в 3-м параметре функции IoSetCompletionRoutine().

Для получения доступа к главному функциональному коду запроса IRPнеобходимо воспользоваиться стеком размещения в/в. Трудность может возникнуть в том, какой стек размещения в/в выбрать. Если будет выбран текущий стек размещения в/в (IoGetCurrentIrpStackLocation ()), это будет являться ошибкой, т.к. это стек нашего устройства-фильтра, в нем нет информации о запросе в/в для нижележащего устройства. Поэтому следует выбирать стек размещения в/в нижележащего устройства (IoGetNextIrpStackLocation ()).

При использовании функции завершения следует быть осторожным с выгрузкой драйвера. Представим ситуацию:

  • запрос IRPбыл перехвачен драйвером-фильтром и передан драйверу нижележащего уровня. При этом в пакетеIRPустановлен адрес функции завершения из драйвера-фильтра.

  • Обработка запроса драйвером нижележащего уровня была отложена.

  • Драйвер-фильтр получает команду на отключение от драйвера нижележащего уровня и выгружается.

  • Драйвер нижележащего уровня завершает запрос IRP, после чего происходит попытка вызова уже несуществующей функции завершения из драйвера-фильтра. Система падает.

Чтобы такая ситуация не происходила, драйвер-фильтр после отключения от драйвера нижележащего уровня должен ждать завершения обработки всех запросов IRP, для которых он устанавливал функцию завершения. Только после этого он может безопасно выгрузиться.

Код функции завершения должен содержать проверку поля Irp->PendingReturned. Если оно ненулевое (TRUE), пакет должен быть помечен как отложенный с помощью вызова функции IoMarkIrpPending().

if(Irp->PendingReturned)

{

IoMarkIrpPending(Irp);

}

Это нужно из-за того, что флаг отложенного завершения хранится в стеке размещения в/в.

Возвращаемым значением для функции завершения драйвера-фильтра обычно будет STATUS_SUCCESS.

Соседние файлы в папке Лабы по драйверам