Mouse filter driver BSOD

I am trying to create an upper filter driver for a usb mouse. To do this I used the KMDF template in Visual Studio and I am testing the driver on a Windows 10 Vm (VmWare). Then on the Vm after turning on test signing mode I would install the inf file which adds my driver to %windir%\system32\drivers it also creates a service directory and adds the drivers name to the mouse’s upperfilter regedit. One issue with this is that it adds my driver bellow mouclass when it needs to add it above it any ideas on how I can invert this? For now I just manually move it above so that I can continue on testing


Anyways at this point I do sc query kmdf and I can see my driver is installed and that its disabled. I can manually start it from console but that does not actually make the filter driver work (I know this because I only receive debug messages originating from the DriverEntry function). I assume that my driver requires a reboot for it to actually be injected into the mouse software stack. However, this is where my main issues occur. Rebooting bricks the whole OS with a BSOD and I receive a Kernel_Security_Check_Failure. I have been looing this up for a while now and I have not found any resources describing possible causes or solutions. I have had this happen to me multiple times one time with basically the same code as MouseFilter and the second time with a bare bones driver that just contained the the DriverEntry function. From what I read excluding functions in your filter driver means the kernel will just pass it on down the line. I also know that sometimes not returning success in a function (for example in AddDevice) can cause the kernel to not pass it down the line which in my case would be to mouclass. But having said that I don’t know what is wrong in this particular situation because in the past I had an issue where my mouse would just not work but breaking my whole OS is so much worse.


I have looked at countless mouse filter drivers but I have not found a single one that uses INF files that actually works. If you have any links to ones that I can use as a template please let me know. Anyways here is my INF file, DriverEntry function, and AddDevice function in case you were curious.

[Version]
Signature="$WINDOWS NT$"
Class=Mouse
ClassGuid= %ClassGUIDToFilter%
Provider=%Provider%
CatalogFile=KMDF.cat
DriverVer=03/15/2023, 1.0.0.0
PnpLockdown=1

[DestinationDirs]
DefaultDestDir = 12 ; DIRID_DRIVERS

[DefaultInstall.NT]
CopyFiles = KMDF.CopyFiles
Addreg = KMDF.AddReg

[KMDF.AddReg]
"HKLM", System\CurrentControlSet\Control\Class\%ClassGUIDToFilter%, "UpperFilters", 0x00010008, %DriverName%   

[KMDF.CopyFiles]
KMDF.sys

[DefaultInstall.NT.Services]
Include = MSMOUSE.INF
Needs = HID_Mouse_Inst.NT.Hw
AddService = KMDF, , KMDF.Service.Install

;[ControlFlags]
; We don't want our device to be installable via the non-PnP hardware dialogs 
;ExcludeFromSelect = *

; ================= Class section =====================

[SourceDisksNames]
1 = %DiskName%

[SourceDisksFiles]
KMDF.sys = 1

; -------------- KMDF driver install sections https://learn.microsoft.com/en-us/windows-hardware/drivers/install/inf-addservice-directive
[KMDF.Service.install]
DisplayName    = %KMDF.SvcDesc%
ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
StartType      = 3                  ; SERVICE_DEMAND_START
ErrorControl   = 1                  ; SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\KMDF.sys

; -------------- String definitions
[Strings]
Provider = "u/IgnoreException"

; Mfg names
IgnoreException = "IgnoreException"

; Service names
KMDF.SvcDesc = "KMDF Service"

; Media names
DiskName = "KMDF Driver Disk"

ClassGUIDToFilter       = "{4d36e96f-e325-11ce-bfc1-08002be10318}"
ServiceDescription      = "Generic Upper Filter"
moufiltr.DeviceDesc	= "Mouse Filter Sample Device"
ServiceName                = "KMDF"
DriverName                  = "KMDF"
DiskId1                           = "Genric Upper Filter Installation Disk"

; Standard defs
SPSVCINST_TAGTOFRONT  = 0x00000001
SPSVCINST_ASSOCSERVICE= 0x00000002
SERVICE_KERNEL_DRIVER = 1
SERVICE_BOOT_START    = 0
SERVICE_SYSTEM_START  = 1
SERVICE_AUTO_START    = 2
SERVICE_ERROR_NORMAL  = 1
SERVICE_ERROR_IGNORE  = 0
REG_EXPAND_SZ         = 0x00020000
REG_DWORD             = 0x00010001
REG_SZ                = 0x00000000
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, MouFilter_EvtDeviceAdd)
#endif;

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    WDF_DRIVER_CONFIG config;
    NTSTATUS status;
    WDFDRIVER driver;

    // Initialize WPP Tracing
    DebugMessage(" ");
    DebugMessage("Starting KMDF");
    DebugMessage(" ");

    DebugPrint("Mouse Filter Driver Sample - Driver Framework Edition.\n");
    DebugPrint(("Built %s %s\n", __DATE__, __TIME__));

    WDF_DRIVER_CONFIG_INIT(&config, MouFilter_EvtDeviceAdd);

    status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    return status;
}
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, MouFilter_EvtDeviceAdd)
#pragma alloc_text (PAGE, MouFilter_EvtIoInternalDeviceControl)
#endif

#pragma warning(push)
#pragma warning(disable:4055) // type case from PVOID to PSERVICE_CALLBACK_ROUTINE
#pragma warning(disable:4152) // function/data pointer conversion in expression

NTSTATUS MouFilter_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
{
    WDF_OBJECT_ATTRIBUTES  deviceAttributes;
    NTSTATUS  status;
    WDFDEVICE hDevice;
    WDF_IO_QUEUE_CONFIG ioQueueConfig;

    UNREFERENCED_PARAMETER(Driver);
    PAGED_CODE();

    DebugMessage(" ");
    DebugMessage("Adding MouFilter Device");
    DebugMessage(" ");

    DebugPrint(("Enter FilterEvtDeviceAdd \n"));

    // Tell the framework that you are filter driver. Framework takes care of inherting all the device flags & characterstics from the lower device you are attaching to.
    WdfFdoInitSetFilter(DeviceInit);

    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_MOUSE);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);

    // Create a framework device object.  This call will in turn create a WDM deviceobject, attach to the lower stack and set the appropriate flags and attributes.
    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &hDevice);
    if (!NT_SUCCESS(status)) {
        DebugPrint(("WdfDeviceCreate failed with status code 0x%x\n", status));
        return status;
    }

    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel);

    // Framework by default creates non-power managed queues for filter drivers.
    ioQueueConfig.EvtIoInternalDeviceControl = MouFilter_EvtIoInternalDeviceControl;

    status = WdfIoQueueCreate(hDevice, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE // pointer to default queue
    );

    if (!NT_SUCCESS(status)) {
        DebugPrint(("WdfIoQueueCreate failed 0x%x\n", status));
        return status;
    }

    return status;
}
  1. You never use “sc start” or “net start” to start a PnP driver. You have to be loaded when the whole device stack is being loaded. You don’t have to reboot; you can just disable and re-enable the device in Device Manager (if you have another mouse), or with “devcon”.
  2. Kernel_Security_Check_Failure is a container with a whole bunch of subtype codes. You might show us your dump analysis.
  3. You have little control over the order of loading if there are multiple filters.
  4. Did you actually, seriously, name your driver KMDF.SYS???

What are you hoping to do in your filter?

> @Tim_Roberts said: > * You never use “sc start” or “net start” to start a PnP driver. You have to be loaded when the whole device stack is being loaded. You don’t have to reboot; you can just disable and re-enable the device in Device Manager (if you have another mouse), or with “devcon”. > * Kernel_Security_Check_Failure is a container with a whole bunch of subtype codes. You might show us your dump analysis. > * You have little control over the order of loading if there are multiple filters. > * Did you actually, seriously, name your driver KMDF.SYS??? > > What are you hoping to do in your filter? Yes I know the name is terrible I’ll change it when I actually start making my project I just kept it like that while testing and I already verified the name is unique. My goal is to be able to manipulate and / or drop mouse input when needed. The order of the filter driver does not particularly matter in this case as long as it’s above mouclass in the upperFilter regEdit. Is there a way I can prepend my filter to the regEdit instead of appending it using the INF file? Oh thanks I never knew that I could disable my mouse and renable it via deceive manager in order to start my driver even though it’s currently stopped. Because yea starting it from cmd does not really do anything. Lastly. I’ll work on trying to get you the dump analysis but after each BSOD I have to reset my whole VM’s os. That being said I just set up a network debugger so I’ll try to figure out how to get that info to be communicated with my host computer and then I’ll get back to you on that.

You can manipulate and drop mouse input as a device upper filter or a class filter below mouclass. Why requirement makes you think you need to be above mouclass? There is no INF directive to prepend a value in a multi sz.

@Doron_Holan said:
You can manipulate and drop mouse input as a device upper filter or a class filter below mouclass. Why requirement makes you think you need to be above mouclass? There is no INF directive to prepend a value in a multi sz.

Oh is that the case? I have been told by multiple people who made mouse filter drivers that my UpperFilter must be added above mouclass for it to work. So you are saying the following should work (please disregard the poor name) and not require any additional changes to my code base compared to the its inverse?

mouclass
KMDF

once you hook the service callback you can modify reported data, inject your own, or prevent reported data from going up the stack to mouclass. I owned this input stack for close to a decade and wrote the moufiltr example, I know how this works :wink:

1 Like

@Doron_Holan said:
once you hook the service callback you can modify reported data, inject your own, or prevent reported data from going up the stack to mouclass. I owned this input stack for close to a decade and wrote the moufiltr example, I know how this works :wink:

Oh wow that is actually extremely impressive. If you have some time do you mind explaining how it works because I have not been able to recreate it. My code is basically identical to that moufilter code that you wrote and I ran a few trials one with KMDF at the top and one with it at the bottom. I then changed the code around a bit to try and recreate what you are talking about without any success. Also I did manage to fix my BSOD so thats how I am able to provide the information bellow.

Firstly, I installed the INF file and then started up the driver first by disabling my mouse then renabling it again and secondly by rebooting my machine just to check every edge case. Just to clarify this trial was with the original ordering of appending KMDF to mouclass. This resulted in the following output captured by my network debugger.

  Starting KMDF  
  Adding MouFilter Device 
  KMDF Dispatch Pass Through 
  Adding MouFilter Device 
  Adding MouFilter Device 

These statements corelate to the function they originated in. Next I inverted their order meaning KMDF came before mouclass and then rebooted my VM here is the what got printed to my debugger.

  Starting KMDF  
  Adding MouFilter Device 
  KMDF Connected Mouse 
  KMDF Dispatch Pass Through 
  KMDF Dispatch Pass Through 
  KMDF Dispatch Pass Through 
  Adding MouFilter Device 
  KMDF Connected Mouse 
  KMDF Dispatch Pass Through 
  Adding MouFilter Device 
  KMDF Connected Mouse 
  KMDF Dispatch Pass Through 
  KMDF Dispatch Pass Through 
  KMDF Dispatch Pass Through 
  KMDF Dispatch Pass Through 

I then repeated this process multiple times to make sure it was not a fluke. Based on my very limited knowledge I concluded that moufilter is obfuscating some of the information which is why I receive a lot less info with your appended approach. However, when I prepended it my filter was able to intercept calls before it reaches moufilter. I don’t understand exactly what is going on behind the scenes so maybe you could elaborate what moufilter does. I assume it is responsible handling my numerous amount of connected mice in order to make a clean exit point of filtered mouse data. Anyways of course you are right when you say you can manipulate mouse input both ways but the issue is I can’t seem to do it your way. If you look at the moufilter example you made you can see that the MouseHook is registered inside of the Connect Mouse case inside of the AddDevice function. This is a problem because that never gets called in your appended method (I am just talking about USB here and I removed all instances of I8042).

Anyways I tried to rectify this by moving the code that assigns MouFilter_ServiceCallback to outside of the switch statement because I know the MouFilter_EvtIoInternalDeviceControl function still gets called with your appended method. This did not create any errors but the MouFilter_ServiceCallback still never got called. So far the only way I have been able to get this function to be called is by using the prepended technique. Do you happen to know how I can rectify this?