В данном фильтре функцией, которая выполняет инициализацию, является только DriverEntry. Ее имя и является параметром директивы.
По умолчанию функции драйвера размещаются в нестраничной памяти. Эта память является очень ценной, поскольку она не может быть выгружена на жесткий диск. Экономней было бы разместить код драйвера в странично организованной памяти. Для этого в C предусмотрена директива #pragmaalloc_text («PAGE», имя). Параметром директивы является имя функции, которая должна быть размещена в странично организованной памяти. В данном драйвере-фильтре все процедуры кроме DriverEntry размещаются там.
Поскольку функция 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) – автоматическая загрузка с помощью диспетчера управления сервисами (ServiceControlManager). Применяется для драйверов, не поддерживающих PlugandPlay.
· SERVICE_DEMAND_START (3) – загрузка «по требованию» либо диспетчера PlugandPlay при обнаружении устройства, либо диспетчера управления сервисами при поступлении от пользователя команды на загрузку.
· 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.1 Выбор языка программирования и средств программирования
Данный проект состоит из трех программ:
- Драйвер-фильтр
- Программа для установки драйвера
- Программа для управления драйвером
Каждая из программ, осуществляет общение с операционной системой на разном уровне. Соответственно необходим разный подход к этим задачам и специальный подбор средств разработки.
От разрабатываемого драйвера-фильтра требуется высокая скорость работы и надежность. При написании такой задачи осуществляется множество манипуляций с памятью, операций с указателями, преобразований типов. Программисту важно представлять структуру скомпилированного продукта, чтобы правильно представить себе логику его работы. Среди языков программирования, удовлетворяющих этим требованиям, известны С и ассемблер. Для написания драйвера предпочтение было отдано языку C. Выбор сделан, основываясь на следующих причинах:
- Существует специальный компилятор C, поставляемый вместе с пакетом DDK, предназначенный специально для компиляции драйверов. Он содержит множество макроопределений и библиотек, позволяющих сделать процесс написания драйвера более легким. Microsoft рекомендует его как основную среду для разработки драйверов для Windows. Компилятор содержит специальные функции, позволяющие уменьшить размер исходного кода. Специального компилятора ассемблера Microsoft не выпускает.
- Программы на ассемблере работают, конечно, быстрее, чем программы на C. Но разница в скорости между этими языками не очень велика. Зато производительность труда при использовании C намного выше, чем при использовании ассемблера.
Программа для установки драйвера
Программа для установки представляет собой консольное предложение. На это приложение не накладывается особых требований по скорости и по размеру. Поэтому и была выбрана среда C++ Builder. Она позволяет легко создавать консольные предложения. Программы, написанные в этой среде, занимают мало места, и имеют компактный текст.
При написании программы также была использована технология структурного программирования, хотя для таких маленьких проектов использовать ее невыгодно. Будет только падение быстродействия.
Программа для управления драйвером
Программа для управления драйвером представляет собой оконное приложение. Написана она была в среде C++ Builder. Поскольку приложение предназначено для пользователя., то оно должно иметь красивый и понятный интерфейс. Данная среда содержит множество стандартных визуальных компонент. Позволяющих осуществить поставленную задачу. Для приложения скорость и объем не является критичным параметром. Поэтому выбор C++ Builder можно считать оптимальным.