Search code examples
cwindowsdriverwindows-kernel

Mouse filter driver gets IRP_MJ_CLOSE after starting


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?


Solution

  • 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
    );