Lower filter driver doesn't start

Hi all

I’m developing an HID lower filter driver to intercept data from an usb touchscreen (because I need to change some data before reach the touch driver). I started by this example and changed some data in the .inf file. My problem is after installed the filter driver if I connect the usb touchscreen I can see my driver showed into device manager but with the orange sign informing that the driver can not be loaded cause an error (error 10). From debug print I can see the function inside the driver are called by the system but after a couple of call the system stop interacting and show the error. Also system touchscreen driver is not loaded. If I uninstall my driver all go back to work again. Follow my .inf file, someone can help me in know wat I’m doing wrong?
Thank you

[Version]
Signature="$WINDOWS NT$"
Class=HIDClass
ClassGuid={745a17a0-74d3-11d0-b6fe-00a0c90f57da}
Provider=%ManufacturerName%
CatalogFile=TouchFilter.cat
DriverVer=03/02/2022,1.0.0.0
PnpLockdown=1

[DestinationDirs]
DefaultDestDir = 12
TouchFilter_Device_CoInstaller_CopyFiles = 11

[SourceDisksNames]
1 = %DiskName%,,,""

[SourceDisksFiles]
TouchFilter.sys  = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames

;*****************************************
; Install Section
;*****************************************

[Manufacturer]
%ManufacturerName%=Standard,NT$ARCH$

[Standard.NT$ARCH$]
%TouchFilter.DeviceDesc%=TouchFilter_Device, USB\VID_03EB&PID_215D

[TouchFilter_Device.NT]
Include=INPUT.INF
Needs=HID_Inst.NT
CopyFiles=Drivers_Dir

[Drivers_Dir]
TouchFilter.sys

[TouchFilter_Device.NT.HW]
Include=INPUT.INF
Needs=HID_Inst.NT.HW
AddReg=TouchFilter_Device.NT.HW.AddReg

[TouchFilter_Device.NT.HW.AddReg]
HKR,,"LowerFilters",0x00010000,"TouchFilter"

;-------------- Service installation
[TouchFilter_Device.NT.Services]
AddService=TouchFilter,,TouchFilter_Service_Inst
Include=INPUT.INF
Needs=HID_Inst.NT.services

; -------------- TouchFilter driver install sections
[TouchFilter_Service_Inst]
DisplayName    = %TouchFilter.SVCDESC%
ServiceType    = 1               ; SERVICE_KERNEL_DRIVER
StartType      = 3               ; SERVICE_DEMAND_START
ErrorControl   = 1               ; SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\TouchFilter.sys

;
;--- TouchFilter_Device Coinstaller installation ------
;

[TouchFilter_Device.NT.CoInstallers]
AddReg=TouchFilter_Device_CoInstaller_AddReg
CopyFiles=TouchFilter_Device_CoInstaller_CopyFiles

[TouchFilter_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"

[TouchFilter_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll

[TouchFilter_Device.NT.Wdf]
KmdfService =  TouchFilter, TouchFilter_wdfsect
[TouchFilter_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$

[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="XXX"
DiskName = "TouchFilter Installation Disk"
TouchFilter.DeviceDesc = "TouchFilter Device"
TouchFilter.SVCDESC = "TouchFilter Service"

How did you install your filter ? If you used devcon, you need to use “devcon update”, not “devcon install”. Better yet, use pnputil. Devcon install will create a root enumerated device, even if you specified a USB HW ID and pnp start will be expected to fail since the hid stack expects a usb PDO.

What was the last function of yours that got called? Error 10 means someone failed IRP_MN_START_DEVICE.

If the sample was used as-is, it doesn’t set any callbacks that are invoked in the pnp start path, so the failure has to be coming from the FDO. Installing HIDUSB on a root enumerated device will behave exactly as described, failing start. If it is installed on a proper USB device, I would recommend removing the IOCTL request processing (FilterEvtIoDeviceControl) to see if the filter’s processing of the URB is contributing to the failed start.

Hi all

At first thank you for your replies.

@Doron_Holan said:
How did you install your filter ?

I install the filter using .inf file (click with right mouse button and select “install”)

@Doron_Holan said:
If the sample was used as-is, it doesn’t set any callbacks that are invoked in the pnp start path, so the failure has to be coming from the FDO. Installing HIDUSB on a root enumerated device will behave exactly as described, failing start. If it is installed on a proper USB device, I would recommend removing the IOCTL request processing (FilterEvtIoDeviceControl) to see if the filter’s processing of the URB is contributing to the failed start.

I already tried to remove the filter callback bot no luck, same error.

@Tim_Roberts said:
What was the last function of yours that got called?

Follow the code of my driver:

#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, FilterEvtDeviceAdd)
#endif

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    WDF_DRIVER_CONFIG   config;
    NTSTATUS            status;
    
    WDF_DRIVER_CONFIG_INIT(&config, FilterEvtDeviceAdd);

    status = WdfDriverCreate(DriverObject,
                            RegistryPath,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            &config,
                            WDF_NO_HANDLE
                            );
    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status));
    }
    
    return status;
}

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

    PAGED_CODE ();

    UNREFERENCED_PARAMETER(Driver);

    WdfFdoInitSetFilter(DeviceInit);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, FILTER_EXTENSION);

    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status));
        return status;
    }

    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel);
	
    //ioQueueConfig.EvtIoInternalDeviceControl = FilterEvtIoDeviceControl;

    status = WdfIoQueueCreate(device,
                            &ioQueueConfig,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            WDF_NO_HANDLE
                            );
    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status));
        return status;
    }

    return status;
}

VOID
FilterEvtIoDeviceControl(
    IN WDFQUEUE      Queue,
    IN WDFREQUEST    Request,
    IN size_t        OutputBufferLength,
    IN size_t        InputBufferLength,
    IN ULONG         IoControlCode
    )
{
    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(IoControlCode);
    WDFDEVICE                       device;

    device = WdfIoQueueGetDevice(Queue);
	
    FilterForwardRequestWithCompletionRoutine(Request, WdfDeviceGetIoTarget(device));

    return;
}

VOID
FilterForwardRequestWithCompletionRoutine(
    IN WDFREQUEST Request,
    IN WDFIOTARGET Target
    )
{
    BOOLEAN ret;
    NTSTATUS status;

    WdfRequestFormatRequestUsingCurrentType(Request);

    WdfRequestSetCompletionRoutine(Request,
                                FilterRequestCompletionRoutine,
                                WDF_NO_CONTEXT);

    ret = WdfRequestSend(Request,
                         Target,
                         WDF_NO_SEND_OPTIONS);

    if (ret == FALSE) {
        status = WdfRequestGetStatus (Request);
        KdPrint( ("WdfRequestSend failed: 0x%x\n", status));
        WdfRequestComplete(Request, status);
    }

    return;
}

VOID
FilterRequestCompletionRoutine(
    IN WDFREQUEST                  Request,
    IN WDFIOTARGET                 Target,
    PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
    IN WDFCONTEXT                  Context
   )
{
    UNREFERENCED_PARAMETER(Target);
    UNREFERENCED_PARAMETER(Context);
    
    WdfRequestComplete(Request, CompletionParams->IoStatus.Status);

    return;
}

Tried also to install the driver using the command:

pnputil /add-driver TouchFilter.inf /install

but same result…

But remember, if you already did a devcon install, then the damage is done – you have a fake device in Device Manager that you are driving. You should check the “hardware ID” and “device instance path” in the details to make sure it’s really a USB device. If it doesn’t start with "USB", then you should delete that device.

For testing, it’s not necessary to use an INF at all. Assuming your service already exists, bring up RegEdit, go to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\USB\VID_03EB&PID_215D, open the first subkey, add a new value called LowerFilters of type REG_MULTI_SZ and set it to “TouchFilter”. Restart the device or reboot, and there you go.

Hi @Tim_Roberts

In all my tests I always installed my driver using .inf file (right mouse click and install), never used the devcon command, just the pnputil to do a test. Thank you also for your info but can you explain me the exact steps to correctly install my filter driver? I mean, I compile the driver and I have as final result a .sys and and .inf file. How is the procedure to install this filter driver in a clean system from scratch?
Thank you for your help

@Tim_Roberts said:
For testing, it’s not necessary to use an INF at all. Assuming your service already exists, bring up RegEdit, go to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\USB\VID_03EB&PID_215D, open the first subkey, add a new value called LowerFilters of type REG_MULTI_SZ and set it to “TouchFilter”. Restart the device or reboot, and there you go.

I just verified installing by .inf file create the LowerFilter value in the path you described than seems the .inf file is correct but unfortunately the filter driver fail to load and I don’t know why…

Strip down the filter driver until the device starts. Remove the io queue and processing completely, etc.

@Doron_Holan said:
Strip down the filter driver until the device starts. Remove the io queue and processing completely, etc.

Already tried all. I tried also to leave only the DriverEntry code excluding the WdfDriverCreate call but the problem remain… It’s the reasons i don’t know how to do now… Error is something like incorrect data. It’s seems like the filter driver miss some callback not allowing to access to original USB device data from system side.

Just for future discussions, what you’re doing is not just “installing the filter”. Your INF completely replaces the original one used by the device. You now become “the” official driver package for that device. You happen to install the main driver (usbhid) plus a filter driver. That’s certainly a viable method. As I said, the procedure I use for testing takes the back-door approach. As long as you create a service entry for your filter, all you have to do is add that LowerFilters key and restart.

How are you handling the driver signing? Are you signing the filter? Do you have signatures disabled?

Perhaps you are not installing the fdo (hidusb) with the right config. Did you verify which INF section is used to install the fdo before you installed the filter? As tim said, you are replacing everything with the style of INF you are writing, including the FDO install. If you can constrain to win10, you can write an extension INF that will only add your filter and you don’t have to worry about the install of the fdo.