Иллюстрированный самоучитель по программированию систем защиты

Диспетчерские точки входа драйвера

Информация, требуемая для выполнения запроса ввода/вывода, содержится в различных элементах как фиксированной части IRP, так и стека размещения ввода/вывода. Рассмотрим эти элементы. Структура поля Parameters в стеке размещения ввода/ вывода зависит от кода главной и второстепенной функции ввода/вывода.

Нас в основном будет интересовать структура поля Parameters для запросов чтения, записи и пользовательских запросов ввода/вывода:

  1. IRPJVIJ_READ. Параметры для этого функционального кода содержат следующее:
    • Parameters.Read.Length (ULONG) содержит размер в байтах буфера инициатора запроса.
    • Parameters. Read.Key (ULONG) содержит ключевое значение, которое нужно использовать при чтении. Обычно представляет интерес только для драйверов файловой системы.
    • Parameters.Read.ByteOfFset (LARGE_INTEGER) содержит смещение (обычно в файле), с которого должна начаться операция чтения.
  2. IRP_MJ_WRITE. Параметры для этого функционального кода следующие:
    • Parameters. Write.Length (ULONG) содержит размер в байтах буфера инициатора запроса.
    • Parameters.Write.Key (ULONG) содержит ключевое значение, которое нужно использовать при записи. Обычно представляет интерес только для драйверов файловой системы.
    • Parameters.Write.ByteOffset (LARGE_INTEGER) содержит смещение (обычно в файле) с которого должна начаться операция записи.
  3. IRPJMJ_DEVICE_CONTROL. Параметры для этого функционального кода следующие:
    • Parameters.DeviceloControl.OutputBufferLength (ULONG) содержит длину в байтах буфера OutBuffer.
    • Parameters.DeviceloControl.InputBufferLength (ULONG) содержит длину в байтах буфера InBuffer.
    • Parameters. DeviceloControl.ControlCode (ULONG) содержит код управления вводом/выводом, идентифицирующий запрашиваемую функцию управления устройством. Этот управляющий код обычно предварительно определен драйвером с использованием макрокоманды CTL_CODE.
    • Parameters.DeviceloControl.TypeSInputBuffer (PVOID) содержит виртуальный адрес буфера инициатора запроса InBuffer (см. функцию Win32 API DeviceloControl()). Адрес обычно используется только тогда, когда IOCTL использует METHOD_NEITHER.

Запросы чтения и записи IRP_MJ_READ и IRPJVLMVRITE

Метод передачи буфера, используемый в запросах чтения и записи, контролируется полем Flags объекта-устройства. После создания объекта-устройства с помощью функции loCreateDevice() необходимо инициализировать это поле. Поле может иметь установленными несколько флагов, при этом применяются следующие правила:

  1. Если установлены флаги DO_BUFFERED_IO или DO_DIRECT_IO, метод передачи буфера будет соответственно буферизованным или прямым.
  2. Если поле флагов не инициализировано (никакие флаги не установлены), используется метод передачи буфера Neither ("никакой" ввода/вывода).
  3. Одновременная установка флагов DO_BUFFERED_IO и DO_DIRECT_IO запрещена и будет являться ошибкой.
  4. Установленный полем Flags метод передачи будет использован и запросом чтения, и запросом записи.

Расположение буфера в зависимости от метода его передачи для запросов чтения и записи полностью определяется таблицей 6.

Для завершения запроса IRP на чтение/запись, необходимо установить поле Irp>IoStatus.Information равным числу прочитанных/записанных в буфер байт. В случае буферизованного ввода/вывода это поле укажет Диспетчеру ввода/вывода, сколько байт нужно скопировать из промежуточного буфера в невыгружаемой области системного адресного пространства в пользовательский буфер.

Пример обработки запросов чтения/записи

Данный пример обработки запросов чтения/записи демонстрирует получение адреса буфера для чтения/записи и его длины. Такой код вставляется в обработчик диспетчерских функций MajorFunction[IRP__MJ_READ], MajorFuriction[IRP_MJ_WRITE].

//получение адреса буфера для чтения/записи
//в случае буферизованного ввода/вывода
BufferAddress = Irp › AssociatedIrp.SystemBuffer/
//в случае прямого ввода/вывода
BufferAddress = MmGetSystemAddressForMdl(Irp › MdlAddress)/ //в случае Neither i/o
BufferAddress = Irp › AssociatedIrp.UserBuffer;
//получение длины буфера для чтения/записи stack = = loGetCurrentlrpStackLocation (Irp);
BufferLength = stack › Parameters.Read.Length;
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.