I Have following custom mouse driver for Windows which i cannot load properly in the windows kernel
#include <ntddk.h>
#include <ntstrsafe.h>
#pragma warning(disable : 4201)
typedef struct
{
PDEVICE_OBJECT LowerKbdDevice;
} DEVICE_EXTENSION, * PDEVICE_EXTENSION;
PDEVICE_OBJECT myKbdDevice = NULL;
ULONG pendingkey = 0;
int first_time = TRUE;
typedef struct _MOUSE_INPUT_DATA {
USHORT UnitId;
USHORT Flags;
union {
ULONG Buttons;
struct {
USHORT ButtonFlags;
USHORT ButtonData;
};
};
ULONG RawButtons;
LONG LastX;
LONG LastY;
ULONG ExtraInformation;
} MOUSE_INPUT_DATA, * PMOUSE_INPUT_DATA;
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
LARGE_INTEGER interval = { 0 };
interval.QuadPart = -10 * 1000 * 1000; // 1 second
PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;
IoDetachDevice(((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerKbdDevice);
while (pendingkey)
{
KeDelayExecutionThread(KernelMode, FALSE, &interval);
}
IoDeleteDevice(myKbdDevice);
DbgPrintEx(0, 0, "Mouse filter unloaded\n");
}
NTSTATUS DispatchPass(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(Irp);
DbgPrintEx(0, 0, "DispatchPass: %d\n", sl->MajorFunction);
UNREFERENCED_PARAMETER(DeviceObject);
IoCopyCurrentIrpStackLocationToNext(Irp);
NTSTATUS status = IoCallDriver(((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerKbdDevice, Irp);
return status;
}
NTSTATUS ReadComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Context);
PMOUSE_INPUT_DATA Keys = (PMOUSE_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
int structnum = (ULONG)Irp->IoStatus.Information / sizeof(PMOUSE_INPUT_DATA);
if (structnum == 0) {
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
for (int i = 0; i < structnum; i++)
{
DbgPrintEx(0, 0, "The button state is %x\n", Keys->ButtonFlags);
}
}
else {
DbgPrintEx(0, 0, "Complete status not success: %d\n", Irp->IoStatus.Status);
}
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
pendingkey--;
return STATUS_CONTINUE_COMPLETION;
}
NTSTATUS DispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
IoCopyCurrentIrpStackLocationToNext(Irp);
pendingkey++;
IoSetCompletionRoutineEx(DeviceObject, Irp, ReadComplete, NULL, TRUE, TRUE, TRUE);
NTSTATUS status = IoCallDriver(((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerKbdDevice, Irp);
DbgPrintEx(0, 0, "DispatchRead: IoCallDriver status is %d\n", status);
return status;
}
NTSTATUS MyAttachDevice(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING TargetDevice = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
PAGED_CODE();
NTSTATUS status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &myKbdDevice);
if (!NT_SUCCESS(status)) {
DbgPrintEx(0, 0, "IoCreateDevice failed\n");
return status;
}
RtlZeroMemory(myKbdDevice->DeviceExtension, sizeof(DEVICE_EXTENSION));
myKbdDevice->Flags |= DO_BUFFERED_IO;
myKbdDevice->Flags &= ~DO_DEVICE_INITIALIZING;
status = IoAttachDevice(myKbdDevice,&TargetDevice,&((PDEVICE_EXTENSION)myKbdDevice->DeviceExtension)->LowerKbdDevice);
if (!NT_SUCCESS(status)) {
DbgPrintEx(0, 0, "IoAttachDevice failed with status %d\n", status);
IoDeleteDevice(myKbdDevice);
return status;
}
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = DriverUnload;
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = DispatchPass;
}
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
NTSTATUS status = MyAttachDevice(DriverObject);
if (!NT_SUCCESS(status)) {
DbgPrintEx(0, 0, "MyAttachDevice failed\n");
return status;
}
return STATUS_SUCCESS;
}
After starting driver through OSR Loader, i am immediately get IRP_MJ_CLOSE IRP and can`t understand why. I use laptop with built-in touch pad. As i know, in this case, PointerClass0 device should represent laptop's touchpad (Mouse). Maybe i need to use other class instead of PointerClass0? I am also have PointerClass1 and PointerClass2, but for this classes, IoAttachDevice always fails. Can anybody have idea?
Solved. I Changed MyAttachDevice function like this:
NTSTATUS MyAttachDevice(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING MCName = RTL_CONSTANT_STRING(L"\\Driver\\Mouclass");
PDRIVER_OBJECT TargetDriverObject;
PDEVICE_OBJECT CurrentDeviceObject;
PDEVICE_OBJECT myDeviceObject = NULL;
DbgPrintEx(0, 0, "Before ObReferenceObjectByName\n");
NTSTATUS status = ObReferenceObjectByName(&MCName, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*)&TargetDriverObject);
if (!NT_SUCCESS(status)) {
DbgPrintEx(0, 0, "ObReferenceObjectByName failed\n");
return status;
}
CurrentDeviceObject = TargetDriverObject->DeviceObject;
ObDereferenceObject(TargetDriverObject);
while (CurrentDeviceObject)
{
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &myDeviceObject);
if (!NT_SUCCESS(status)) {
DbgPrintEx(0, 0, "IoCreateDevice failed\n");
return status;
}
RtlZeroMemory(myDeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
DbgPrintEx(0, 0, "Before IoAttachDeviceToDeviceStackSafe\n");
status = IoAttachDeviceToDeviceStackSafe(myDeviceObject, CurrentDeviceObject, &((PDEVICE_EXTENSION)myDeviceObject->DeviceExtension)->LowerKbdDevice);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(myDeviceObject);
DbgPrintEx(0, 0, "IoAttachDeviceToDeviceStackSafe failed\n");
return status;
}
myDeviceObject->Flags |= DO_BUFFERED_IO;
myDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
CurrentDeviceObject = CurrentDeviceObject->NextDevice;
}
return STATUS_SUCCESS;
}
In short: we need attach our devices to devices from "\Driver\Mouclass" instead of "\Device\PointerClass0"
And also unload function should be like this:
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
LARGE_INTEGER interval = { 0 };
PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;
interval.QuadPart = -10 * 1000 * 1000; // 1 second
while (DeviceObject)
{
IoDetachDevice(((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerKbdDevice);
DeviceObject = DeviceObject->NextDevice;
}
while (pendingkey)
{
KeDelayExecutionThread(KernelMode, FALSE, &interval);
}
DeviceObject = DriverObject->DeviceObject;
while (DeviceObject)
{
IoDeleteDevice(DeviceObject);
DeviceObject = DeviceObject->NextDevice;
}
DbgPrintEx(0, 0, "Mouse filter unloaded\n");
}
Also, we should add prototype for undocumented function ObReferenceObjectByName
// undocumented function
NTSYSAPI NTSTATUS NTAPI ObReferenceObjectByName(
PUNICODE_STRING ObjectName,
ULONG Attributes,
PACCESS_STATE AccessState,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID ParseContext OPTIONAL,
PVOID* Object
);