Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
СОДЕРЖАНИЕ
1. Краткое описание...................................................................................... 2
2. Реализация драйвер фильтров.................................................................. 3
2.1. Драйвер фильтр клавиатуры........................................................ 3
2.2. Подключение к функциональному драйверу.............................. 5
2.3. Механизм работы стека клавиатуры с
установленным фильтром................................................................... 7
2.4. Алгоритм работы KbFilter_ServiceCallback................................ 9
2.5. Драйвер фильтр мыши................................................................. 10
3. Управляющее приложение........................................................................ 11
4. Анализ клавиатурного почерка................................................................ 12
5. Текст программы....................................................................................... 14
5.1 Драйвер фильтр клавиатуры......................................................... 14
5.2 Управляющее приложение............................................................ 36
5.2 Драйвер фильтр мыши.................................................................. 42
6. Литература................................................................................................. 43
1. Краткое описание
Система позволяет выявить подмену идентифицированного пользователя, проводя непрерывный мониторинг клавиатурного почерка. В её состав входят два драйвер фильтра клавиатуры и мыши, а так же управляющее приложение. Система может работать в трёх режимах: обучение, анализ, блокировка:
- Режим обучение – определяются эталонные характеристики клавиатурного почерка Режим анализ – система сравнивает эталонные характеристиками с вновь введёнными, после чего переходит либо остаётся в режиме анализа, либо переходит в режим блокировки. Режим блокировки – в этом режиме блокированы клавиатура и мышь, система ожидает ввода пароля на разблокировку.
Управляющее приложение предназначено для просмотра временных характеристик, их сохранения и перевода системы в режим анализ.

Рис. 1. Переход между режимами работы системы
2. Реализация драйвер фильтров
2.1. Драйвер фильтр клавиатуры
Cвязь клавиатуры с шиной осуществляет микроконтроллер клавиатуры Intel 8042 (или совместимый с ним). На современных компьютерах он интегрирован в чипсет материнской платы. Все клавиатуры являются PS/2-совместимыми или клавиатурами, подключаемыми через интерфейс USB. В PS/2-совместимом режиме микроконтроллер клавиатуры также связывает с шиной и PS/2-совместимую мышь. Всем этим управляет функциональный драйвер i8042prt (Intel 8042 Port Driver). Драйвер i8042prt создает два безымянных объекта "устройство" и подключает один к стеку клавиатуры.
Поверх драйвера i8042prt, точнее поверх его устройств, располагаются именованные объекты "устройство" драйверов Kbdclass и Mouclass. Имя "KeyboardClass" является базовым, и к нему добавляются индексы (0, 1 и т. д.). Базовое имя хранится в параметре реестра HKLM\SYSTEM\CurrentControlSet\Services\Kbdclass\Parameters\KeyboardDeviceBaseName Драйверы Kbdclass и Mouclass являются так называемыми драйверами класса (class drivers) и реализуют общую функциональность для всех типов клавиатур и мышей, т. е. для всего класса этих устройств. Оба эти драйвера устанавливаются как высокоуровневые драйверы.
Стек клавиатуры обрабатывает несколько типов. P
Запросы типа IRP_MJ_READ несут в себе коды клавиш. Генератором этих IRP является поток необработанного ввода RawInputThread системного процесса csrcc. exe. Этот поток открывает объект "устройство" драйвера класса клавиатуры для эксклюзивного использования и с помощью функции ZwReadFile направляет ему IRP типа IRP_MJ_READ. Получив IRP, драйвер Kbdclass, используя макрос IoMarkIrpPending, отмечает его как ожидающий завершения (pending), ставит в очередь и возвращает STATUS_PENDING. Потоку необработанного ввода придется ждать завершения IRP. То есть RawInputThread получает клавиатурные события как вызов асинхронной процедуры.

Рис. 2. Схема стека драйверов клавиатуры и мыши

Рис. 3. Схема стека драйверов клавиатуры и мыши после установки системы
2.2. Подключение к функциональному драйверу
Для подключения к функциональному драйверу клавиатуры (I8042ptr), высокоуровневый драйвер фильтр kbdclass посылает внутренний запрос IRP_MJ_INTERNAL_CONTROL. Все нижележащие драйверы имеют процедуру обработки таких внутренних запросов. Внутренний запрос посылается с параметром IO_CTL_INTERNAL_KEYBOARD_CONNECT. (заносится в IrpStack–>Parametrs. DeviceIoControl. IoControlCode). С этим запросом kbdclass посылает структуру CONNECT_DATA. (заносится в IrpStack–>Parametrs. DeviceIoControl. Type3bufer)
typedef struct _CONNECT_DATA {
IN PDEVICE_OBJECT ClassDeviceObject;
IN PVOID ClassService;
} CONNECT_DATA, *PCONNECT_DATA;
Так как инициатором этого запроса является kbdclass, то он соответственно и будет заполнять первым эту структуру. В ClassDeviceObject занесётся адрес объекта, который создается в драйвере kbdclass. В ClassService занесётся адрес функции KeyboardClassServiceCallback, которую будут вызывать IRP пакеты по возвращению. (когда встречается функция IoCompileIrp).
Получив такой запрос на соеденение kbfilter (если установлен) или функциональный драйвер I8042ptr выполняет следующее:
Сохраняет полученную структуру CONNECT_DATA Переопределяет структуру: заносит в ClassDeviceObject указатель на свой объект устройство, в ClassService указатель на свою процедуру обратного вызова. Передаёт IRP дальше по стеку или завешает запрос.
Рис. 4. Схема подключения к функциональному драйверу
2.3. Механизм работы стека клавиатуры с установленным фильтром
Когда будет нажата или отпущена клавиша, контроллер клавиатуры выработает аппаратное прерывание. Его обработчик вызовет I8042KeyboardInterruptService, которая прочитает из внутренней очереди контроллера клавиатуры необходимые данные. Так как обработка аппаратного прерывания происходит на повышенном IRQL, ISR делает только самую неотложную работу и ставит в очередь вызов отложенной процедуры (Deferred Procedure Call, DPC). DPC работает при IRQL = DISPATCH_LEVEL. Когда IRQL понизится до DISPATCH_LEVEL, система вызовет процедуру I8042KeyboardIsrDpc, которая вызовет зарегистрированную драйвером фильтром kbfilter процедуру обратного вызова KbFilter_ServiceCallback. (также выполняется на IRQL = DISPATCH_LEVEL). В этой процедуре произойдёт заполнение структуры KEY_INFO:
typedef struct _KEY_INFO{
ULONG MakeCode; // код клавиши
ULONG CountUp; // количество отжатий
ULONGLONG LastDown; // последнее нажатие
ULONGLONG LastUp; // последнее отжатие
ULONGLONG LastLastUp; // предпоследнее отжатие
ULONG LastFromDownToUp; // посленее нажатие-отпуск
ULONG MeanFromDownToUp; // среднее нажатие отпуск
ULONGLONG LastBetweenTwoUp; // последне между двумя отжатиями
ULONG MeanBetweenTwoUp; // среднее между двумя отжатиями
ULONG ToOtherBreak; // время до другой
ULONG MeanToOtherBreak; // среднее время до другой
ULONG KeyVector[NUMBER_OF_KEYS]; // среднее до определённой
} KEY_INFO,*PKEY_INFO;
Затем произойдёт вызов процедуры обратного вызова KeyboardClassServiceCallback в драйвере Kbdclas. KeyboardClassServiceCallback извлечет из своей очереди ожидающий завершения IRP, заполнит структуру KEYBOARD_INPUT_DATA, несущую всю необходимую информацию о нажатиях/отпусканиях клавиш и завершит IRP. Поток необработанного ввода пробуждается, обрабатывает полученную информацию и вновь посылает IRP типа IRP_MJ_READ драйверу класса, который опять ставится в очередь до следующего нажатия/отпускания клавиши. Таким образом, у стека клавиатуры всегда есть, по крайней мере, один, ожидающий завершения IRP и находится он в очереди драйвера Kbdclass. "Мышиный" стек ведет себя подобным же образом.

Рис.5. Схема работы стека клавиатуры с установленным фильтром
2.4. Алгоритм работы KbFilter_ServiceCallback
Процедура KbFilter_ServiceCallback вызывается всякий раз когда происходят события, связанные с клавиатурой имеет следующий алгоритм:

Рис. 6. Схема алгоритма работы KbFilter_ServiceCallback
2.5. Драйвер фильтр мыши
Драйвер фильтр мыши полностью аналогичен описанному выше драйвер фильтру клавиатуры. Взаимодействие между драйверами осуществляется, как показано на рисунке.

Рис. 7.Схема взаимодействия м между драйвер фильтрами
3. Управляющее приложение.
Управляющее приложение предназначено для управления драйвер фильтром клавиатуры. Оно отображает все временные характеристики по каждой клавише на экране. Сохраняет сформированный клавиатурный почерк. Так же оно предназначено для запуска самой системы защиты.

Рис. 8. Вид управляющего приложения

Рис. 9. Вид окна «О программе»
4. Анализ клавиатурного почерка
Для анализа клавиатурного почерка используется матрица межклавишных взаимодействий, которая имеет вид:
![]()

где n – количество клавиш на клавиатуре,
tij – время нажатия от i-й клавиши на j-ю
tij = keyinf[i].keyvector[j]
Каждые 30 нажатий клавиш, составляется вектор времён, имеющий 29 элементов.
Если система работает в режиме анализа, то для этого вектора составляется эталонный вектор из эталонной матрицы межклавишных взаимодействий. Для эталонного вектора определяется доверительный интервал. Если все значения проверяемого вектора входят в доверительный интервал с определённой точностью, то клавиатурный почерки совпадают.
Получены при помощи программы результаты представлены в таблице 1.
Таблица 1.
Клавиша | Выборка по вектору межклавишного взаимодействия |
| ||||
Фраза введённая 50 раз | Нижняя граница доверительного интервала | Верхняя граница доверительного интервала | Фраза введённая 1 раз | Фраза введенная другим человеком | ||
а | ||||||
н | 1676042 | 1176042 | 2176042 | 801152 | 2203168 |
|
а | 1798288 | 1298288 | 2298288 | 2103024 | 2603744 |
|
л | 1364853 | 864853 | 1864853 | 1101584 | 3304752 |
|
и | 2439249 | 1939249 | 2939249 | 2002880 | 1502160 |
|
з | 3214778 | 2714778 | 3714778 | 4907056 | 2203168 |
|
пробел | 1787140 | 1287140 | 2287140 | 1101584 | 2103024 |
|
к | 1605824 | 1105824 | 2105824 | 1502160 | 3705328 |
|
л | 3153753 | 2653753 | 3653753 | 1802592 | 2303312 |
|
а | 2030067 | 1530067 | 2530067 | 1902736 | 2203168 |
|
в | 1495901 | 995901 | 1995901 | 1402016 | 2002880 |
|
и | 1876526 | 1376526 | 2376526 | 1802592 | 4005760 |
|
а | 2339301 | 1839301 | 2839301 | 2002880 | 1602304 |
|
т | 1848360 | 1348360 | 2348360 | 1602304 | 1902736 |
|
у | 3289886 | 2789886 | 3789886 | 4005760 | 2203168 |
|
р | 1947722 | 1447722 | 2447722 | 1902736 | 1802592 |
|
н | 2886572 | 2386572 | 3386572 | 2804032 | 1802592 |
|
о | 881932 | 381932 | 1381932 | 801152 | 1502160 |
|
г | 1933248 | 1433248 | 2433248 | 1902736 | 2103024 |
|
о | 2712689 | 2212689 | 3212689 | 2403456 | 1502160 |
|
пробел | 1049556 | 549556 | 1549556 | 801152 | 1702448 |
|
п | 1812371 | 1312371 | 2312371 | 1802592 | 2603744 |
|
о | 2182239 | 1682239 | 2682239 | 2002880 | 2403456 |
|
ч | 2095982 | 1595982 | 2595982 | 2203168 | 3905616 |
|
е | 1966695 | 1466695 | 2466695 | 1902736 | 1402016 |
|
р | 2162288 | 1662288 | 2662288 | 1702448 | 1702448 |
|
к | 1148330 | 648330 | 1648330 | 901296 | 2002880 | |
а | 1989579 | 1489579 | 2489579 | 2002880 | 3104464 |
|

Рис. 10. Фраза введённая 50 раз

Рис. 11. Фраза введённая 1 раз

Рис. 12. Фраза введённая другим человеком
5. Текст программы
5.1 Драйвер фильтр клавиатуры
#include "kbfiltr. h"
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, FilterAddDevice)
#pragma alloc_text (PAGE, FilterDispatchPnp)
#pragma alloc_text (PAGE, FilterUnload)
#pragma alloc_text (PAGE, FilterInternIoCtl)
#pragma alloc_text (PAGE, FilterCreateControlObject)
#pragma alloc_text (PAGE, FilterDeleteControlObject)
#pragma alloc_text (PAGE, FilterDispatchIo)
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*
Точка входа инициализации драйвера
Вызывается непосредстенно системой в/в
Аргументы:
DriverObject - указатель на объект драйвер
RegistryPath - указатель на unicode string пути
в регистре к подразделу драйвера
Возвращаемое значение:
STATUS_SUCCESS если успешно,
STATUS_UNSUCCESSFUL в противном случае.
*/
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulIndex;
PDRIVER_DISPATCH * dispatch;
UNREFERENCED_PARAMETER (RegistryPath);
//все запросы будут приводить к вызову функции FilterPass,
//которая переадресует запросы нижним драйверам в стеке.
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;
ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;
ulIndex++, dispatch++) {
*dispatch = FilterPass;
}
//исключение составят функции, зарегестрированные ниже
//регестрация функций, которые будет обрабатывать объект в стеке
DriverObject->MajorFunction[IRP_MJ_PNP] = FilterDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = FilterDispatchPower;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FilterInternIoCtl;
DriverObject->DriverExtension->AddDevice = FilterAddDevice;
DriverObject->DriverUnload = FilterUnload;
//регестрация функций, которые будет обрабатывать объект устройство управленя
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
FilterDispatchIo;
// Инициализация FastMutex для понижения уровня IRQL при
// создании и удалении объекта устройство управления
ExInitializeFastMutex(&ControlMutex);
return status;
}
NTSTATUS
FilterAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*
Созданию объекта устройства,
подготовка устройства к работе
Аргументы:
DeviceObject - указатель на объект данного драйвера
PhysicalDeviceObject - указатель на объект физического
устройства, созданного родительским (шинным) драйвером
Возвращаемое значение:
STATUS_SUCCESS или код ошибки
*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
ULONG deviceType = FILE_DEVICE_UNKNOWN;
PKEY_INFO KeyInfo;
USHORT i;
PAGED_CODE ();
// Создание объекта устройство фильтр
status = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
NULL, // без имени
deviceType,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&deviceObject);
if (!NT_SUCCESS (status)) {
return status;
}
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
deviceExtension->Type = DEVICE_TYPE_FIDO;
deviceExtension->NextLowerDriver = IoAttachDeviceToDeviceStack (
deviceObject,
PhysicalDeviceObject);
// при не удачном присоеденении к стеку, возвращаем STATUS_UNSUCCESSFUL
if(NULL == deviceExtension->NextLowerDriver) {
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
deviceObject->Flags |= deviceExtension->NextLowerDriver->Flags &
(DO_BUFFERED_IO | DO_DIRECT_IO |
DO_POWER_PAGABLE );
deviceObject->DeviceType = deviceExtension->NextLowerDriver->DeviceType;
deviceObject->Characteristics =
deviceExtension->NextLowerDriver->Characteristics;
deviceExtension->Self = deviceObject;
//Выделяем память под массив структур KEY_INFO, хранящих информацию о каждой клавише
//обнуляем все её поля и сохраняем указатель в поле deviceExtension->KeyInfo
KeyInfo=(PKEY_INFO)ExAllocatePool(PagedPool, NUMBER_OF_KEYS*sizeof(KEY_INFO));
ResetKeyInfo(KeyInfo);
deviceExtension->KeyInfo=KeyInfo;
for (i=0;i<NUMBER_OF_CHEK_KEYS;i++)
{
KeyList[i]=0;
}
//инициализируем remove lock для веденя учёта IRP, чтобы не удалить
//объект устройство, когда запрос в/в в стеке еще не завершён
IoInitializeRemoveLock (
&deviceExtension->RemoveLock , //указатель на структуру IO_REMOVE_LOCK
POOL_TAG, //#define POOL_TAG 'arty'
1, //максимальное количество минут удержки
100); //макс число незавершённых захватов блокировки
// Устанавливаем статус Filter DO
INITIALIZE_PNP_STATE(deviceExtension);
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
NTSTATUS
FilterPass (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*
Стандартная функция обработки
Если драйвер не обрабатывает запрс IRP,
то просто посылает его вниз по стеку
Аргументы:
DeviceObject - указатель на объект данного драйвера
Irp - указатель на пакет запроса ввода/вывода
Возвращаемое значение:
NT status code
*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS status;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//увеличиваем счётчик захватов Remove Lock
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
//завершаем IRP запрос если ошибка при увелечении счётчика
if (!NT_SUCCESS (status)) {
Irp->IoStatus. Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
//иначе передаем запрос нижележащему драйверу по стеку
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (deviceExtension->NextLowerDriver, Irp);
//уменьшаем счётчик захватов Remove Lock
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
return status;
}
NTSTATUS
FilterDispatchPnp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*
Функция диспетчеризации PnP.
Аргументы:
DeviceObject - указатель на объект данного драйвера
Irp - указатель на пакет запроса ввода/вывода
Возвращаемое значение:
NT status code */
{
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
KEVENT event;
PAGED_CODE();
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
//Стандартная проверка счётчика Remove Lock
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS (status)) {
Irp->IoStatus. Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
switch (irpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
// Устройство запущено
// Неможем трогать устройство пока не
// перенаправим запрос нижележащим драйверам
KeInitializeEvent(&event, NotificationEvent, FALSE);
//Копируем содержимое ячейки стека IRP для текущего
//драйвера в ячейку стека для нижестоящего драйвера
IoCopyCurrentIrpStackLocationToNext(Irp);
//Регестрируем процедуру завершения
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) FilterStartCompletionRoutine,
&event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);
//Перед таем как запустить устройство нужно дождаться пока
//стартуют низкоуровневые драйверы
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus. Status;
}
if (NT_SUCCESS (status)) {
//если NT_SUCCESS значит внизу всё нормально, устанавливаем статус
SET_NEW_PNP_STATE(deviceExtension, Started);
if (deviceExtension->NextLowerDriver->Characteristics & FILE_REMOVABLE_MEDIA) {
DeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
}
if(Stopped != deviceExtension->PreviousPnPState) {
// запущено первый раз
FilterCreateControlObject(DeviceObject);
}
}
Irp->IoStatus. Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
return status;
case IRP_MN_REMOVE_DEVICE:
//Если существует KeyInfoTemp (переходили в режим анализ), отчищаем
if (deviceExtension->KeyInfoTemp)ExFreePool(deviceExtension->KeyInfoTemp);
//Освобождаем память под KeyInfo
ExFreePool(deviceExtension->KeyInfo);
//Ждём завершения всех незавершенных IRP
IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);
SET_NEW_PNP_STATE(deviceExtension, Deleted);
FilterDeleteControlObject();
IoDetachDevice(deviceExtension->NextLowerDriver);
IoDeleteDevice(DeviceObject);
return status;
case IRP_MN_QUERY_STOP_DEVICE:
SET_NEW_PNP_STATE(deviceExtension, StopPending);
status = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_STOP_DEVICE:
if(StopPending == deviceExtension->DevicePnPState)
{
RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
}
status = STATUS_SUCCESS; // We must not fail this IRP.
break;
case IRP_MN_STOP_DEVICE:
SET_NEW_PNP_STATE(deviceExtension, Stopped);
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
SET_NEW_PNP_STATE(deviceExtension, RemovePending);
status = STATUS_SUCCESS;
break;
case IRP_MN_SURPRISE_REMOVAL:
SET_NEW_PNP_STATE(deviceExtension, SurpriseRemovePending);
status = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
if(RemovePending == deviceExtension->DevicePnPState)
{
RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
}
status = STATUS_SUCCESS;
break;
default:
status = Irp->IoStatus. Status;
break;
}
// Посылаем IRP дальше и забываем про него
Irp->IoStatus. Status = status;
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (deviceExtension->NextLowerDriver, Irp);
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
return status;
}
NTSTATUS
FilterStartCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*
Функция завершения, используется когда вызываются
нижележащие объекты устройства
Аргументы:
DeviceObject - указательна объект устройство
Irp - указатель на PnP Irp.
Context - NULL
Возвращаемое значение:
NT status code
*/
{
PKEVENT event = (PKEVENT)Context;
UNREFERENCED_PARAMETER (DeviceObject);
// если нижележащий драйвер не вернул STATUS_PENDING
// мы не должны отмечать событие
if (Irp->PendingReturned == TRUE) {
KeSetEvent (event, IO_NO_INCREMENT, FALSE);
}
// функция диспетчеризации вызовит IoCompleteRequest
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
FilterDispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*
Функция обработки IRP электропитания.
Аргументы:
DeviceObject - указательна объект устройство
Irp - указатель на пакет запроса.
Возвращаемое значение:
NT status code
*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS status;
//стандартная проверка RemoveLock
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS (status)) {
Irp->IoStatus. Status = status;
PoStartNextPowerIrp(Irp);
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
//просто передаём запрос вниз
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
status = PoCallDriver(deviceExtension->NextLowerDriver, Irp);
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
return status;
}
VOID
FilterUnload(
IN PDRIVER_OBJECT DriverObject
)
/*
Функция выгрузки драйвера
освобаждаем все ресурсы, выделенные в DriverEntry
Аргументы:
DeviceObject - указательна объект устройство
Возвращаемое значение:
VOID.
*/
{
PAGED_CODE ();
// устанавливаем DeviceObject в NULL
ASSERT(DriverObject->DeviceObject == NULL);
return;
}
NTSTATUS
FilterCreateControlObject(
IN PDEVICE_OBJECT DeviceObject
)
/*
Функция создания устройства управления
Аргументы:
DeviceObject - указательна объект устройство
Возвращаемое значение:
NT status code
*/
{
UNICODE_STRING ntDeviceName;
UNICODE_STRING symbolicLinkName;
PCONTROL_DEVICE_EXTENSION deviceExtension;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PAGED_CODE();
// понижаем уровень IRQL, IoCreateDeviceSecure и IoCreateSymbolicLink
// должны быть вызваны на уровне PASSIVE_LEVEL
ExAcquireFastMutexUnsafe(&ControlMutex);
// если это первый экземпляр устройства, то созжаём объект управления
if(1 == ++InstanceCount)
{
RtlInitUnicodeString(&ntDeviceName, NTDEVICE_NAME_STRING);
RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);
status = IoCreateDevice(DeviceObject->DriverObject,
sizeof(CONTROL_DEVICE_EXTENSION),
&ntDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&ControlDeviceObject);
if (NT_SUCCESS( status )) {
ControlDeviceObject->Flags |= DO_BUFFERED_IO;
status = IoCreateSymbolicLink( &symbolicLinkName, &ntDeviceName );
if ( !NT_SUCCESS( status )) {
IoDeleteDevice(ControlDeviceObject);
goto End;
}
deviceExtension = ControlDeviceObject->DeviceExtension;
deviceExtension->Type = DEVICE_TYPE_CDO;
deviceExtension->ControlData= NULL;
deviceExtension->Deleted = FALSE;
deviceExtension->StackObject= DeviceObject;
deviceExtension->MouseLock= FALSE; //в начале мышь работает
deviceExtension->ModeFlag= MODE_EDUCATION; //начинаем работу в режиме обучение
ControlDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}else {
DbgPrint("IoCreateDevice failed %x\n", status);
}
}
End:
ExReleaseFastMutexUnsafe(&ControlMutex);
return status;
}
VOID
FilterDeleteControlObject(
)
/*
Функция удаления устройства управления
Возвращаемое значение:
VOID
*/
{
UNICODE_STRING symbolicLinkName;
PCONTROL_DEVICE_EXTENSION deviceExtension;
PAGED_CODE();
//захватываем быстрый мьютекс для понижения irql
ExAcquireFastMutexUnsafe (&ControlMutex);
// если это последний экземпляр устройства то удаляем controlobject
if(!(--InstanceCount) && ControlDeviceObject)
{
RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);
deviceExtension = ControlDeviceObject->DeviceExtension;
deviceExtension->Deleted = TRUE;
IoDeleteSymbolicLink(&symbolicLinkName);
IoDeleteDevice(ControlDeviceObject);
ControlDeviceObject = NULL;
}
ExReleaseFastMutexUnsafe (&ControlMutex);
}
NTSTATUS
FilterDispatchIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*
Routine Description:
Функция обаботки IRP не проходящих через стек
определяем входне значение объекта устройство
если это устройство управления, обрабатываем IRP и завершаем
если это устройство в стеке, передаем IRP вниз
Аргументы:
DeviceObject - указательна объект устройство
Irp - указатель на пакет запроса.
Возвращаемое значение:
NT status code
*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PCOMMON_DEVICE_DATA commonData;
ULONG outBufLength;
PCONTROL_DEVICE_EXTENSION CtrlDevExtension;
PKEY_INFO keyinfo;
PDEVICE_EXTENSION MainDevExt;
PCONTROL_MOUSE_DEVICE_EXTENSION MouCtrlDevExt;
UNICODE_STRING ObjectName;
PFILE_OBJECT FileObject=NULL;
PDEVICE_OBJECT DeviceMouCtrlObject=NULL;
PKEY_INFO KeyInfoTemp;
USHORT i;
PAGED_CODE();
commonData = (PCOMMON_DEVICE_DATA)DeviceObject->DeviceExtension;
// определяем тип устройства
if(commonData->Type == DEVICE_TYPE_FIDO) {
// Если IRP адресован устройству в стеке
// просто перенаправляем вниз по стеку
return FilterPass(DeviceObject, Irp);
}
ASSERT(commonData->Type == DEVICE_TYPE_CDO);
// Иначе это устройство для контроля
// для открытия устройства управленя мышью
RtlInitUnicodeString(&ObjectName, L"\\Device\\MouCtrlFilter");
//получаем указатель на объект Расширение устройства управления
CtrlDevExtension = (PCONTROL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
// из Расширения Устройства Управления получаем указатель
// на Расширение устройства в стеке
MainDevExt=(PDEVICE_EXTENSION)CtrlDevExtension->StackObject->DeviceExtension;
// из Расширения устройства в стеке получаем указатель на KeyInfo
keyinfo=MainDevExt->KeyInfo;
if(! CtrlDevExtension->Deleted) {
status = STATUS_SUCCESS;
Irp->IoStatus. Information = 0;
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
DbgPrint("Create in kbdfiltr");
break;
case IRP_MJ_CLOSE:
DbgPrint("Close in kbdfiltr");
break;
case IRP_MJ_CLEANUP:
DbgPrint("Cleanup in kbdfiltr");
break;
case IRP_MJ_DEVICE_CONTROL:
// получаем длину буфера переданного с запросом
outBufLength = irpStack->Parameters. DeviceIoControl. OutputBufferLength;
switch (irpStack->Parameters. DeviceIoControl. IoControlCode) {
case GET_KEY_INFO:
RtlCopyMemory(Irp->AssociatedIrp. SystemBuffer, keyinfo, outBufLength);
Irp->IoStatus. Information=outBufLength;
status=STATUS_SUCCESS;
break;
case GET_KEY_LIST:
RtlCopyMemory(Irp->AssociatedIrp. SystemBuffer,&KeyList, outBufLength);
Irp->IoStatus. Information=outBufLength;
status=STATUS_SUCCESS;
break;
case WRITE_FILE:
ReadWriteKeyInfoToFile(keyinfo, FLAG_WRITE);
status=STATUS_SUCCESS;
break;
case READ_FILE:
ReadWriteKeyInfoToFile(keyinfo, FLAG_READ);
status=STATUS_SUCCESS;
break;
case RESET_KEY_INFO:
ResetKeyInfo(MainDevExt->KeyInfo);
status=STATUS_SUCCESS;
break;
case START_KBD_SCAN:
//Получаем указатель на объект устройство управление мыши
status=IoGetDeviceObjectPointer (&ObjectName,
FILE_ALL_ACCESS,
&FileObject,
&DeviceMouCtrlObject);
if( NT_SUCCESS(status) )
{
// из полученного указателя получем указатель на УУ мыши
MouCtrlDevExt=(PCONTROL_MOUSE_DEVICE_EXTENSION)
DeviceMouCtrlObject->DeviceExtension;
//захват управления над мышью
CtrlDevExtension->MouseLock=&MouCtrlDevExt->MouseLock;
}
//выделение памяти под структру почерка
KeyInfoTemp=(PKEY_INFO)ExAllocatePool(PagedPool,
NUMBER_OF_KEYS*sizeof(KEY_INFO));
// записываем в KeyInfoTemp клавиатурный почерк
status=ReadWriteKeyInfoToFile(KeyInfoTemp, FLAG_READ);
// ели операция чтения успешна
if( NT_SUCCESS(status) )
{
// записываем указатель
MainDevExt->KeyInfoTemp=KeyInfoTemp;
// обнуляем KeyInfo для режима анализ
ResetKeyInfo(MainDevExt->KeyInfo);
// обнуляем список, зопиманаемых клавиш
CountKeyList=0;
// переходим в режим анализ
CtrlDevExtension->ModeFlag=MODE_ANALYSIS;
}
status=STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
default:
break;
}
} else {
ASSERTMSG(FALSE, "Requests being sent to a dead device\n");
status = STATUS_DEVICE_REMOVED;
}
// и завершаем запрос
Irp->IoStatus. Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;}
NTSTATUS
ReadWriteKeyInfoToFile(
IN PKEY_INFO keyinfo,
ULONG flag
)
/*
Routine Description:
Функция записи/чтения структуры почерка в фаило
Аргументы:
keyinfo - указательна структуру почерка
flag - режим работы FLAG_READ/FLAG_WRITE
Возвращаемое значение:
NT status code
*/
{
ULONG Length;
IO_STATUS_BLOCK IoStatus;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS status;
HANDLE FileHandle;
UNICODE_STRING fileName;
// инициализируем имя фаила
fileName. Buffer = NULL;
fileName. Length = 0;
fileName. MaximumLength = sizeof(DEFAULT_LOG_FILE_NAME) + sizeof(UNICODE_NULL);
fileName. Buffer = ExAllocatePool(PagedPool, fileName. MaximumLength);
if (!fileName. Buffer) {
DbgPrint("LogMessage: FAIL. ExAllocatePool Failed");
return FALSE;
}
RtlZeroMemory(fileName. Buffer, fileName. MaximumLength);
status = RtlAppendUnicodeToString(&fileName, (PWSTR)DEFAULT_LOG_FILE_NAME);
InitializeObjectAttributes (&objectAttributes,
(PUNICODE_STRING)&fileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
switch(flag)
{
// если операция на чтение
case FLAG_WRITE:
status = ZwCreateFile( &FileHandle,
FILE_WRITE_DATA,
&objectAttributes,
&IoStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0 );
ZwWriteFile( FileHandle,
NULL, NULL,
NULL,&IoStatus,
keyinfo,
NUMBER_OF_KEYS*sizeof(KEY_INFO),
NULL, NULL );
break;
// если операция на запись
case FLAG_READ:
status = ZwCreateFile( &FileHandle,
FILE_READ_DATA,
&objectAttributes,
&IoStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0 );
ZwReadFile( FileHandle,
NULL, NULL,
NULL,&IoStatus,
keyinfo,
NUMBER_OF_KEYS*sizeof(KEY_INFO),
NULL, NULL );
break;
}
if( NT_SUCCESS(status) ) {
DbgPrint("ZwCreateFile SUCCESS");
ZwClose( FileHandle );
}
if( fileName. Buffer ) {
ExFreePool (fileName. Buffer);
}
return status;;
}
NTSTATUS
FilterInternIoCtl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*
Функция обработки фнутренних запросов
IOCTL_INTERNAL_KEYBOARD_CONNECT:
сохраняем старый контекст и указатель функции
и заменяем на свой для потключения к стеку клавиатуры
Аргументы:
DeviceObject - указательна объект устройство
Irp - указатель на пакет запроса.
Возвращаемое значение:
NT status code
*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION devExt;
KEVENT event;
PCONNECT_DATA connectData;
NTSTATUS status = STATUS_SUCCESS;
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
Irp->IoStatus. Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->Parameters. DeviceIoControl. IoControlCode) {
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
if (devExt->UpperConnectData. ClassService!= NULL) {
status = STATUS_SHARING_VIOLATION;
break;
}
else if (irpStack->Parameters. DeviceIoControl. InputBufferLength <
sizeof(CONNECT_DATA)) {
// неверный буфер
status = STATUS_INVALID_PARAMETER;
break;
}
// копируем параметры соеденения в device extension.
connectData = ((PCONNECT_DATA)
(irpStack->Parameters. DeviceIoControl. Type3InputBuffer));
devExt->UpperConnectData = *connectData;
// заменяем данные на свои, утанавливаем свю функцию
connectData->ClassDeviceObject = devExt->Self;
connectData->ClassService = KbFilter_ServiceCallback;
break;
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
// не потдерживается
status = STATUS_NOT_IMPLEMENTED;
break;
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
case IOCTL_KEYBOARD_QUERY_INDICATORS:
case IOCTL_KEYBOARD_SET_INDICATORS:
case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
case IOCTL_KEYBOARD_SET_TYPEMATIC:
break;
}
if (!NT_SUCCESS(status)) {
Irp->IoStatus. Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
// передаем запрос дальше по стеку
return FilterPass(DeviceObject, Irp);
}
VOID
KbFilter_ServiceCallback(
IN PDEVICE_OBJECT DeviceObject,
IN PKEYBOARD_INPUT_DATA InputDataStart,
IN PKEYBOARD_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
)
/*
Функция, которую вызывает i4082ptr после
генерирования прерывания от клавиатуры
Аргументы:
DeviceObject - указательна объект устройство
InputDataStart - указатель на первый пакет
InputDataEnd - указатель на последний пакет
InputDataConsumed - количество обработаных сообщений
Возвращаемое значение:
VOID
*/
{
int jk;
USHORT i, t,NumberOfKeys, ik, r;
PDEVICE_EXTENSION devExt;
PKEY_INFO keyInf;
PKEY_INFO keyEtalon;
PCONTROL_DEVICE_EXTENSION ControlDevExt;
CHAR buf [300];
// получаем указатель на устройство расширения устройства стека
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
// получаем указатель на устройство расширения утсройства управления
ControlDevExt=(PCONTROL_DEVICE_EXTENSION)ControlDeviceObject->DeviceExtension;
// вытаскиваем указатель на KEY_INFO
keyInf=devExt->KeyInfo;
// определяем количество структур KEYBOARD_INPUT_DATA
NumberOfKeys=(USHORT)(InputDataEnd-InputDataStart);
// если режим анализ, существует указатель на почерк
if(devExt->KeyInfoTemp) keyEtalon=devExt->KeyInfoTemp;
//по всем PKEYBOARD_INPUT_DATA
for (i=0;i<NumberOfKeys;i++)
{
// предварительная обработка нажатия клавиши
if (InputDataStart[i].Flags==KEY_MAKE){
// определяем интервал от предидущего нажатия
gLastLastUp=KeQueryInterruptTime();
// фильтр на слишком долгие паузы, если вермя между нажатием 2х клавиш
// более 3 сек, то эту паузу заменяем на паузу в 1 секунду
if ((gLastLastUp-gLastUp)>) gDelay=gDelay+(gLastLastUp-gLastUp);
gLastUp=gLastLastUp;
// проверка на ввод пароля ----
if ((PasswLock[PasswLock[6]])==(InputDataStart[i].MakeCode)){
PasswLock[6]++;
} else {PasswLock[6]=0;}
if ((PasswUnLock[PasswUnLock[6]])==(InputDataStart[i].MakeCode)){
PasswUnLock[6]++;
} else {PasswUnLock[6]=0;}
if (PasswLock[6]==6){
if(ControlDevExt->MouseLock) {*(ControlDevExt->MouseLock)=TRUE;}
// в режиме обученя пароли не работают
if(ControlDevExt->ModeFlag!=MODE_EDUCATION){ControlDevExt-
>ModeFlag=MODE_BLOCK;}
}
if (PasswUnLock[6]==6){
if(ControlDevExt->MouseLock) *(ControlDevExt->MouseLock)=FALSE;
// в режиме обученя пароли не работают
if(ControlDevExt->ModeFlag!=MODE_EDUCATION){ControlDevExt-
>ModeFlag=MODE_ANALYSIS;}
}
// ------
}
// если в режиме анализа или обучения просчтываем статистику
if((ControlDevExt->ModeFlag==MODE_ANALYSIS)||(ControlDevExt->ModeFlag==MODE_EDUCATION)){
//по всем клавишам (104 штуки)
for (t=0;t<NUMBER_OF_KEYS;t++)
{
//определяем в контексте какой keyinf будем работать
if ((InputDataStart[i].MakeCode==keyInf[t].MakeCode)){
switch (InputDataStart[i].Flags)
{
case KEY_MAKE:
// определяем время последнего нажатия
keyInf[t].LastDown=KeQueryInterruptTime()-gDelay;
break;
case KEY_BREAK:
case KEY_E0:
case KEY_E1:
// подсчёт остальных верменных характеристик
AnalizKeyInfo(keyInf, t);
// если режим анализ, и нажато 30 клавиш
if((ControlDevExt-
>ModeFlag==MODE_ANALYSIS)&&(CountKeyList==NUMBER_OF_CHEK_KEYS))
{
DbgPrint("BEGIN ALGORITM");
r=0;
for (ik=0;ik<NUMBER_OF_CHEK_KEYS-1;ik++)
{
// считаем те интервалы которые попали в границы эталона
if ((keyEtalon[KeyList[ik]].KeyVector[KeyList[ik+1]]-500000<keyInf[KeyList[ik]].KeyVector[KeyList[ik+1]])&&
(keyInf[KeyList[ik]].KeyVector[KeyList[ik+1]]<keyEtalon[KeyList[ik]].KeyVector[KeyList[ik+1]]+500000))
{r++;}
}
// если почерки не сходятся (ALG_FACTOR=2, совпадений меньше половины)
if (r<((NUMBER_OF_CHEK_KEYS-1)/ALG_FACTOR))
{
// блокируем клавиатуру и мыш
ControlDevExt->ModeFlag=MODE_BLOCK;
if(ControlDevExt->MouseLock)
{*(ControlDevExt->MouseLock)=TRUE;}
}
ResetKeyInfo(keyInf);
}
//
// если нажато 30 клавиш, заполняем KeyList по новому
if(CountKeyList==NUMBER_OF_CHEK_KEYS)
{
for (ik=0;ik<NUMBER_OF_CHEK_KEYS;ik++)
{KeyList[ik]=0;}
CountKeyList=0;
}
KeyList[CountKeyList]=InputDataStart[i].MakeCode;
CountKeyList++;
break;
}
}
}
}
}
// если режим блокировки заменяем коды всех клавиш
if(ControlDevExt->ModeFlag==MODE_BLOCK)
{
for (i=0;i<NumberOfKeys;i++)
InputDataStart[i].MakeCode=69;
}
// передаем управление в callback функцию драйвера класса
(*(PSERVICE_CALLBACK_ROUTINE) devExt->UpperConnectData. ClassService)(
devExt->UpperConnectData. ClassDeviceObject,
InputDataStart,
InputDataEnd,
InputDataConsumed);
}
VOID AnalizKeyInfo(
PKEY_INFO keyInf,
USHORT t
)
/*
Функция подсчёта временных характеристк
при отжатии клавишши
Аргументы:
keyInf - указатель на структуру почерка
t - номер клавиши
Возвращаемое значение:
VOID
*/
{
// время последнего отжатия
keyInf[t].LastLastUp=KeQueryInterruptTime()-gDelay;
// последнеие между отжатием и нажатием
keyInf[t].LastFromDownToUp=(ULONG)(keyInf[t].LastLastUp-keyInf[t].LastDown);
// последние между двумя отжатиями
keyInf[t].LastBetweenTwoUp=keyInf[t].LastLastUp-keyInf[t].LastUp;
// перезапоминаем последнее отжатие
keyInf[t].LastUp=keyInf[t].LastLastUp;
// последнее до другой
keyInf[gLastKey].ToOtherBreak=(ULONG)(keyInf[t].LastLastUp-keyInf[gLastKey].LastLastUp);
// если запуск не первый, считаем средние с деление на 2
if(keyInf[t].MeanFromDownToUp!=0){
// среднее между двумя отжатиями
keyInf[t].MeanBetweenTwoUp=(ULONG)((keyInf[t].MeanBetweenTwoUp+
keyInf[t].LastBetweenTwoUp)/2);
// среднеие меду нажатием и отжатием
keyInf[t].MeanFromDownToUp=(ULONG)((keyInf[t].MeanFromDownToUp+
keyInf[t].LastFromDownToUp)/2);
// среднее до другой
keyInf[gLastKey].MeanToOtherBreak=(ULONG)((keyInf[gLastKey].MeanToOtherBreak+
keyInf[gLastKey].ToOtherBreak)/2);
}
// если первый запуск, средние значения считаем без деления на 2:
if(keyInf[t].MeanFromDownToUp==0){
// среднее между двумя отжатиями
keyInf[t].MeanBetweenTwoUp=(ULONG)((keyInf[t].MeanBetweenTwoUp+
keyInf[t].LastBetweenTwoUp));
// среднеие меду нажатием и отжатием
keyInf[t].MeanFromDownToUp=(ULONG)((keyInf[t].MeanFromDownToUp+
keyInf[t].LastFromDownToUp));
// среднее до другой
keyInf[gLastKey].MeanToOtherBreak=(ULONG)((keyInf[gLastKey].MeanToOtherBreak+
keyInf[gLastKey].ToOtherBreak));
}
// первый запуск для вектора межклавишных взаимодействий
if(keyInf[gLastKey].KeyVector[t]==0){
// время нажатия от клавиши gLastKey до t
keyInf[gLastKey].KeyVector[t]= ((keyInf[gLastKey].ToOtherBreak
+keyInf[gLastKey].KeyVector[t]));
}
// не первый запуск для вектора межклавишных взаимодействий
if(keyInf[gLastKey].KeyVector[t]!=0){
// время нажатия от клавиши gLastKey до t
keyInf[gLastKey].KeyVector[t]= (ULONG)((keyInf[gLastKey].ToOtherBreak
+keyInf[gLastKey].KeyVector[t])/2);
}
// количество нажатий данной клавишы
keyInf[t].CountUp++;
// запоминаем текущуб клавишу
gLastKey=t;
}
VOID ResetKeyInfo(
PKEY_INFO KeyInfo
)
/*
Функция обнуления структуры KEY_INFO
Аргументы:
keyInf - указатель на структуру KEY_INFO
Возвращаемое значение:
VOID
*/
{
USHORT i, j;
for(i=0;i<NUMBER_OF_KEYS;i++)
{
KeyInfo[i].CountUp=0;
KeyInfo[i].LastBetweenTwoUp=0;
KeyInfo[i].LastDown=0;
KeyInfo[i].LastFromDownToUp=0;
KeyInfo[i].LastUp=0;
KeyInfo[i].LastLastUp=0;
KeyInfo[i].MakeCode=i;
KeyInfo[i].MeanBetweenTwoUp=0;
KeyInfo[i].MeanFromDownToUp=0;
KeyInfo[i].MeanToOtherBreak=0;
KeyInfo[i].ToOtherBreak=0;
for(j=0;j<NUMBER_OF_KEYS;j++)
{
KeyInfo[i].KeyVector[j]=0;
}
}
}
#include "ntddk. h"
#include "kbdmou. h"
#include "ntddkbd. h"
#include "ntdd8042.h"
#include <stdio. h>
#define GET_KEY_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define WRITE_FILE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define READ_FILE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define START_KBD_SCAN CTL_CODE(FILE_DEVICE_UNKNOWN, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define RESET_KEY_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define GET_KEY_LIST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x905, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define NUMBER_OF_KEYS 104
#define NUMBER_OF_CHEK_KEYS 30
#define DEFAULT_LOG_FILE_NAME L"\\??\\C:\\keydata. dat"
#define NTDEVICE_NAME_STRING L"\\Device\\KbdCtrlFilter"
#define SYMBOLIC_NAME_STRING L"\\DosDevices\\KbdCtrlFilter"
#define FLAG_WRITE 210
#define FLAG_READ 211
#define ALG_FACTOR 2 // чувствительность алгоритма анализа почерка
#ifndef STATUS_CONTINUE_COMPLETION //required to build driver in Win2K and XP build environment
#define STATUS_CONTINUE_COMPLETION STATUS_SUCCESS
#endif
//задание ярлыка для функции IoInitializeRemoveLock
#define POOL_TAG 'arty'
#define MODE_EDUCATION 100
#define MODE_BLOCK 101
#define MODE_ANALYSIS 102
//Глобальные пнрнманные -
USHORT PasswLock[7] ={4,8,6,2,3,8,0}; // пароль на блокировки, переход в режим бокировки = 375127
USHORT PasswUnLock[7] ={3,5,9,10,8,6,0}; // пароль на разблокировку, переход в режим анализ = 248975
ULONGLONG gLastUp =0; // время последнего отжатия
ULONGLONG gLastLastUp =0; // время предпоследнего отжатия
ULONGLONG gDelay =0; // глобальная задержка
USHORT gLastKey =0; // номер полседней нажатой клавиши
FAST_MUTEX ControlMutex; // для понижения IRQL до PASSIVE_LEVEL при создании устройства управления
ULONG InstanceCount = 0; // счётчик экземпляров устройств управления
PDEVICE_OBJECT ControlDeviceObject; // указатель на объект устройство управления
ULONG KeyList [NUMBER_OF_CHEK_KEYS];
ULONG CountKeyList=0;
//--
// Структура, описывающая клавиатурный почерк
typedef struct _KEY_INFO{
ULONG MakeCode; // код клавиши
ULONG CountUp; // количество отжатий
ULONGLONG LastDown; // последнее нажатие
ULONGLONG LastUp; // последнее отжатие
ULONGLONG LastLastUp; // предпоследнее отжатие
ULONG LastFromDownToUp; // посленее нажатие-отпуск
ULONG MeanFromDownToUp; // среднее нажатие отпуск
ULONGLONG LastBetweenTwoUp; // последне между двумя отжатиями
ULONG MeanBetweenTwoUp; // среднее между двумя отжатиями
ULONG ToOtherBreak; // время до другой
ULONG MeanToOtherBreak; // среднее время до другой
ULONG KeyVector[NUMBER_OF_KEYS]; // среднее до определённой
} KEY_INFO,*PKEY_INFO;
typedef enum _DEVICE_PNP_STATE {
NotStarted = 0, // еще не запущено
Started, // устройство получило START_DEVICE IRP
StopPending, // устройство получило QUERY_STOP IRP
Stopped, // устройство получило STOP_DEVICE IRP
RemovePending, // устройство получило QUERY_REMOVE IRP
SurpriseRemovePending, // устройство получило SURPRISE_REMOVE IRP
Deleted // устройство получило REMOVE_DEVICE IRP
} DEVICE_PNP_STATE;
#define INITIALIZE_PNP_STATE(_Data_) \
(_Data_)->DevicePnPState = NotStarted;\
(_Data_)->PreviousPnPState = NotStarted;
#define SET_NEW_PNP_STATE(_Data_, _state_) \
(_Data_)->PreviousPnPState = (_Data_)->DevicePnPState;\
(_Data_)->DevicePnPState = (_state_);
#define RESTORE_PREVIOUS_PNP_STATE(_Data_) \
(_Data_)->DevicePnPState = (_Data_)->PreviousPnPState;\
typedef enum _DEVICE_TYPE {
DEVICE_TYPE_INVALID = 0,
DEVICE_TYPE_FIDO,
DEVICE_TYPE_CDO,
} DEVICE_TYPE;
typedef struct _COMMON_DEVICE_DATA
{
DEVICE_TYPE Type;
} COMMON_DEVICE_DATA, *PCOMMON_DEVICE_DATA;
//устройство расширение устройства стека
typedef struct _DEVICE_EXTENSION
{
COMMON_DEVICE_DATA;
PDEVICE_OBJECT Self; // указатель на сам объект устройство
PDEVICE_OBJECT NextLowerDriver; // вершина стека перед тем как фильтр будет добавлен.
DEVICE_PNP_STATE DevicePnPState; // текущее PnP состояние устройства
DEVICE_PNP_STATE PreviousPnPState; // предидущее PnP состояние устройства
IO_REMOVE_LOCK RemoveLock; // Removelock для защещённой выгрузки
CONNECT_DATA UpperConnectData; // данные на соеденение, которые отправляет драйвер
PVOID UpperContext; // Previous initialization and hook routines (and context)
PKEY_INFO KeyInfo; // указатель на структуру почерка для записи в неё
PKEY_INFO KeyInfoTemp; // указатель на структуру почерка эталона
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//устройство расширение устройства управления
typedef struct _CONTROL_DEVICE_EXTENSION {
COMMON_DEVICE_DATA;
ULONG Deleted; // TRUE если устройство удалено
PVOID ControlData; // Store your control data here
PDEVICE_OBJECT StackObject; // объеект устройство подключенное к стеку
PULONG MouseLock; // указатель на флаг блокировки мыши в
// устройстве расширения устройства управления мыши
ULONG ModeFlag; //в каком режиме работает драйвер в данный момент
} CONTROL_DEVICE_EXTENSION, *PCONTROL_DEVICE_EXTENSION;
//устройство расширение устройства управления мыши
typedef struct _CONTROL_MOUSE_DEVICE_EXTENSION {
COMMON_DEVICE_DATA;
ULONG Deleted; // TRUE если устройство удалено
PVOID ControlData; // для сохранения ControlData
NTSTATUS status; // NTSTATUS
ULONG MouseLock; // если TRUE мышь блоктрована
} CONTROL_MOUSE_DEVICE_EXTENSION, *PCONTROL_MOUSE_DEVICE_EXTENSION;
//Объявленя функций \/\/\/\/\/\/\/\/\/\/\/\/\/\/
PCHAR
PnPMinorFunctionString (
UCHAR MinorFunction
);
NTSTATUS
FilterAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
);
NTSTATUS
FilterDispatchPnp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
FilterDispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
FilterUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
FilterPass (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
FilterStartCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
FilterDeviceUsageNotificationCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
FilterInternIoCtl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
KbFilter_ServiceCallback(
IN PDEVICE_OBJECT DeviceObject,
IN PKEYBOARD_INPUT_DATA InputDataStart,
IN PKEYBOARD_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
);
NTSTATUS
FilterCreateControlObject(
IN PDEVICE_OBJECT DeviceObject
);
VOID
FilterDeleteControlObject(
);
NTSTATUS
FilterDispatchIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
ReadWriteKeyInfoToFile(
IN PKEY_INFO keyinfo,
ULONG flag
);
VOID
ResetKeyInfo(
PKEY_INFO KeyInfo
);
VOID
AnalizKeyInfo(
PKEY_INFO KeyInfo,
USHORT t
);
5.2 Управляющее приложение
#include "ControlApp. h"
int
WINAPI WinMain (
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR szCmdLine,
int iCmdShow
)
/*
Точка входа программы
Аргументы:
hInstance - описателем экземпляра
hPrevInstanceIrp - предыдущий экземпляр
szCmdLine - указатель на командную строку
iCmdShow - начальный вид
Возвращаемое значение:
int
*/
{
static char szAppName[] = "HexCalc" ;
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclass ;
// Регистрация класса окна
wndclass. cbSize = sizeof (wndclass) ;
wndclass. style = CS_HREDRAW | CS_VREDRAW;
wndclass. lpfnWndProc = WndProc ;
wndclass. cbClsExtra = 0 ;
wndclass. cbWndExtra = DLGWINDOWEXTRA ;
wndclass. hInstance = hInstance ;
wndclass. hIcon = LoadIcon (hInstance, szAppName) ;
wndclass. hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass. hbrBackground = (HBRUSH) (COLOR_WINDOW + 0) ;
wndclass. lpszMenuName = NULL ;
wndclass. lpszClassName = szAppName ;
wndclass. hIconSm = LoadIcon (hInstance, szAppName) ;
RegisterClassEx (&wndclass) ;
// создание окна
hwnd = CreateDialog (hInstance, szAppName, 0, NULL) ;
hinst=hInstance;
ShowWindow (hwnd, iCmdShow) ;
// цикл обработки сообщений
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg. wParam ;
}
LRESULT
CALLBACK WndProc (
HWND hwnd,
UINT iMsg,
WPARAM wParam,
LPARAM lParam
)
/*
Точка входа программы
Аргументы:
hwnd - описатель окна
iMsg - принятое сообщение
wParam - параметр сообщения
wParam - параметр сообщения
Возвращаемое значение:
LRESULT
*/
{
DWORD bytesReturned;
DWORD Code, i;
int count, j,temp;
char buf[100];
float p, pcount;
char bufer[2000];
switch (iMsg)
{
case WM_CREATE:
keyinfo=(PKEY_INFO)malloc(104*sizeof(KEY_INFO));
KeyList=(PULONG)malloc(NUMBER_OF_CHEK_KEYS*sizeof(ULONG));
hDevice = CreateFile( "\\\\.\\KbdCtrlFilter",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
return 0;
case WM_COMMAND :
// нажата кнопка на нарисованой клавиатуре
Code=(DWORD)(LOWORD (wParam))-999;
if (Code<94 )
{
sprintf(buf,"%d",Code);
SetDlgItemText(hwnd, IDC_EDIT1,buf);
sprintf(buf,"%d",keyinfo[Code].CountUp);
SetDlgItemText(hwnd, IDC_EDIT2,buf);
sprintf(buf,"%I64d",keyinfo[Code].LastDown);
SetDlgItemText(hwnd, IDC_EDIT3,buf);
sprintf(buf,"%I64d",keyinfo[Code].LastUp);
SetDlgItemText(hwnd, IDC_EDIT4,buf);
sprintf(buf,"%d",keyinfo[Code].LastFromDownToUp);
SetDlgItemText(hwnd, IDC_EDIT5,buf);
sprintf(buf,"%d",keyinfo[Code].MeanFromDownToUp);
SetDlgItemText(hwnd, IDC_EDIT7,buf);
sprintf(buf,"%I64d",keyinfo[Code].LastBetweenTwoUp);
SetDlgItemText(hwnd, IDC_EDIT8,buf);
sprintf(buf,"%d",keyinfo[Code].MeanBetweenTwoUp);
SetDlgItemText(hwnd, IDC_EDIT9,buf);
sprintf(buf,"%d",keyinfo[Code].ToOtherBreak);
SetDlgItemText(hwnd, IDC_EDIT12,buf);
sprintf(buf,"%d",keyinfo[Code].MeanToOtherBreak);
SetDlgItemText(hwnd, IDC_EDIT13,buf);
pcount =0;
for (i=0;i<104;i++)
{pcount+=keyinfo[i].CountUp; }
p=(double)(keyinfo[Code].CountUp/pcount);
sprintf(buf,"%f",p);
SetDlgItemText(hwnd, IDC_EDIT10,buf);
j=0;
for (i=0;i<NUMBER_OF_KEYS;i++)j+=sprintf( bufer+j,"%d%c", keyinfo[Code].KeyVector[i],' ');
SetDlgItemText(hwnd, IDC_EDIT14,bufer);
}
// нажата кнопка получить KeyList
if (LOWORD (wParam)==IDC_GET_KEY_LIST)
{
DeviceIoControl(hDevice,
GET_KEY_LIST,0,0,KeyList,
NUMBER_OF_CHEK_KEYS*sizeof(ULONG),
&bytesReturned, NULL);
j=0;temp=0;
for (i=0;i<NUMBER_OF_CHEK_KEYS;i++)
{
if (KeyList[i]==0) {temp++;}
j+=sprintf( bufer+j,"%d%c", KeyList[i],' ');
}
SetDlgItemText(hwnd, IDC_EDIT15,bufer);
j=0; //if (temp==0){temp=1;}
for (i=0;i<NUMBER_OF_CHEK_KEYS-temp-1;i++)
j+=sprintf( bufer+j,"%d%c", keyinfo[KeyList[i]].KeyVector[KeyList[i+1]],' ');
SetDlgItemText(hwnd, IDC_EDIT16,bufer);
}
// нажата кнопка пуск
if (LOWORD (wParam)==IDC_PUSK)
{
DeviceIoControl(hDevice, START_KBD_SCAN,0,0,0,
0,&bytesReturned, NULL);
}
// нажата кнопка сбросить все показатели
if (LOWORD (wParam)==IDC_RESET)
{
DeviceIoControl(hDevice, RESET_KEY_INFO,0,0,0,
0,&bytesReturned, NULL);
}
// нажата кнопка сохраниьт все показатели
if (LOWORD (wParam)==IDC_SAVE)
{
DeviceIoControl(hDevice, WRITE_FILE,0,0,0,
0,&bytesReturned, NULL);
}
// нажата кнопка обнавить данные
if (LOWORD (wParam)==IDC_UPDATE)
{
DeviceIoControl(hDevice,
GET_KEY_INFO,0,0,keyinfo,
NUMBER_OF_KEYS*sizeof(KEY_INFO),
&bytesReturned, NULL);
count =0;
for (i=0;i<NUMBER_OF_KEYS;i++)
{count+=keyinfo[i].CountUp; }
sprintf(buf,"%d",count);
SetDlgItemText(hwnd, IDC_EDIT6,buf);
}
if (LOWORD (wParam)==IDC_ABOUT)
{
DialogBox (hinst, (LPCTSTR)IDD_ABOUT, hwnd, AboutDlgProc);
}
return 0;
case WM_DESTROY :
free(keyinfo);
free(KeyList);
CloseHandle(hDevice);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
BOOL
CALLBACK AboutDlgProc (
HWND hDlg,
UINT iMsg,
WPARAM wParam,
LPARAM lParam
)
/*
Точка входа программы
Аргументы:
hInstance - описателем экземпляра
hPrevInstanceIrp - предыдущий экземпляр
szCmdLine - указатель на командную строку
iCmdShow - начальный вид
Возвращаемое значение:
BOOL
*/
{
switch (iMsg)
{
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDOK :
EndDialog (hDlg, 0) ;
return TRUE ;
}
break ;
}
return FALSE ;
}
ControlApp. h
#include <windows. h>
#include <limits. h>
#include <stdlib. h>
#include <string. h>
#include <ctype. h>
#include "resource. h"
#define NUMBER_OF_KEYS 104
#define NUMBER_OF_CHEK_KEYS 30
typedef struct _KEY_INFO{
ULONG MakeCode;
ULONG CountUp;
ULONGLONG LastDown;
ULONGLONG LastUp;
ULONGLONG LastLastUp;
ULONG LastFromDownToUp;
ULONG MeanFromDownToUp;
ULONGLONG LastBetweenTwoUp;
ULONG MeanBetweenTwoUp;
ULONG ToOtherBreak;
ULONG MeanToOtherBreak;
ULONG KeyVector[NUMBER_OF_KEYS];
} KEY_INFO,*PKEY_INFO;
#define GET_KEY_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define WRITE_FILE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define READ_FILE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define START_KBD_SCAN CTL_CODE(FILE_DEVICE_UNKNOWN, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define RESET_KEY_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define GET_KEY_LIST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x905, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ID_TIMER 1
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
PKEY_INFO keyinfo;
HANDLE hDevice;
PLONG KeyList ;
HINSTANCE hinst;
5.2 Драйвер фильтр мыши
Код аналогичен клавиатурному фильтру, интерес составляет только MouFilter_ServiceCallback
VOID
MouFilter_ServiceCallback(
IN PDEVICE_OBJECT DeviceObject,
IN PMOUSE_INPUT_DATA InputDataStart,
IN PMOUSE_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
)
{
USHORT i, num;
PDEVICE_EXTENSION devExt;
PCONTROL_MOUSE_DEVICE_EXTENSION MouCtrlDevExt;
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
MouCtrlDevExt=(PCONTROL_MOUSE_DEVICE_EXTENSION)ControlDeviceObject->DeviceExtension;
num=(USHORT)(InputDataEnd-InputDataStart);
if(!MouCtrlDevExt->MouseLock)
{
(*(PSERVICE_CALLBACK_ROUTINE) devExt->UpperConnectData. ClassService)(
devExt->UpperConnectData. ClassDeviceObject,
InputDataStart,
InputDataEnd,
InputDataConsumed
);
}
}
6. ЛИТЕРАТУРА
Программирование для Windows 95 в двух томах. «BHV — Санкт-Петербург», 2003 г. Windows для профессионалов: создание эффективных Win32 приложений с учетом специфики 64-разрядной версии Windows/Пер, англ - 4-е изд. - СПб; Питер; М.: Издательско-торговый дом "Русская Редакция", 20с.; ил. Румянцев программирования в WIN32 API Сорокина драйверов и систем безопасности: Учеб. Пособие – Спб.: БХВ – Петербург, 2003. – 256 с.:ил. и Внутреннее устройство Microsoft Windows 2000. Мастер-класс / Пер. с англ. — СПб.: Питер; М.: Издательско-торговый дом «Русская Редакция». 2004. — 746 стр.: ил. Солдатов драйверов Windows. Изд. 2-е, перераб. и доп. М.: -Пресс», 2004 г. Савинков материал по курсу «Операционные системы» Современные операционные системы. 2-е изд. – СПб.: Питер, 2002. – 1040 с.:ил. , Фролов для Windows NT части 1,2. 1996 г. http://www. *****/article. php? article=drvw2k16 MSDN Library, Copyright Microsoft Corporation Driver Development Kit (DDK) documentation, built on Tuesday, February 22, 2005 г.

