I’m trying to make a keyboard class filter and it works fine if I do not make it as a class filter and I only attach to one device (my IRP_MJ_READ callback is called).
However, after installing it as a class filter driver, my IRP_MJ_READ callback is never called, even tho the device is registered and attached successfully.
My DriverEntry where I register the functions callbacks:
`NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
// Set driver unload callback
DriverObject->DriverUnload = KeyboardFilterDriverUnload;
// Set general pass through
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = KeyboardFilterIrpPassthrough;
}
// Set read callback
DriverObject->MajorFunction[IRP_MJ_READ] = KeyboardFilterIrpRead;
// Set AddDevice callback
DriverObject->DriverExtension->AddDevice = KeyboardFilterAddDevice;
// Set PnP callback
DriverObject->MajorFunction[IRP_MJ_PNP] = KeyboardFilterIrpPnP;
KdPrint(("[KB] Loaded driver"));
return STATUS_SUCCESS;
}`
My AddDevice handler:
`
NTSTATUS KeyboardFilterAddDevice(IN struct _DRIVER_OBJECT* DriverObject, IN struct _DEVICE_OBJECT* PhysicalDeviceObject) {
PDEVICE_OBJECT DeviceObject;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KEYBOARD, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject);
if (!NT_SUCCESS(status)) {
KdPrint(("[KB] Failed to create device"));
return status;
}
// Initialize extension
RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// Set buffer io flag
DeviceObject->Flags |= DO_BUFFERED_IO;
// Get device name
WCHAR wcsDeviceID[256] = { 0 };
ULONG dataLen;
NTSTATUS nameStatus = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyHardwareID, sizeof(wcsDeviceID), &wcsDeviceID, &dataLen);
UNICODE_STRING nameUnicode = { 0 };
RtlInitEmptyUnicodeString(&nameUnicode, wcsDeviceID, 256);
if (nameStatus == STATUS_SUCCESS) {
RtlAppendUnicodeToString(&nameUnicode, wcsDeviceID);
}
else {
RtlAppendUnicodeToString(&nameUnicode, L"UNKNOWN");
}
deviceExtension->DeviceID = &nameUnicode;
KdPrint(("[KB] KeyboardID: %wZ \n", deviceExtension->DeviceID));
// Attach to keyboard driver chain
deviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(
DeviceObject,
PhysicalDeviceObject);
deviceExtension->DeviceObject = DeviceObject;
// Set done flag
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
KdPrint(("[KB] Successfully attached to keyboard chain"));
return STATUS_SUCCESS;
}
And here is my Pnp Remove Device handler (for the problem I listed below):
VOID KeyboardFilterDeleteDeviceFromExtension(PDEVICE_EXTENSION DeviceExtension) {
KdPrint((“[KB] Deleting device: %wZ \n”, DeviceExtension->DeviceID));
RtlFreeUnicodeString(DeviceExtension->DeviceID);
IoDetachDevice(DeviceExtension->LowerDeviceObject);
IoDeleteDevice(DeviceExtension->DeviceObject);
KdPrint(("[KB] Device deleted"));
return;
}
NTSTATUS KeyboardFilterIrpPnP(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
IO_STACK_LOCATION* stack = IoGetCurrentIrpStackLocation(Irp);
switch (stack->MinorFunction) {
case IRP_MN_START_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_REMOVE_DEVICE:
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS ret = IoCallDriver(deviceExtension->LowerDeviceObject, Irp);
KeyboardFilterDeleteDeviceFromExtension(deviceExtension);
return ret;
}
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(deviceExtension->LowerDeviceObject, Irp);
}
`
Another problem I’m facing off is when there are multiple devices connected and I disconnect one device (IrpPNP callback is called with IRP_MN_REMOVE_DEVICE minor), however for an unknown reason, I can’t detach/delete my objects, the device extension returned from the DeviceObject that comes as parameter doesn’t contains what PDEVICE_EXTENSION contains).
When I mount a device, I get the following WinDbg:
[KB] KeyboardID: HID\VID_04F2&PID_1516&REV_0111&MI_00 [KB] Successfully attached to keyboard chain
However, when I dismount a device, I get the following WinDbg then the system crashes:
`[KB] Deleting device: KDTARGET: Refreshing KD connection
*** Fatal System Error: 0x0000007e
(0xFFFFFFFFC0000005,0xFFFFF8060A6407E7,0xFFFF880EBA3DB178,0xFFFF880EBA3DA9B0)
Break instruction exception - code 80000003 (first chance)`
It doesn’t know what the value of DeviceID is (so I’m guessing the pointer to the DeviceExtension is not actually a PDEVICE_EXTENSION?)