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

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

Рассмотрим составляющие кода управления ввода/вывода:

  1. Поле DeviceType определяет тип объекта-устройства, которому предназначен запрос. Это тот самый тип устройства, который передается функции IoCreateDevice() при создании устройства. Как уже говорилось, существует два диапазона значений типов устройств: 0-32767 – зарезервированные значения для стандартных типов устройств, 32768-65535 – диапазон значений типов устройств для выбора разработчиком.
    Следует отметить, что несколько разных устройств могут иметь одинаковое значение типа устройства. Поскольку каждый запрос ввода/вывода предназначен конкретному устройству, совпадение типов устройств не приводит к неприятностям. Также необходимо отметить, что тип устройства в коде управления ввода/вывода может не совпадать с типом устройства объекта-устройства, и это не будет являться ошибкой.
  2. Поле Function идентифицирует конкретные действия, которые должно предпринять устройство при получении запроса/Значения поля Function должны быть уникальны внутри устройства. Как и для типов устройств, существует два диапазона значений поля Function: 0-2047 – зарезервированный диапазон значений, и 2048-4095 – диапазон значений, доступный разработчикам устройств.
  3. Поле Method указывает метод передачи буферов данных. Для понимания этого поля вернемся к функции DeviceloControl(). Функция передает два буфера – InBuffer и OutBuffer. Буфер InBuffer передает данные драйверу, буфер OutBuffer может передавать данные в обоих направлениях (к драйверу и от драйвера).

В следующей таблице приведены возможные значения поля Method и методы передачи буферов InBuffer и OutBuffer:

Значение поля Method Использование OutBuffer Используемый метод передачи буфера
InBuffer OutBuffer
METHOD BUFFERED   Буферизованный ввод/вывод (Buffered I/O)
METHOD_IN_DIRECT Передача данных к драйверу Буферизованный ввод/вывод Прямой ввод/вывод. Осуществляется проверка буфера на доступ по чтению
METHODJDUTJDIRECT Приема данных от драйвера Буферизованный ввод/вывод Прямой ввод/вывод. Осуществляется проверка буфера на доступ по записи
METHOD NEITHER   Neither I/O

Местоположение буферов данных в пакете IRP будет рассмотрено в следующем разделе ("Получение буфера").

  1. Поле Access указывает тип доступа, который должен был быть запрошен (и предоставлен) при открытии объекта-файла, для которого передается данный код Управления вводом/выводом. Возможные значения для этого параметра следующие:
    • FILE_ANY_ACCESS. Это значение указывает, что при вызове CreateFile() мог быть запрошен любой доступ.
    • FILE_READ_ACCESS. Это значение указывает, что должен был быть запрошен доступ для чтения.
    • FILE_WRITE_ACCESS. Это значение указывает, что должен был быть запрошен доступ для записи.

Заметим, что file_read_access и file_write_access могут быть указаны одновременно, чтобы указать, что при открытии устройства должен быть предоставлен и доступ на чтение, и доступ на запись.

Параметр Access требуется потому, что операции управления ввода/вывода, по своей сути не есть операция чтения или записи. Прежде, чем будет разрешена запрашиваемая операция ввода/вывода, Диспетчер Ввода/вывода должен знать, какой режим доступа нужно проверить в таблице описателей.

Получение буфера

При использовании буферизованного метода, Диспетчер ввода/вывода выделяет в системной невыгружаемой памяти промежуточный буфер, размер которого равен максимальному из размеров буферов InBuffer и OutBuffer. Если при запросе был определен InBuffer и его длина не нулевая, содержание InBuffer копируется в промежуточный буфер. В любом случае, адрес промежуточного буфера помещается в IRP в поле Associatedlrp.SystemBuffer. Затем IRP, содержащий запрос, передается драйверу.

Данные, находящиеся в промежуточном буфере, могут читаться и перезаписываться драйвером. Затем драйвер размещает в промежуточном буфере данные, которые нужно вернуть в OutBuffer.

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

При использовании методов METHOD_IN_DIRECT и METHOD_OUT_ DIRECT, буфер InBuffer, если он определен в запросе ввода/вывода и его длина не нулевая, обрабатывается в точности так же, как и при буферизованном вводе/выводе. В этом случае выделяется промежуточный буфер, в него копируется InBuffer, указатель на промежуточный буфер помещается в IRP в поле Associatedlrp.SystemBuffer.

Буфер OutBuffer, если он определен в запросе ввода/вывода и его длина не нулевая, обрабатывается в соответствии с прямым вводом/выводом. В этом случае адрес проверяется на возможность доступа (запись или чтение), производится закрепление физических страниц в памяти, и создается таблица описания памяти MDL, описывающая OutBuffer. Указатель на MDL передается в поле Irp › MdlAddress.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.