Факультет: Информатика исистемы управления
Кафедра: Программноеобеспечение ЭВМ и информационные технологии
РАСЧЕТНО-ПОЯСНИТЕЛЬНАЯЗАПИСКА
к курсовому проекту натему:
«Переопределениеназначений клавиш на клавиатуре
в операционной системе Windows»
2009 г.
Оглавление
Введение. 4
1.Аналитический раздел. 5
1.1 Постановка задачи. 5
1.2 Архитектура Windows XP. 5
1.3 Модель WDM… 8
1.4 Стек клавиатуры… 9
1.5 Структура драйвера. 12
DiverEntry. 12
AddDevice. 12
DriverUnload. 13
Процедуры обработки пакетов IRP. 13
Функция обработки пакетов IRP_MJ_DEVICE_CONTROL. 15
Функция обработки пакетов IRP_MJ_READ… 16
Функция обработки пакетов IRP_MJ_PNP. 16
ISR… 16
1.6 Анализ методов решения задачи. 17
2.Конструкторский раздел. 19
2.1 Точки входа разрабатываемогодрайвера-фильтра. 19
DiverEntry. 19
AddDevice. 20
DriverUnload. 21
Процедуры обработки пакетов IRP. 21
Функция обработки пакетов IRP_MJ_DEVICE_CONTROL. 21
Функция обработки пакетов IRP_MJ_READ… 22
Функция обработки пакетов IRP_MJ_PNP. 22
Обработка остальных пактов IRP. 23
2.2 Взаимодействие компонентовсистемы… 24
2.3 Размещение драйвера в памяти. 24
2.4 Переопределение клавиш… 25
2.5 Установка драйвера в системе. 27
3.Технологический раздел. 30
3.1 Выбор языка программированияи средств программирования. 30
Драйвер-фильтр. 30
Программа для установки драйвера. 31
Программа для управления драйвером. 31
3.2 Структуры данных проекта. 31
Информация о нажатиях и отпусканиях клавиш… 31
Структура списка замен. 33
Дополнительная информация. 33
3.3 Интерфейс управляющегоприложения. 34
3.4 Тестирование драйвера-фильтраклавиатуры… 35
Заключение. 37
Списоклитературы… 38
Введение
Очень частовозникает необходимость в переназначении клавиш на клавиатуре.
§ Стандартное расположениеклавиш неудобно при работе с определенным программным обеспечением
§ При переходе с одноготипа клавиатуры на другой трудно привыкнуть к новому расположению клавиш.
Во многихслучаях определенные клавиши могут помешать работе. Случайное нажатие на такиеклавиши замедляет работу пользователя. Желательно, чтобы нажатие этих клавиш неприводило ни к каким действиям.
Поэтомузадача переопределения и отключения клавиш является на сегодняшний деньактуальной.
Существуютпрограммы, решающие поставленную задачу. Примерами таких программ являютсяпрограмма Марка Руссиновича Ctrl2 и программа MagicKey.
Программа Ctrl2 заменяет клавишу CapsLock на клавишу «левый Ctrl». Она реализована в видедрайвера.
Программа MagicKey, позволяет менятьместами алфавитно-цифровые клавиши. Она реализована в виде драйвера ипользовательского приложения для управления этим драйвером.
1. Аналитический раздел
1.1 Постановка задачи
Всоответствии с заданием на курсовую работу, необходимо разработать программноеобеспечение, позволяющее переопределять назначение клавиш на клавиатуре.
§ Программноеобеспечение должно позволять переопределять все клавиши клавиатуры
§ Программноеобеспечение должно позволять отключать клавиши.
§ Программноеобеспечение должно позволять устанавливать список осуществляемых замен.
§ Программноеобеспечение не должно нарушать и замедлять работу системы./>1.2 Архитектура Windows XP
Windows XP является следующей – послеWindows 2000 и Windows Millennium – версией операционнойсистемы Microsoft Windows. Наиболее распространены реализации данной ОСдля платформы Intel x86 в одно- или многопроцессорных конфигурациях, однако существуюттакже версии для DEC Alpha и MIPS. Данная операционная система используетзащищённый режим центрального процессора, реализует механизмы виртуальнойпамяти и многозадачности.
Windows XP использует два уровняпривилегий: уровень привилегий 0, соответствующий коду режима ядра и уровеньпривилегий 3, соответствующий коду прикладных задач (всего существует четыреуровня привилегий). Уровень привилегий накладывает определённые ограничения: впользовательском режиме не могут выполняться привилегированные инструкциипроцессора и не разрешено обращение к защищённым страницам в памяти. Этиограничения накладываются для обеспечения безопасности работы системы.Пользовательское приложение не должно иметь возможность – в результате ошибкиили преднамеренно – вносить изменения в системные таблицы или в память другихприложений. В частности, такие ограничения запрещают пользовательскомуприложению напрямую управлять внешними устройствами.
В Windows XP обеспечение обменаданными и управление доступом к внешнему устройству возлагается на его драйвер.Ввод и вывод в драйверах осуществляется пакетами – IRP (Input/Output Request Packet). Запросы на ввод /вывод, посылаемые приложениями или другими драйверами, обрабатываютсядрайвером, после чего запрашивающей программе в том же пакете посылается статусзавершения операции.
Архитектураввода / вывода в Windows XP имеет иерархическую структуру. Для осуществленияоперации ввода / вывода пользовательское приложение должно вызвать одну изфункций API. Эта функция создает необходимый IRP пакет и направляет егоподсистеме ввода / вывода. Подсистема ввода / вывода направляет IRP пакет необходимомудрайверу. Драйвер осуществляет обращение к устройствам, используя функции HAL.
HAL (Hardware Abstraction Layer) – это слой программногообеспечения, который скрывает специфику аппаратной платформы от остальныхкомпонентов системы. Он обеспечивает малые затраты при переносе системы илиэлементов программного обеспечения. На Рис. 1. показана архитектура ввода /вывода Windows XP.
/>
Рис. 1.Архитектура ввода / вывода Windows XP
Управлениевнешним устройством в общем случае сводится к заполнению регистров контроллеранеобходимыми данными. Монопольный доступ драйвера к этим регистрамгарантируется операционной системой. Очевидно, что при данных обстоятельствахтребуется, чтобы драйвер устройства выполняется в режиме ядра. В архитектуре Windows XP существуют такназываемые драйверы виртуальных устройств для поддержки DOS‑приложений,исполняющиеся в реальном режиме.
Классификациядрайверов WindowsXP
§ Драйверы режима ядра
· Драйверыфайловых систем
· Унаследованные
· ДрайверыPlug and Play
· Видеодрайверы
§ Драйверыпользовательского режима
· Драйверывиртуальных устройств
1.3 Модель WDM
Windows Driver Model (WDM) – это стандартнаяспецификация Microsoft для разработчиков драйверов устройств. Она поддерживается воперационных системах Windows 98/Me/2000/XP. Компания Microsoft требует, чтобы все новыедрайверы под эти операционные системы создавались по этой спецификации. Дляэтого от них требуется чёткое следование структуре WDM, поддержка Plug and Play и управленияэлектропитанием.
Драйвернаямодель WDM построена на организации и манипулировании слоями «Объектовфизических устройств» и «Объектов функциональных устройств». Объект-устройство –это особая структура данных, создаваемая системой для взаимодействияпрограммного и аппаратного обеспечения. Объект PDO создается для каждогонайденного элемента аппаратуры, подключенного к шине данных. Объект FDO предлагает«олицетворение» каждой логической функции, которую видит в устройствепрограммное обеспечение верхних уровней.
/>
ФункциональнымОбъектам устройств разрешается окружать себя Объектами Фильтрами (Filter Device objects). Соответственно,каждому FiDO объекту сопоставлен драйвер, который выполняет определеннуюработу. Объукты фильтры подразделяются на фильтры нижнего уровня и фильтрыверхнего уровня. И тех и других может существовать произвольное количество. Онимодифицируют процесс обработки запросов ввода / вывода. Объекты FDO и FiDO отличаются только всмысловом отношении. FDO объект и его драйвер считаются главными. Ониобычно обеспечивают управление устройством, а объекты FiDO являютсявспомогательными.
Все объекты FDO и FiDO позиционируют себя встеке устройств. Порядок объектов в стеке определяет порядок обработки запросовввода-вывода. Если необходимо перехватить и обработать запрос, непосредственноидущий от пользователя, то нужно устанавливать верхний фильтр. Если же нужноотслеживать обращение к портам ввода вывода, обрабатывать прерывания, то нуженнижний фильтр. Данная модель позволяет драйверу устанавливать callback процедуры. Когда запросначинает обрабатываться, то он обрабатывается последовательно всеми драйверамистека устройства (исключая ситуацию, когда какой-либо драйвер сам завершитобработку запроса). После этого диспетчер ввода-вывода передает запрос callback процедуре каждогодрайвера стека. Сначала запрос передается callback процедуре последнегодрайвера который в стеке, потом процедуре предпоследнего драйвера и.т. д. Callback процедуры нужны длятого, чтобы обработать прочитанную из устройства информацию. Если фильтробрабатывает запросы на чтение, то когда этот запрос поступит в драйверинформация еще не будет считана. Поэтому драйверу необходимо установить callback функцию. При ее вызовезапрос уже будет содержать считанные данные.
1.4 Стек клавиатуры
Физическуюсвязь клавиатуры с шиной осуществляет микроконтроллер клавиатуры Intel 8042. Насовременных компьютерах он интегрирован в чипсет материнской платы. Этотконтроллер может работать в двух режимах: AT‑совместимом и PS/2‑совместимом.Почти все клавиатуры уже давно являются PS/2‑совместимыми. В PS/2‑совместимомрежиме микроконтроллер клавиатуры также связывает с шиной и PS/2‑совместимуюмышь. Данным микроконтроллером управляет функциональный драйвер i8042prt. Драйверi8042prt создает два безымянных объекта «устройство» и подключает один к стекуклавиатуры, а другой к стеку мыши. Поверх драйвера i8042prt, точнее, поверх егоустройств, располагаются именованные объекты «устройство» драйверов Kbdclass иMouclass. Драйверы Kbdclass и Mouclass являются так называемыми драйверамикласса и реализуют общую функциональность для всех типов клавиатур и мышей, т.е.для всего класса этих устройств. Оба эти драйвера устанавливаются каквысокоуровневые драйверы.
Стекклавиатуры обрабатывает несколько типов. В данной курсовой работе необходиморассмотреть только IRP типа IRP_MJ_READ, которые несут с собой коды клавиш.Генератором этих IRP является поток необработанного ввода RawInputThreadсистемного процесса csrcc.exe. Этот поток открывает объект «устройство»драйвера класса клавиатуры для эксклюзивного использования и направляет ему IRPтипа IRP_MJ_READ. Получив IRP, драйвер Kbdclass отмечает его как ожидающийзавершения (pending), ставит в очередь и возвращает STATUS_PENDING. Потокунеобработанного ввода придется ждать завершения IRP. Подключаясь к стеку,драйвер Kbdclass регистрирует у драйвера i8042prt процедуру обратного вызоваKeyboardClassServiceCallback, направляя ему IRPIOCTL_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 функция. Вызов может произойти в любом контексте: как ядра, так ипользовательского процесса. Здесь драйвер может либо дожидаться следующегопрерывания (с какой-либо целью), либо запросить отложенный вызов процедуры(Deferred Procedure Call), DPC
1.6 Анализ методов решения задачи
Всоответствии с заданием на курсовую работу, необходимо разработать программноеобеспечение, позволяющее переопределять назначение клавиш на клавиатуре. Изанализа архитектуры Windows XP следует, что для доступа к информации,содержащей скэнкоды нажатых или отпущенных клавишей необходимо написать драйвер.Драйвер может получить доступ к скэнкодам нажатых или отпущенных клавиш двумяспособами. Либо перехватывая IRP пакеты от других драйверов, либо самостоятельнообрабатывая прерывания от клавиатуры. Оптимальным является написание драйвера,который перехватывал бы IRP пакеты от драйвера клавиатуры, то есть написаниедрайвера-фильтра. В этом случае нет необходимости переписывать уже сделанныйдрайвер клавиатуры, нужно написать драйвер, изменяющий информацию в приходящих IRP пакетах.
Существуетдва типа драйверов фильтров: драйвер-фильтр верхнего и нижнего уровня. В рамкойданной задачи не имеет значения на каком этапе будет производитсяпереопределение. Но предпочтительнее выбрать драйвер-фильтр верхнего уровня,поскольку информация возвращаемая драйвером клавиатуры хорошо документирована иописана в литературе.
Ввиду того,что все современные драйверы, рекомендуется писать согласно стандарту PnP, поскольку они обладаютбольшей функциональностью, то разрабатываемый драйвер должен быть драйвером PnP.
Формализацияпостановки задачи:
§ Необходимонаписать драйвер-фильтр верхнего уровня для драйвера клавиатуры.
§ Драйвер-фильтрдолжен перехватывать IRP пакеты, содержащие скэнкоды нажатых и отпущенныхклавиш, переопределять, если необходимо, скэнкоды на скэнкоды других клавиш. Ондолжен удалять записи, соответствующие отключенным клавишам.
§ Решениео том, какие клавиши должны быть переопределены или отключены, принимается всоответствии со списком замен, который хранится в памяти ядра.
§ Дляустановки списка замен используется пользовательское приложение, котороепересылает в драйвер список замен.
§ Драйвердолжен быть драйвером PnP.
§ Драйвер-фильтрне должен тормозить ввод с клавиатуры и работу всей системы в целом. Драйвер-фильтрдолжен обеспечить надежную работу системы.
2. Конструкторский раздел
2.1 Точки входа разрабатываемого драйвера-фильтра
Посколькуразрабатываемый драйвер-фильтр является драйвером PnP, то должен иметьследующие точки входа:
§ DriverEntry
§ DriverUnload
§ AddDevice
§ Функциидля обработки пакетов IRP
Функции дляобработки прерываний в данной работе не регистрируются, поскольку драйвер неработает с прерываниями.
DiverEntry
В даннойработе процедура DriverEntry выполняет следующие действия:
· Заполнениемассива MajorFunctions. Регистрируется процедура обработки пакета на чтение,процедура обработки IOCTL запросов, процедуры обработки запросов от менеджера PnP и менеджера питания.Остальные элементы массива заполняются адресом функции MyPassNext, котораяпропускает пакеты ниже по стеку.
· Регистрацияпроцедуры AddDevice. В данной работе она называется MyAddDevice.
· Регистрацияпроцедуры DriverUnload, называющейся MyUnload.
· Выделениепамяти для хранения массива замен клавиш. Одна запись массива занимает 4 байта,а максимум может быть только 103 замены (клавиша Pause/Break не в счет). Значитмаксимальный объем массива равен 412 байт. DriverEntry сразу выделяет призагрузке эти 412 байт. Не имеет смысла экономить и выделять память динамическипри каждой инициализации массива, поскольку 412 – это очень мало, и система небудет тратить время на освобождение и выделение памяти при каждойинициализации.
· Инициализациянекоторых глобальных переменных: AltPressed, CtrlPressed, KeyPause.
DriverEntry регистрирует тольконеобходимые процедуры. Поскольку проект представляет собой драйвер-фильтрверхнего уровня, и в нем нет необходимости обрабатывать прерывания, то непроизводится регистрация DriverStartIo, процедур ISR и DPC.
AddDevice
В даннойработе функция MyAddDevice создает одно функциональное устройство с именем \\Device\\MyFilter.При создании устройства происходит резервирования места для хранения адресаустройства, расположенного ниже в стеке драйверов. Это сделано для того, чтобыпри разрушении стека драйверов передать запрос PnP на демонтаж нижестоящемудрайверу. Созданное устройство подключается к стеку драйверов клавиатуры. Этоделается с помощью функции IoAttachDeviceToDeviceStack. Это стандартная функцияWindows, она принимает PDO и указатель на структуруподключаемого FDO. FDO занимает место в стеке драйверов сразу после объекта,находящегося в вершине стека. Теперь подключаемый FDO становится вершинойстека. Нельзя подключится к стеку когда он уже сформирован, поэтому необходимоподключится к нему в определенный момент. Очередность загрузки драйверовописана в реестре Windows. Программа установки производит необходимую регистрацию.Структура этой программы описана ниже.
Для тогочтобы пользовательское приложение смогло обратиться к драйверу (для загрузки вдрайвер списка замен или для получения списка замен, которые драйверосуществляет в данный момент) для FDO должно быть зарегистрировано DOS имя. Используя это имяприложение сможет послать драйверу IOCTL запрос. Для регистрации такого имени создаетсястрока юникод со значением \\DosDevices\\MyFilter и применяется функцияIoCreateSymbolicLink. Ее параметрами является только что созданная строка и имяFDO, которое обслуживает нашдрайвер. Теперь \\DosDevices\\MyFilter – это DOS имя созданного FDO устройства.
DriverUnload
Посколькуданный фильтр является PnP драйвером, то на процедуру DriverUnload ничего не возложено.
Процедуры обработки пакетов IRP
Разрабатываемыйдрайвер-фильтр осуществляет обработку следующих пакетов IRP:
§ IRP_MJ_DEVICE_CONTROL
§ IRP_MJ_READ
§ IRP_MJ_PNP
Остальные IRP пакеты пропускаются нижепо стеку драйверов.
Функция обработки пакетов IRP_MJ_DEVICE_CONTROL
В даннойработе пользовательское приложение должно иметь возможность посылать IOCTL запросы драйверу. Приложениедолжно иметь возможность получить список текущих замен осуществляемых драйвероми передать драйверу новый список замен.
Для этого втеле драйвера определены две 32‑битные константы.
§ GetKeys
CTL_CODE(FILE_DEVICE_KEYBOARD, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)
§ SetKeys
CTL_CODE(FILE_DEVICE_KEYBOARD, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)
Это коды IOCTL запросов неиспользующиеся драйверами стека клавиатуры. Поэтому в данном проекте они могутбыть использованы безо всяких опасений. Запросы с первым кодом используется дляполучения списка текущих замен, со вторым для его установки.
Поскольку впервом случае драйверу необходимо получить буфер с данными, а во втором передатьего, то необходимо использовать один из четырех способов передачи данных. Впроекте применяется способ METHOD_BUFFERED. Поскольку список замен занимает всего 500 байт,то его размер не повредит системному пулу, и копироваться пользовательскийбуфер в системный будет очень быстро. Нет необходимости применять более сложныеметоды METHOD_IN_DIRECT или METHOD_NEITHER использующиеся при передаче больших объемов данных.
При обработкезапроса на получение списка замен процедура копирует данные из буфера драйверав системный буфер. После завершения обработки запроса менеджер ввода / выводаскопирует системный буфер в выходной пользовательский. Таким образом приложениесможет получить список замен. При установке списка замен менеджер скопируетпользовательский буфер в системный, а функция обработки IOCTL скопирует системныйбуфер в буфер драйвера. После этого драйвер начинает производить заменусканкодов, ориентируясь на новые данные.
Функция обработки пакетов IRP_MJ_READ
Даннаяфункция осуществляет обработку пакетов на чтение. IRP пакет сначала будетпопадать в разрабатываемый драйвер. Вызовется зарегистрированная в DriverEntry функция MyRead. К моменту вызова MyRead, буфер не содержит кодовсчитанных клавиш. Для того чтобы получить доступ к ним. MyRead должна установить CallBack процедуру. Она получитуправление когда буфер IRP пакета будет содержать информацию о нажатыхклавишах и будет подниматься вверх по стеку драйверов и будет вызывать CallBack функции на каждом уровнестека. CallBack процедура устанавливается с помощью функцииIoSetCompletionRoutine. Далее в MyRead происходит копирование текущей ячейки IRP пакета в следующуюячейку, таким образом. Таким образом происходит передача неизмененныхпараметров в Kbdclass.
Функция обработки пакетов IRP_MJ_PNP
Драйвер-фильтрдолжен обрабатывать только запрос IRP_MN_REMOVE_DEVICE. При этом функцияпосылает данный пакет менеджера PnP нижестоящему в стеке устройству. Затем онапроизводит необходимые завершающие действия:
§ отключает устройство отстека драйверов вызовом функции IoDetachDevice
§ удаляет устройство FDO вызовом функции IoDeleteDevice
§ удаляетсимвольную ссылку вызовом IoDeleteSymbolicLink
Остальныепакеты пропускаются ниже по стеку.
Обработка остальных пактов IRP
Остальныепакета IRP, которые за ненадобностью не обрабатываются в данном фильтре, пропускаютсяниже по стеку. Процедуры данного фильтра не в праве самостоятельно обрабатыватьэти запросы, так как это могут запросы, адресованные нижестоящим драйверам.Примером одного из таких запросов является IOCTL запрос, адресованныйдрайверу i8042prt и предназначенный для перепрограммирования котроллераклавиатуры и для зажжения лампочек на клавиатуре. Такие запросы посылает Windows при обнаружении нажатия CapsLock, NumLock или ScrollLock.
В даннойработе за пропускание пакетов вниз отвечает процедура MyPassNext. Она передает IRP пакет нижестоящемудрайверу с помощью функции IoCallDriver. При этом нижестоящий драйвер долженсчитывать текущую ячейку IRP пакета. Это достигается за счет использованияфункции IoSkipCurrentIrpStackLocation
2.2 Взаимодействие компонентов системы
/>
2.3 Размещение драйвера в памяти
Некоторыепроцедуры драйвера, те которые выполняют инициализацию, выгодно выполнить иосвободить память после выполнения. Поскольку процедуры инициализациивыполняются всего один раз при загрузке системы, а после этого находятся впамяти, занимая ценное место. В языке C есть специальная директива, позволяющаяразместить инициализирующий код в специальной секции. Память из под этой секциибудет возвращена системе после выполнения. Это директива #pragma alloc_text («INIT», имя). Параметром директивыявляется имя функции.
В данномфильтре функцией, которая выполняет инициализацию, является только DriverEntry. Ее имя и являетсяпараметром директивы.
По умолчаниюфункции драйвера размещаются в нестраничной памяти. Эта память является оченьценной, поскольку она не может быть выгружена на жесткий диск. Экономней былобы разместить код драйвера в странично организованной памяти. Для этого в C предусмотрена директива#pragma alloc_text («PAGE», имя). Параметромдирективы является имя функции, которая должна быть размещена в страничноорганизованной памяти. В данном драйвере-фильтре все процедуры кроме DriverEntry размещаются там.
2.4 Переопределение клавиш
Посколькуфункция MyRead, которая обрабатывает пакеты IRP_MJ_READ, получает пакет IRP без прочитанных данных,то она устанавливает CallBack процедуру. Эта процедура вызывается, когда буферполучает данные.
Реализацияпроцедуры MyReadBack
/>
N – это количество записейв буфере.
K – количество записей вмассиве замен.
S[i] – скэнкод клавиши, соответствующейi‑ой записи буфера.
F1 [j] – скэнкод заменяемойклавиши (j‑аязапись массива замен).
F2 [j] – скэнкод клавиши, накоторую происходит замена (j‑ая запись массива замен).
Клавиша Pause
Драйвер непозволяет заменить клавишу Pause на какую либо другую клавишу, посколько онасигнализирует только при нажатии. Но эта клавиша может выдавать различныезаписи в буфере, в зависимости от того, нажат Ctrl или нет.
Предположим,пользователь поменял правый Ctrl и «a» местами. В этом случае при нажатии на «a» + Pause, клавиша Pause должна выдать код, какбудто бы была нажата клавиша Ctrl. И наоборот выдать обычный код Pause при нажатии Ctrl + Pause.
Для решенияэтой задачи необходимо завести переменную, которая будет хранить информацию, отом, нажата ли клавиша, отвечающая на данный момент за Ctrl. Эта переменнаяназывается CtrlPressed. Если клавиша нажата, то переменная равна 1, иначе 0.
Алгоритмработы с клавишей Pause
§ Встреченапоследовательность записей Ctrl + Pause
· Если CtrlPressed=1, то
последовательностьпропускается в неизмененном состоянии
· Если CtrlPressed=0, то
последовательность,заменяется на последовательность, соответствующую обычной Pause
§ Встреченапоследовательность записей Pause
· Если CtrlPressed=1, то
последовательность,заменяется на последовательность, соответствующую Ctrl + Pause
· Если CtrlPressed=0, то
последовательностьпропускается в неизмененном состоянии
Клавиша PrintScreen
Поскольку PrintScreen выдает разные записи, взависимости от того, нажата ли клавиша Alt. Клавиша PrintScreen, в отличие от Pause может быть заменена надругую клавишу. И она всегда выдает по одной записи при нажатии и тпускании.
Как и вслучае с Pause вводится переменная AltPressed, которая равна 1, если нажата клавиша,отвечающая за Alt.
Произведем унификацию.При встрече записи, соответствующей PrintScreen или Alt + PrintScreen будем заменять ее назапись, соответствующую PrintScreen.
Теперьнеобходимо проверить, есть ли PrintScreen в списке замен, и если нужно, заменить его надругую клавишу или вообще удалить из буфера (если клавиша отключена).
§ Если PrintScreen был заменен на другуюклавишу, то
никакиедействия над ним не производятся
§ Если PrintScreen не был заменен, то
· Если AltPressed=1, то
записьзаменяется на запись, соответствующую Alt + PrintScreen
· Если AltPressed=1, то
записьзаменяется на запись, соответствующую Alt + PrintScreen
2.5 Установка драйвера в системе
Для установкидрайвера необходимо вызвать функции драйвера в определенный момент загрузки системы.Это необходимо для того, чтобы драйвер занял нужное место в стеке драйверов.Операционная система Windows осуществляет загрузку драйверов в порядке, прописанномв системном реестре.
Каждоеустройство имеет свой раздел в реестре. Все эти разделы находятся в HKEY_LOCAL_MACHINE\SYSTEM\CurrentControleSet\Control\Class.Клавиатуресоответствует раздел {4D36E96B-E325–11CE-BFC1–08002BE10318}. У каждого устройства вего разделе есть ключи UpperFilters и LowerFilters. Это ключи типа MultiString. Они содержат именаверхних и нижних драйверов-фильтров данного устройства. Драйверы-фильтры загружаютсяв систему в том порядке, в каком они записаны в этих ключах.
Длярегистрации разрабатывавемого драйвера как фильтра необходимо поместить его имяв первым в ключе UpperFilters.
Для регистрации новогодрайвера необходимо создать раздел с именем этого драйвера в системном реестрепо адресу HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services.Этот раздел должен содержать следующие ключи.
§ Type типа двойное слово
Определяеттип подключаемого модуля. Для драйверов режима ядра значение всегда равноединице.
§ Start типа двойное слово
Определяетметод загрузки драйвера. Может принимать одно из следующих значений:
· SERVICE_BOOT_START (0) – во время начальной загрузки ОС.Данное значение применяется, когда драйвер используется загрузчиком системы;
· SERVICE_SYSTEM_START(1) – после начальной загрузкиОС. Применяется для драйверов, которые самостоятельно осуществляют поискоборудования, но не используются загрузчиком системы (нумераторы).
· SERVICE_AUTO_START (2) – автоматическая загрузка с помощьюдиспетчера управления сервисами (Service Control Manager). Применяется длядрайверов, не поддерживающих Plug and Play.
· SERVICE_DEMAND_START (3) – загрузка «по требованию» либодиспетчера Plug and Play при обнаружении устройства, либо диспетчерауправления сервисами при поступлении от пользователя команды на загрузку.
· SERVICE_DISABLED (4) – драйвер не загружается.
§ ErrorControl типа двойное слово
Определяетуровень контроля ошибок. Может принимать одно из следующих значений:
· SERVICE_ERROR_IGNORE (0). В случае сбоя при загрузке драйвера игнорировать его ипродолжить работу.
· SERVICE_ERROR_NORMAL (1). В случае сбоя при загрузке драйвера продолжить работу, новыдать при этом соответствующее предупреждение.
· SERVICE_ERROR_SEVERE (2). В случае сбоя при загрузке драйвера переключиться напоследнюю конфигурацию, при которой работа системы происходила без ошибок.
· SERVICE_ERROR_CRITICAL (3). Аналогично (2), но в случае повторного сбоя выдать «синийэкран».
§ DisplayName типа строка ASCII
Названиедрайвера или устройства в том виде, в котором оно будет отображаться дляпользователя.
§ ImagePath типа строка Unicode
Полный путь кфайлу с драйвером на диске. Обычно это поле устанавливается в значение % windir%\system32\Drivers\DriverName.sys, где % windir% – папка, вкоторую установлена Windows, а DriverName – имя файла.
3. Технологический раздел
3.1 Выбор языка программирования и средств программирования
Данный проектсостоит из трех программ:
§ Драйвер-фильтр
§ Программа для установкидрайвера
§ Программа для управлениядрайвером
Каждая изпрограмм, осуществляет общение с операционной системой на разном уровне.Соответственно необходим разный подход к этим задачам и специальный подборсредств разработки.
Драйвер-фильтр
Отразрабатываемого драйвера-фильтра требуется высокая скорость работы инадежность. При написании такой задачи осуществляется множество манипуляций спамятью, операций с указателями, преобразований типов. Программисту важнопредставлять структуру скомпилированного продукта, чтобы правильно представитьсебе логику его работы. Среди языков программирования, удовлетворяющих этим требованиям,известны С и ассемблер. Для написания драйвера предпочтение было отдано языку C. Выбор сделан,основываясь на следующих причинах:
§ Существует специальныйкомпилятор C,поставляемый вместе с пакетом DDK, предназначенный специально для компиляциидрайверов. Он содержит множество макроопределений и библиотек, позволяющих сделатьпроцесс написания драйвера более легким. Microsoft рекомендует его какосновную среду для разработки драйверов для Windows. Компилятор содержитспециальные функции, позволяющие уменьшить размер исходного кода. Специальногокомпилятора ассемблера Microsoft не выпускает.
§ Программы на ассемблереработают, конечно, быстрее, чем программы на C. Но разница в скоростимежду этими языками не очень велика. Зато производительность труда прииспользовании Cнамного выше, чем при использовании ассемблера.
Программа для установки драйвера
Программа дляустановки представляет собой консольное предложение. На это приложение ненакладывается особых требований по скорости и по размеру. Поэтому и былавыбрана среда C++Builder. Она позволяет легкосоздавать консольные предложения. Программы, написанные в этой среде, занимаютмало места, и имеют компактный текст.
При написаниипрограммы также была использована технология структурного программирования, хотядля таких маленьких проектов использовать ее невыгодно. Будет только падениебыстродействия.
Программа для управления драйвером
Программа дляуправления драйвером представляет собой оконное приложение. Написана она была всреде C++Builder. Поскольку приложениепредназначено для пользователя., то оно должно иметь красивый и понятныйинтерфейс. Данная среда содержит множество стандартных визуальных компонент.Позволяющих осуществить поставленную задачу. Для приложения скорость и объем неявляется критичным параметром. Поэтому выбор C++ Builder можно считатьоптимальным.
В приложениииспользуется технология объектно-ориентированного программирования. Без ееиспользования организация оконного интерфейса выглядела бы очень запутанной.
3.2 Структуры данных проекта
Информация о нажатиях и опусканиях клавиш
Скэнкодынажатых или отпущенных клавиш хранятся в системном буфере. Доступ к этомубуферу можно получить, если прочитать данные по адресу, хранящемуся в IRP пакете. Адрес хранится вполе AssociatedIrp. SystemBuffer. Буфер представляетсобой массив структур типа KEYBOARD_INPUT_DATA. Она состоит из следующихполей:
§ UnitId типа USHORT. В нем хранится номер устройства, на которомнажали или отпустили клавишу.
§ MakeCode типа USHORT. В этом поле хранится скэнкод нажатой илиотпущенной клавиши. Скэнкод, переданный в этом поле, не определяет клавишуоднозначно. Для полной идентификации клавиши необходимо значение поля Flags.
§ Flags типа USHORT. Это поле несет дополнительную информацию оклавише, а так же определяет, нажали клавишу или отпустили. Если нулевой битравен 0, то значит клавиша нажата, если же он равен 1, то она отпущена. Биты 1и 2 используются для идентификации клавиши.
§ Reserved типа USHORT. Поля является зарезервированным.
§ ExtraInformation типа ULONG. Этополе содержит дополнительную информацию об устройстве.
Все клавиши,кроме клавиши Pause, вырабатывают одну запись при нажатии и одну при отпускании.
§ КлавишаPause вырабатывает 4 записи,если она была нажата без Ctrl:
· Сканкод равен 29, флаги равны 4
· Сканкод равен 69, флаги равны 0
· Сканкод равен 29, флаги равны 5
· Сканкод равен 69, флаги равны 1
Если клавиша Pause была нажата вместе с Ctrl, то она выдает 2 записи:
· Сканкод равен 70, флаги равны 2
· Сканкод равен 70, флаги равны 3
§ Бит 2равен 0, а бит 1 равен 1 в поле Flags у следующих клавиш: Insert, Delete, PageUp, PageDown, Home, End, PrintScreen, правй Ctrl, правй Alt, Enterна дополнительнойклавиатуре, обратный слеш на дополнительной, стрелки, клавиши Windows, клавиша всплывающегоменю.
§ Увсех остальных клавиш биты 1 и 2 поля Flags равны 0.
Клавиша PrintScreen – это единственнаяклавиша, которая меняет выдаваемый скэнкод в зависимости от того, нажата лидругая. PrintScreen меняет скэнкод в зависимости от Alt.
Вместе с Alt PrintScreen выдает:
§ Скан код равен 84, флагиравны 0 (при нажатии)
§ Скан код равен 84, флагиравны 1 (при отпускании)
Без Alt PrintScreenвыдает:
§ Скан код равен 55, флагиравны 2 (при нажатии)
§ Скан код равен 55, флагиравны 3 (при отпускании)
Структура списка замен
Список замензамен – это массив структур ChangeStruct. Она состоит из следующих полей:
§ f1 типа UCHAR. Полесодержит дополнительную, идентифицирующую заменяемую клавишу.
§ Scan1 типа UCHAR. Полесодержит скэнкод заменяемой клавиши
§ f2 типа UCHAR. Полесодержит информацию о клавише, на которую заменяют.
§ Scan2 типа UCHAR. Полесодержит скэнкод клавиши, на которую заменяют.
Фактическиполя f1и f2 содержат 1 и 2 бит поляFlagsструктурыKEYBOARD_INPUT_DATA. Они помогают идентифицировать клавишу, котораязаменяется, и на которую происходит замена.
Дополнительная информация
При создании FDO выделяется память подструктуру DEVICE_EXTENSION, в эта структура состоит всего из одногополя. Это поле TopOfStack типа PDEVICE_OBJECT. Оно содержитуказатель на FDO, расположенное ниже в стеке клавиатуры, и используется для передачиIRP пакетов ниже по стеку.Адрес этой структуры находится в поле DeviceExtension нашего FDO.
3.3 Интерфейс управляющего приложения
Интерфейсуправляющего приложения состоит из двух окон. Первое окно представляет собой модельклавиатуры, оно является главным в программе. Второе окно предназначено длявывода информации и называется информационным.
/>
При нажатиина интересующую кнопку на главном окне она вдавливается, и красным цветомподсвечивается кнопка, на которую заменяется выбранная кнопка. При этомпоявляется информационное окно, содержащее следующие параметры:
§ Название выбранной кнопки
§ Название кнопки, накоторую происходит замена
§ Состояние кнопки(включена или выключена)
§
/>
Еслинеобходимо переопределить кнопку, то нужно щелкнуть по этой кнопке. Винформационном окне появится информация об активизированной кнопке. Далеенеобходимо нажать на кнопку «Заменить», она расположена в информационном окне.И затем щелкнуть по кнопке, на которую необходимо произвести замену.
После тогокак желаема конфигурация определена, нужно нажать кнопку «Установить». Послеэтого информация будет отослана драйверу, и изменения вступят в силу. Еслинеобходимо узнать, какие замены производит драйвер на данный момент, то нужнощелкнуть по кнопке «Принять».
Для быстроговосстановления стандартных настроек клавиатуры предусмотрена кнопка «Поумолчанию». Она загружает стандартную конфигурацию. Чтобы она вступила в силу,необходимо нажать на кнопку «Установить».
3.4 Тестированиедрайвера-фильтра клавиатуры
Драйвер былпротестирован с использованием стандартной тестирующей утилиты DriverVerifier пакета DDK. С его помощью былипроведены следующие тесты:
§ Операции с пулами памяти
§ Корректность уровней IRQL, на которых выполняетсякод драйвера
§ Обнаружениевзаимоблокировок
§ Нехватка ресурсов
§ Нетипичные запросы кдрайверу
Все тестыпрошли успешно. Память в системе распределялась правильно, ошибок с ней невозникало. На нехватку ресурсов драйвер реагировал корректно. Нетипичныезапросы к драйверу не обрабатывались им.
Для отладкидрайвера использовалась программа DebugView. С помощью этой программы любой драйверможет выводить на экран отладочную информацию. При отладке эта программапозволила отследить процесс переопределения клавиш.
Драйвер использовалитрое человек в течение месяца, и ошибок за этот период ими обнаружено не было.
Заключение
В даннойработе рассмотрен вопрос, связанный с разработкой драйверов устройств в системеWindows, и реализован драйвер-фильтрклавиатуры.
Разрабатываемыйдрайвер позволяет
§ переопределять значениелюбых клавиш клавиатуры
§ отключать клавиши клавиатуры
Драйвер-фильтротвечает всем современным требованиям, накладываемым Windows на драйверы.
Драйвер был протестированс помощью тестирующих утилит Microsoft и успешно выдержал все тесты. Тестированиепоказало корректную работу.
Список литературы
1. Кузьмин И. Драйверыуровня ядра системы Windows XP // Программист, – М.: ООО «Викфилд». – №11,2003
2. Солдатов В.П. Программированиедрайверов Windows. Изд. 2-е, перераб. и доп. М.: ООО «Бином-Пресс», 2004 г.
3. MSDNLibrary, Copyright 1987–2004 Microsoft Corporation
4. Форуми публикации проекта «Первые шаги» – www.firststeps.ru.