Привет всем! Пишу фильтр клавиатуры, успешно прицепился к стеку(виден в DeviceTree): Код (Text): PDEVICE_EXTENSION devExt; PDEVICE_OBJECT device; UNICODE_STRING devName; NTSTATUS status; status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KEYBOARD, 0, FALSE, &device ); if (!NT_SUCCESS(status)) { return (status); } RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION)); devExt = (PDEVICE_EXTENSION) device->DeviceExtension; devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, device); RtlInitUnicodeString(&devName, L"\\Device\\KeyboardClass0"); IoAttachDevice(device, &devName, &devExt->TopOfStack); if (devExt->TopOfStack == NULL) { IoDeleteDevice(device); return STATUS_DEVICE_NOT_CONNECTED; } ASSERT(devExt->TopOfStack); device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE); device->Flags &= ~DO_DEVICE_INITIALIZING; return status; А вот обработчик DriverObject->MajorFunction [IRP_MJ_READ] = DispatchRead: Код (Text): NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) { DbgPrint("Bla Bla"); IoCopyCurrentIrpStackLocationToNext(pIrp); return IoCallDriver(((PDEVICE_EXTENSION)pDeviceObject->DeviceExtension)->pKeyboardDevice, pIrp); } Т.е. в моем понимании, при нажатии клавиш, должна вызываться ф-ция DispatchRead. Но сообщения в DriverMonitor я не вижу. Где моя ошибка?
Когда же вы наконец поймёте, что когда что-то пишешь нельзя тупо копипастить, нужно хотя бы приблизительно понять чужой кусок кода. Вот и здесь явно видно что либо тупо скопипастил, либо писал сам, при этом даже не делая попыток разобраться в происходящем. Итого: Посмотри внимательно документацию на функцию IoAttachDeviceToDeviceStack(), думаю, это наведёт тебя на мысль о природе твоей ошибки. Кроме того, на сегодняшний день рекомендуется использовать вместо неё IoAttachDeviceToDeviceStackSafe(). А это ничего, что значение полю pKeyboardDevice нигде не присваивается?
Каюсь, грешен, но с этими драйверами черт ногу сломит... Но: 1. К стеку мы всетаки прицепились (а про ф-цию сейчас прочитаю-исправлю(сь)) 2. этих вызовов может и не быть в DispatchRead, но както управление туда ведь должно попадать?
Так, ещё раз. 1. Зачем здесь вообще вызов IoAttachDeviceToDeviceStack()? Это совершенно лишнее, убери. 2. Создание фильтрующего устройства не совсем корректно у тебя, ибо 2.1. Вместо FILE_DEVICE_KEYBOARD следует указать pTargetDevice -> DeviceType. 2.2. Вместо (DO_BUFFERED_IO | DO_POWER_PAGABLE) следует указать pTargetDevice -> Flags (выборочно). При этом pTargetDevice следует получить заранее через IoGetDeviceObjectPointer() и использовать IoAttachDeviceToDeviceStackSafe() вместо IoAttachDevice(). Именно так, потому что в общем случае ты не знаешь характеристик целевого девайса, а это важно, т.к. твой девайс должен иметь те же параметры. 3. Это верно: 4. Поле pKeyboardDevice тебе не нужно, замени на TopOfStack. 5. Что с остальными запросами? Например, ты IRP_MJ_CREATE обрабатываешь? Или только IRP_MJ_READ? Приложения-то как там вообще, с ума не сходят после загрузки твоего фильтра? 6. Как насчёт обработки IRP_MJ_PNP и IRP_MJ_POWER? Они вообще-то обязательны. Ты вообще legacy или WDM фильтр хочешь? Я посоветовал бы взять пример kbfiltr из WDK, там всё как надо, но это WDM, если что.
По первому пункту исправился: Код (Text): PDEVICE_EXTENSION devExt; PDEVICE_OBJECT device; UNICODE_STRING devName; NTSTATUS status; PFILE_OBJECT use_fileObject; PDEVICE_OBJECT use_deviceObject; status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KEYBOARD, 0, FALSE, &device ); if (!NT_SUCCESS(status)) { return (status); } RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION)); devExt = (PDEVICE_EXTENSION) device->DeviceExtension; RtlInitUnicodeString(&devName, L"\\Device\\KeyboardClass0"); status = IoGetDeviceObjectPointer(&devName, FILE_READ_DATA, &use_fileObject, &use_deviceObject); if(!NT_SUCCESS(status)) { DbgPrint("Error get device object poiner: %d", status); return status; } devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, use_deviceObject); if (devExt->TopOfStack == NULL) { IoDeleteDevice(device); return STATUS_DEVICE_NOT_CONNECTED; } ASSERT(devExt->TopOfStack); device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE); device->Flags &= ~DO_DEVICE_INITIALIZING; return status; Обработчик IRP_MJ_READ сделал пустым(только DbgPrint), но туда не заходит управление.
По первому пункту исправился: Код (Text): PDEVICE_EXTENSION devExt; PDEVICE_OBJECT device; UNICODE_STRING devName; NTSTATUS status; PFILE_OBJECT use_fileObject; PDEVICE_OBJECT use_deviceObject; status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KEYBOARD, 0, FALSE, &device ); if (!NT_SUCCESS(status)) { return (status); } RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION)); devExt = (PDEVICE_EXTENSION) device->DeviceExtension; RtlInitUnicodeString(&devName, L"\\Device\\KeyboardClass0"); status = IoGetDeviceObjectPointer(&devName, FILE_READ_DATA, &use_fileObject, &use_deviceObject); if(!NT_SUCCESS(status)) { DbgPrint("Error get device object poiner: %d", status); return status; } devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, use_deviceObject); if (devExt->TopOfStack == NULL) { IoDeleteDevice(device); return STATUS_DEVICE_NOT_CONNECTED; } ASSERT(devExt->TopOfStack); device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE); device->Flags &= ~DO_DEVICE_INITIALIZING; return status; Обработчик IRP_MJ_READ сделал пустым(только DbgPrint), но туда не заходит управление.
Упс, не то хотел отправить, вот окончательный код, с учетом всех исправлений: Код (Text): PDEVICE_EXTENSION devExt; PDEVICE_OBJECT device; UNICODE_STRING devName; NTSTATUS status; PFILE_OBJECT use_fileObject; PDEVICE_OBJECT use_deviceObject; RtlInitUnicodeString(&devName, L"\\Device\\KeyboardClass0"); status = IoGetDeviceObjectPointer(&devName, FILE_READ_DATA, &use_fileObject, &use_deviceObject); if(!NT_SUCCESS(status)) { DbgPrint("Error get device object poiner: %d", status); return status; } status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, use_deviceObject->DeviceType, 0, FALSE, &device ); if (!NT_SUCCESS(status)) { DbgPrint("Error during device creation: %d", status); return (status); } RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION)); devExt = (PDEVICE_EXTENSION) device->DeviceExtension; devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, use_deviceObject); if (devExt->TopOfStack == NULL) { DbgPrint("Impossible to attach device to stack drivers"); IoDeleteDevice(device); return STATUS_DEVICE_NOT_CONNECTED; } ASSERT(devExt->TopOfStack); device->Flags = use_deviceObject->Flags; device->Flags &= ~DO_DEVICE_INITIALIZING; return status; А вот с ф-цией IoAttachDeviceToDeviceStackSafe() незадача, нет ее у меня походу: Обработчик IRP_MJ_READ до сих пор не работает! В чем еще дело?
А, все! Прицепил клавиатуру PS/2 и все заработало! Интересно, а в какой стек цеплять драйвер, если клавиатура работает по bluetooth?
А вот и нифига! Вызов IoGetDeviceObjectPointer(); проходит неуспешно. Аналогичную ситуацию описывал автор в 16й статье по разработке драйверов (на этом сайте). Здесь походу нужен совсем другой подход... хех...
Ещё раз: цепляться тебе в любом случае к драйверу класса, ибо это есть абстракция от тех самых стеков, о которых ты говоришь. А получить указатель на девайс клавиатуры можно двумя способами: 1. Написать WDM-фильтр (см. пример в WDK), в этом случае указатель на целевой девайс сам приедет тебе в функцию AddDevice(). 2. В случае legacy-фильтра попробовать получить указатель на объект-девайс топорным методом через IoCreateFileSpecifyDeviceObjectHint() с соответствующими флагами. Не советую использовать для этого ObReferenceObjectByName(), потому как для объектов типа "Device" эта функция не работает.
Спасибо за совет, попробую обязательно. Но для начала доведу до ума начатое: сейчас споткнулся на получении сканкодов клавиш, т.е.: Код (Text): NTSTATUS DispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PKEYBOARD_INPUT_DATA KeyData; KeyData = Irp->AssociatedIrp.SystemBuffer; DbgPrint("Key pressed: %d", KeyData[0].MakeCode); IoCopyCurrentIrpStackLocationToNext(Irp); return IoCallDriver(((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->TopOfStack, Irp); } Выводит постоянно 0. А по описанию это должен быть сканкод.
>x64 Насчет присоединиться к стеку другой клавиатуры(не ps/2): так ведь в AddDevice по сути будет тот же самый код, что сейчас у меня отвечает за соединение со стеком. В чем принципиальное отличие WDM?
А ты почитай в документации про 1. регистрацию WDM-драйверов. 2. функцию AddDevice, её назначение и использование. Мне, честно говоря, уже лень объяснять такую элементарщину...
x64 2. В случае legacy-фильтра попробовать получить указатель на объект-девайс топорным методом через IoCreateFileSpecifyDeviceObjectHint() с соответствующими флагами. Было несколько попыток, типа: Код (Text): if (pModInitParams->InitParam.LowPart == 0) RtlInitUnicodeString(&KbdDevClassName, L"\\Device\\KeyboardClass0"); else RtlInitUnicodeString(&KbdDevClassName, L"\\Device\\KeyboardClass1"); InitializeObjectAttributesKrnlObj(&ObjAttr, &KbdDevClassName, OBJ_CASE_INSENSITIVE, NULL, NULL); RetStatus = IoCreateFileSpecifyDeviceObjectHint(&KbdHandle, FILE_READ_ATTRIBUTES, &ObjAttr, &IoBlock, NULL, FILE_ATTRIBUTE_DEVICE, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN , FILE_NON_DIRECTORY_FILE | IO_ATTACH_DEVICE_API, NULL, 0, CreateFileTypeNone, NULL, IO_IGNORE_SHARE_ACCESS_CHECK, NULL); Log_WriteW(L"DriverEntry", L"IoCreateFileSpecifyDeviceObjectHint", RetStatus); if NT_SUCCESS( RetStatus ) __try { PFILE_OBJECT LocalFileObject; RetStatus = ObReferenceObjectByHandle(KbdHandle, 0, *IoFileObjectType, KernelMode, (PVOID*)&LocalFileObject, NULL); Log_WriteW(L"DriverEntry", L"ObReferenceObjectByHandle", RetStatus); if (NT_SUCCESS(RetStatus)) __try { PDEVICE_OBJECT TargetDevice = IoGetRelatedDeviceObject(LocalFileObject); if (TargetDevice) RetStatus = IoAttachDeviceToDeviceStackSafe(deviceObject, TargetDevice, &extension->DeviceObject); else RetStatus = STATUS_ACCESS_VIOLATION; } __finally { ObDereferenceObject(LocalFileObject); } } __finally { ZwClose(KbdHandle); }; но к успеху они не привели: возвращаемая ошибка "файл занят другим приложением". Это было только предположение, или реально получилось ? Если второе, то не подскажите ли где я партачу ? P.S. C KeyboardClass0 все работает.