Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 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 г.