Смекни!
smekni.com

Переопределение назначений клавиш на клавиатуре в операционной системе Windows (стр. 2 из 5)

Стек клавиатуры обрабатывает несколько типов. В данной курсовой работе необходимо рассмотреть только IRP типа IRP_MJ_READ, которые несут с собой коды клавиш. Генератором этих IRP является поток необработанного ввода RawInputThread системного процесса csrcc.exe. Этот поток открывает объект «устройство» драйвера класса клавиатуры для эксклюзивного использования и направляет ему IRP типа IRP_MJ_READ. Получив IRP, драйвер Kbdclass отмечает его как ожидающий завершения (pending), ставит в очередь и возвращает STATUS_PENDING. Потоку необработанного ввода придется ждать завершения IRP. Подключаясь к стеку, драйвер Kbdclass регистрирует у драйвера i8042prt процедуру обратного вызова KeyboardClassServiceCallback, направляя ему IRP IOCTL_INTERNAL_KEYBOARD_CONNECT. Драйвер i8042prt тоже регистрирует у системы свою процедуру обработки прерывания (ISR) I8042KeyboardInterruptService, вызовом функции IoConnectInterrupt. Когда будет нажата или отпущена клавиша, контроллер клавиатуры выработает аппаратное прерывание. Его обработчик вызовет I8042KeyboardInterruptService, которая прочитает из внутренней очереди контроллера клавиатуры необходимые данные. Т.к. обработка аппаратного прерывания происходит на повышенном IRQL, ISR делает только самую неотложную работу и ставит в очередь вызов отложенной процедуры (DPC). DPC работает при IRQL = DISPATCH_LEVEL. Когда IRQL понизится до DISPATCH_LEVEL, система вызовет процедуру I8042KeyboardIsrDpc, которая вызовет зарегистрированную драйвером Kbdclass процедуру обратного вызова KeyboardClassServiceCallback (также выполняется на IRQL = DISPATCH_LEVEL). KeyboardClassServiceCallback извлечет из своей очереди ожидающий завершения IRP, заполнит структуру KEYBOARD_INPUT_DATA, несущую всю необходимую информацию о нажатиях / отпусканиях клавиш, и завершит IRP. Поток необработанного ввода пробуждается, обрабатывает полученную информацию и вновь посылает IRP типа IRP_MJ_READ драйверу класса, который опять ставится в очередь до следующего нажатия / отпускания клавиши. Таким образом, у стека клавиатуры всегда есть, по крайней мере, один, ожидающий завершения IRP и находится он в очереди драйвера Kbdclass.

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


1.5 Структура драйвера

Драйвер имеет следующие точки входа:

- DriverEntry

- DriverUnload

- AddDevice

- Функции для обработки пакетов IRP

- ISR

DiverEntry

Процедура DiverEntry должна присутствовать в любом драйвере. На данную процедуру возложена функция начальной инициализации и определение остальных точек входа в драйвер. Она выполняется в момент загрузки драйвера. В драйверах WDM значение этой функции значительно уменьшилось, большая часть работы возлагается на функцию AddDevice. Для регистрации точек входа в драйвер DriverEntry должна заполнить соответствующие поля в структуре объекта драйвера. Указатель на эту структуру передается в функцию.

Поле DriverUnload необходимо заполнить адресом процедуры, вызывающейся при выгрузке драйвера.

Поле DriverExtension->AddDevice необходимо заполнить адресом процедуры AddDevice.

Массив MajorFunctions заполняется адресами процедур обработки IRP пакетов. Процедура, зарегистрированная под номером N, обрабатывает IRP пакет с кодом N. Обычно драйверы используют не все эти процедуры, а регистрируют только нужные. Остальные же элементы массива заполняются адресом процедуры, выполняющей передачу пакета ниже по стеку драйверов.

AddDevice

Данная функция регистрируется, если драйвер поддерживает PnP. Одна из главных обязанностей AddDevice – это создание объекта устройства FDO и если необходимо подключение его к стеку драйверов устройства. Данная функция может создать несколько объектов устройств и подключить их к разным стекам. Более того, некоторые устройства FDO могут существовать, не будучи в связке с PDO. Они часто содаются для управления драйвером.

DriverUnload

Процедура DriverUnload необходима для того, чтобы сделать драйвер выгружаемым. В драйверах «в стиле NT» на эту процедуру возложен весь процесс выгрузки. Она обязана удалить все символьные ссылки, все объекты устройств, отключить (если нужно) прерывания от объектов, очистить память за собой. В PnP драйверах все эти действия возложены на обработчик пакетов IRP_MJ_PNP.

Процедуры обработки пакетов IRP

Функции, адреса которых записаны в массиве MajorFunctions, вызываются диспетчером ввода / вывода для обработки соответствующих запросов от клиентского драйвера (пользовательских приложений или модулей уровня ядра). Эти запросы оформляются в виде специальных структур – IRP пакетов.

При любом запросе Диспетчер формирует IRP. память для структуры IRP выделяется в нестраничной памяти. В IRP записывается код операции ввода вывода. Пакет IRP состоит из заголовка, который имеет постоянный размер и стека IRP. Стек имеет переменную длину.

Заголовок IRP пакета:

- Поле IoStatus типа IO_STATUS_BLOCKсодержит два подполя

- Status содержит значение, которое устанавливает драйвер после обработки пакета.

- В Information чаще всего помещается число переданных или полученных байт.

- Поле AssociatedIrp. SystemBuffer типа void* содержит указатель на системный буфер для случая если устройство поддерживает буферизованный ввод / вывод.

- Поле MdlAddress типа PMDL содержит указатель на MDL список, если устройство поддерживает прямой ввод вывод.

- Поле UserBuffer типа void* содержит адрес пользовательского буфера для ввода / вывода.

- Типа Cancel типа BOOLEAN– это индикатор того, что пакет IRP должен быть аннулирован.

Стек IRP пакета

Основное значение ячеек стека IRP пакета состоит в том, чтобы хранить функциональный код и параметры запроса на ввод / вывод. Для запроса, который адресован драйверу самого нижнего уровня, соответствующий IRP пакет имеет только одну ячейку стека. Для запроса, который послан драйверу верхнего уровня, Диспетчер ввода / вывода создает пакет IRP с несколькими стековыми ячейками – по одной для каждого FDO.

Каждая ячейка стека IRP содержит:

- MajorFunction типа UCHAR – это код, описывающий назначение операции

- MinorFunction типа UCHAR – это код, описывающий суб-код операции

- DeviceObject типа PDEVICE_OBJECT – это указатель на объект устройства, которому был адресован данный запрос IRP

- FileObject типа PFILE_OBJECT – файловый объект для данного запроса

Диспетчер ввода / вывода использует поле MajorFunction для того, чтобы извлечь из массива MajorFunction нужную для обработки запроса процедуру.

Каждая процедура обработки IRP пакетов должна в качестве параметров иметь:

- Указатель на объект устройства, для которого предназначен IRP запрос

- Указатель на пакет IRP, описывающий этот запрос

Возвращает такая функция значение типа NTSTATUS, содержащее результат обработки.

Функция обработки пакетов IRP_MJ_DEVICE_CONTROL

Эти функции позволяют обрабатывать расширенные запросы от клиентов пользовательского режима. Такой запрос может быть сформирован посредством вызова функции DeviceIoControl. Каждый IOCTL запрос имеет свой код. Этот код передается как параметр функции DeviceIoControl. Код IOCTL – это 32‑битное число.

Запросы IOCTL служат чаще всего для обмена данными между драйвером и приложением. Для передачи данных в Windows предусмотрены 4 способа

- METHOD_BUFFERED

Входной пользовательский буфер копируется в системный, а по окончании обработки системный копируется в в выходной пользовательский буфер.

- METHOD_IN_DIRECT и METHOD_OUT_DIRECT

Необходимые страницы пользовательского буфера загружаются с диска в оперативную память и блокируются. И с помощью DMA осуществляется передача данных между устройством и пользователем.

- METHOD_NEITHER

При данном методе передачи не производится проверка доступности памяти, не выделяются промежуточные буфера и не создаются MDL. В пакете IRP передаются виртуальные адреса буферов в пространстве памяти инициатора запроса ввода / вывода.

Функция обработки пакетов IRPMJREAD

Данная функция должна обрабатывать запросы на чтение информации из устройства.

Функция обработки пакетов IRPMJPNP

Данная функция должна обрабатывать запросы от менеджера PnP.

ISR

Данная точка входа вызовется при, когда произойдет прерывание, на которое зарегистрирована эта ISR функция. Вызов может произойти в любом контексте: как ядра, так и пользовательского процесса. Здесь драйвер может либо дожидаться следующего прерывания (с какой-либо целью), либо запросить отложенный вызов процедуры (DeferredProcedureCall), DPC


1.6 Анализ методов решения задачи

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