键盘筛选器驱动程序卸载BSOD [英] Keyboard filter driver unload BSOD

查看:160
本文介绍了键盘筛选器驱动程序卸载BSOD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经开发了一种键盘过滤器驱动程序,可以将键盘按钮"1"(位于Q按钮上方)更改为"2".

I have developed a keyboard filter driver that changes the keyboard button '1' (above the Q button) to '2'.

此驱动程序工作正常.

但是,执行卸载后,按键盘按钮会导致BSOD.

However, after Unload is executed, pressing the keyboard button causes BSOD.

如果在不按键盘按钮的情况下加载和卸载驱动程序,它将正常卸载.

If the driver is loaded and unloaded without pressing the keyboard button, it will be unloaded normally.

当我使用Windbg进行检查时,即使卸载驱动程序的ReadCompletion()函数也会被调用.

When I check it with Windbg, my driver's ReadCompletion () function is called even after it is unloaded.

即使我已将IoDetachDevice()和IoDeleteDevice()称为我也不知道为什么会发生这种情况.

I do not know why this is happening even though I've called IoDetachDevice () and IoDeleteDevice ().

此外,在加载驱动程序之后,如果您一开始按键盘按钮'1',它就不会变为'2'.

In addition, after loading the driver, if you press the keyboard button '1' at the beginning, it does not change to '2'.

然后它变化得很好.

我不知道这和什么有关.

I do not know what this is related to.

希望您能找到解决该问题的方法.

I hope you will find a solution to this problem.

请回答我的问题.

下面是源代码.

#include <wdm.h>

typedef struct
{
    PDEVICE_OBJECT NextLayerDeviceObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

const WCHAR next_device_name[] = L"\\Device\\KeyboardClass0";

const char dbg_name[] = "[Test]";

NTSTATUS IrpSkip(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS ret = STATUS_SUCCESS;
    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);

    DbgPrint("%s IrpSkip() Start\n", dbg_name);
    DbgPrint("%s IrpSkip() - MajorFunction %d\n", dbg_name, Stack->MajorFunction);

    IoSkipCurrentIrpStackLocation(Irp);
    ret = IoCallDriver(((PDEVICE_EXTENSION)(DeviceObject->DeviceExtension))->NextLayerDeviceObject, Irp);
    DbgPrint("IoCallDriver return %x\n", ret);
    DbgPrint("%s IrpSkip() End\n", dbg_name);

    return ret;
}

NTSTATUS ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
    NTSTATUS ret = STATUS_SUCCESS;
    PIO_STACK_LOCATION Stack;
    unsigned char key[32];

    DbgPrint("%s ReadCompletion() Start\n", dbg_name);

    if (Irp->IoStatus.Status == STATUS_SUCCESS)
    {
        DbgPrint("%s ReadCompletion() - Success\n", dbg_name);
        RtlCopyMemory(key, Irp->AssociatedIrp.SystemBuffer, 32);
        DbgPrint("%s Data : %d %d %d %d %d %d %d %d\n", dbg_name, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
        if (key[2] == 2)
        {
            key[2] = 3;
            RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, key, 32);
            DbgPrint("%s Key '1' changed '2'\n", dbg_name);
        }
    }
    //else if (Irp->IoStatus.Status == STATUS_PENDING)
    else
    {
        DbgPrint("%s ReadCompletion() - Fail... %x\n", Irp->IoStatus.Status);
    }

    if (Irp->PendingReturned)
    {
        IoMarkIrpPending(Irp);
    }

    DbgPrint("%s ReadCompletion() End\n", dbg_name);

    return Irp->IoStatus.Status;
}

NTSTATUS Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS ret = STATUS_SUCCESS;
    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);

    DbgPrint("%s Read() Start\n", dbg_name);

    PDEVICE_EXTENSION device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    //IoCopyCurrentIrpStackLocationToNext(Irp);
    PIO_STACK_LOCATION current_irp = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION next_irp = IoGetNextIrpStackLocation(Irp);
    *next_irp = *current_irp;

    IoSetCompletionRoutine(Irp, ReadCompletion, DeviceObject, TRUE, TRUE, TRUE);

    ret=IoCallDriver(((PDEVICE_EXTENSION)device_extension)->NextLayerDeviceObject, Irp);

    DbgPrint("%s Read() End\n", dbg_name);

    return ret;
}

NTSTATUS Unload(IN PDRIVER_OBJECT DriverObject)
{
    NTSTATUS ret = STATUS_SUCCESS;

    IoDetachDevice(((PDEVICE_EXTENSION)(DriverObject->DeviceObject->DeviceExtension))->NextLayerDeviceObject);
    IoDeleteDevice(DriverObject->DeviceObject);

    DbgPrint("%s Unload()...\n", dbg_name);

    return ret;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS ret=STATUS_SUCCESS;
    UNICODE_STRING _next_device_name;

    DbgSetDebugFilterState(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, TRUE);

    DbgPrint("%s DriverEntry() Start\n", dbg_name);

    RtlInitUnicodeString(&_next_device_name, next_device_name);

    for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION ; i++)
    {
        DriverObject->MajorFunction[i] = IrpSkip;
    }
    DriverObject->DriverUnload = Unload;
    DriverObject->MajorFunction[IRP_MJ_READ] = Read;

    PDEVICE_OBJECT DeviceObject = 0;
    PDEVICE_EXTENSION DeviceExtension;

    ret = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0, FILE_DEVICE_KEYBOARD, 0, TRUE, &DeviceObject);
    if (ret == STATUS_SUCCESS)
    {
        DbgPrint("%s DriverEntry() - IoCreateDevice() Success\n", dbg_name);
    }
    else
    {
        DbgPrint("%s DriverEntry() - IoCreateDevice() Fail\n", dbg_name);
        return ret;
    }
    DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
    DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
    DeviceObject->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);

    ret = IoAttachDevice(DeviceObject, &_next_device_name, &DeviceExtension->NextLayerDeviceObject);
    if (ret == STATUS_SUCCESS)
    {
        DbgPrint("%s DriverEntry() - IoAttachDevice() Success\n", dbg_name);
    }
    else
    {
        DbgPrint("%s DriverEntry() - IoAttachDevice() Fail\n", dbg_name);
        IoDeleteDevice(DriverObject->DeviceObject);
        return ret;
    }

    DbgPrint("%s DriverEntry() End\n", dbg_name);

    return ret;
}

下面是Windbg调用堆栈.

Below is Windbg Call Stack.

0: kd> k
 # ChildEBP RetAddr  
00 82f33604 82eea083 nt!RtlpBreakWithStatusInstruction
01 82f33654 82eeab81 nt!KiBugCheckDebugBreak+0x1c
02 82f33a1c 82e4c5cb nt!KeBugCheck2+0x68b
03 82f33a1c 975e36e0 nt!KiTrap0E+0x2cf
WARNING: Frame IP not in any known module. Following frames may be wrong.
04 82f33aac 82e83933 <Unloaded_Test.sys>+0x16e0
05 82f33af0 8efed7a2 nt!IopfCompleteRequest+0x128
06 82f33b14 8eea7b74 kbdclass!KeyboardClassServiceCallback+0x2fa
07 82f33b78 82e831b5 i8042prt!I8042KeyboardIsrDpc+0x18c
08 82f33bd4 82e83018 nt!KiExecuteAllDpcs+0xf9
09 82f33c20 82e82e38 nt!KiRetireDpcList+0xd5
0a 82f33c24 00000000 nt!KiIdleLoop+0x38

CallBack函数似乎没有正确释放.

The CallBack function does not seem to be released properly.

我该如何解决这个问题?

How do I solve this problem?

推荐答案

如果将指针传递给自己的驱动程序主体(在您的情况下为ReadCompletion)-在使用此指针之前,必须卸载驱动程序(调用ReadCompletion退回了您的案件)

if you pass pointer to own driver body (ReadCompletion in your case) - driver must not be unloaded until this pointer is used (ReadCompletion called and returned your case)

根据 Harry Johnston 的通知,需要使用 IoSetCompletionRoutineEx -您可以查看此例程无所作为,以防止驱动程序卸载.它只是分配了小的内存块,将DeviceObjectContextCompletionRoutine保存在此处,并将IopUnloadSafeCompletion设置为完成,并将指向已分配的内存块的指针设置为上下文.

as notified Harry Johnston need use IoSetCompletionRoutineEx - but documentation for this is bad and not explain all details. absolute mandatory study windows src files (WRK-v1.2 for example) and binary windows code. if you look for implementation of IoSetCompletionRoutineEx - you can view that this routine nothing do for prevent you driver for unloading. it simply allocate small memory block, save here your DeviceObject, Context and CompletionRoutine and set IopUnloadSafeCompletion as completion and pointer to allocated memory block as context.

IopUnloadSafeCompletion在做什么?

NTSTATUS
IopUnloadSafeCompletion(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
{
    PIO_UNLOAD_SAFE_COMPLETION_CONTEXT Usc = Context;
    NTSTATUS Status;

    ObReferenceObject (Usc->DeviceObject);

    Status = Usc->CompletionRoutine (DeviceObject, Irp, Usc->Context);

    ObDereferenceObject (Usc->DeviceObject);
    ExFreePool (Usc);
    return Status;
}

但这是假设在呼叫IopUnloadSafeCompletionUsc->DeviceObject 是有效的.您可以删除/取消引用CompletionRoutine中的DeviceObject,执行一些导致驱动程序卸载的任务-并且不会崩溃,因为您的CompletionRoutine通过添加对设备的引用来保护.但是如果在设备已销毁并卸载驱动程序后调用IopUnloadSafeCompletion,则任何方法都会崩溃.

but this assume that Usc->DeviceObject IS VALID at calling IopUnloadSafeCompletion time. you can delete/de-reference DeviceObject inside CompletionRoutine , do some task which cause your driver unload - and will be no crash, because your CompletionRoutine protected by adding reference to your device. but if IopUnloadSafeCompletion will be called when your device already destroyed and driver unloaded - any way will be crash.

partial 解决方案将在调度例程中调用ObfReferenceObject(DeviceObject),在完成例程中调用ObfDereferenceObject(DeviceObject).这在实践中解决了问题.所以代码必须是下一个

partial solution will be call ObfReferenceObject(DeviceObject) in your dispatch routine and ObfDereferenceObject(DeviceObject) in completion routine. this on practice resolve problem. so code must be next

NTSTATUS OnComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID /*Context*/)
{
    ObfDereferenceObject(DeviceObject);// !!!

    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);

    if (Irp->PendingReturned)
    {
        IrpSp->Control |= SL_PENDING_RETURNED;
    }

    if (IrpSp->MajorFunction == IRP_MJ_READ &&
        Irp->IoStatus.Status == STATUS_SUCCESS && 
        (Irp->Flags & IRP_BUFFERED_IO))
    {
        if (ULONG n = (ULONG)Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA))
        {
            PKEYBOARD_INPUT_DATA pkid = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;

            do 
            {
                DbgPrint("Port%x> %x %x\n", pkid->UnitId, pkid->MakeCode, pkid->Flags);
            } while (pkid++, --n);
        }
    }

    return ContinueCompletion;
}

NTSTATUS KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    IoCopyCurrentIrpStackLocationToNext(Irp);

    if (0 > IoSetCompletionRoutineEx(DeviceObject, Irp, OnComplete, NULL, TRUE, TRUE, TRUE))
    {
        IoSkipCurrentIrpStackLocation(Irp);
    }
    else
    {
        ObfReferenceObject(DeviceObject);// !!!
    }

    return IofCallDriver(
        reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject, Irp);
}

OnComplete内部调用ObfDereferenceObject(DeviceObject);之前,请调用KbdDispatch中的ObfReferenceObject(DeviceObject);防止卸载驱动程序.

call ObfReferenceObject(DeviceObject); in KbdDispatch prevent unload your driver until ObfDereferenceObject(DeviceObject); called inside OnComplete.

在这种情况下,您可以要求 IoSetCompletionRoutineEx 保护您的完成例程.

you can ask for what in this case IoSetCompletionRoutineEx at all, if we yourself call ObfReferenceObject / ObfDereferenceObject ? because if DriverUnload already called - all your code hold only on single reference on DeviceObject - so when you call ObfDereferenceObject(DeviceObject); from OnComplete - your device will be deleted and driver unloaded inside ObfDereferenceObject and finally this routine returned to your unloaded code. so sense of IoSetCompletionRoutineEx is protect your completion routine.

,但需要了解,这毕竟不是100%正确的解决方案.对于DriverUnload中连接的设备不正确,请呼叫IoDetachDevice/IoDeleteDevice. (必须从IRP_MN_REMOVE_DEVICEFAST_IO_DETACH_DEVICE回调调用它)

but need understand that this is anyway not 100% correct solution. call IoDetachDevice/IoDeleteDevice for attached device not correct from DriverUnload. ( this must be called from IRP_MN_REMOVE_DEVICE or FAST_IO_DETACH_DEVICE callback)

假定下一种情况-有人呼叫NtReadFile与您的B设备相连的设备A. NtReadFile通过IoGetRelatedDeviceObject获取指向您的B设备的指针.在内部,此例行调用 IoGetAttachedDevice .阅读此内容:

assume next scenario - somebody call NtReadFile for device A to which your B device is attached. NtReadFile get pointer to your B device via IoGetRelatedDeviceObject. internally this routine call IoGetAttachedDevice. read this:

IoGetAttachedDevice 不会增加引用的数量 设备对象. (因此,没有匹配的 ObDereferenceObject 调用是 是必需的.) IoGetAttachedDevice 的调用者必须确保没有任何设备 将对象添加到堆栈或从堆栈中删除 IoGetAttachedDevice 正在执行.无法做到这一点的呼叫者必须使用 IoGetAttachedDeviceReference .

IoGetAttachedDevice does not increment the reference count on the device object. (Thus no matching call to ObDereferenceObject is required.) Callers of IoGetAttachedDevice must ensure that no device objects are added to or removed from the stack while IoGetAttachedDevice is executing. Callers that cannot do this must use IoGetAttachedDeviceReference instead.

假设NtReadFile使用指向您的B设备的指针时,另一个名为您的DriverUnload的线程删除了B设备并卸载了驱动程序.设备A上存在句柄/文件对象-可以保存它并防止卸载.但您连接的B设备一无所有.结果是,如果NtReadFile或使用设备的任何其他I/O子系统例程与DriverUnload并发执行,您在其中调用分离/删除设备-系统可能已经崩溃了NtReadFile代码.而你对此无能为力.调用IoDetachDevice之后只有一种方法,在调用IoDeleteDevice之前要等待一些(多少?!)时间.幸运的是,这种情况的可能性通常很低.

assume that while NtReadFile using pointer to your B device, another thread called your DriverUnload which delete B device and unload driver. handle/file object exist on device A - this hold it and prevent from unloading. but your attached B device not hold nothing. as result if NtReadFile or any another I/O subsystem routine which use your device execute in concurrent with DriverUnload where you call detach/delete device - system can crash already inside NtReadFile code. and you nothing can do with this. only one way after call IoDetachDevice some(how many ?!) time wait before call IoDeleteDevice. fortunately possibility of this case very low usual.

所以请尝试理解-系统可能已在NtReadFile中崩溃.即使您的调度调用-您的DeviceObject可以被删除/无效,或者在调度例程期间卸载了驱动程序.仅在调用ObfReferenceObject(DeviceObject)之后一切正常.以及所有这些问题,因为您尝试在DriverUnload(不是为此设计的Windows)中分离连接的设备.

so try understand - system can crash in NtReadFile already. even if your Dispatch called - your DeviceObject can be deleted/not valid already or driver unloaded during dispatch routine. only after you call ObfReferenceObject(DeviceObject) all become ok. and all this problem because you try detach attached device in DriverUnload (windows not designed for this).

还可以指出代码中的许多其他错误.说完成例程一定不能返回Irp->IoStatus.Status它必须返回或StopCompletion(即STATUS_MORE_PROCESSING_REQUIRED)或任何其他值-通常ContinueCompletion(即STATUS_CONTINUE_COMPLETION或0)也不需要硬编码"\\Device\\KeyboardClass0"但使用如果您不是wdm驱动程序,请使用GUID_CLASS_KEYBOARD.对于XP来说,也需要IRP_MJ_POWER的特殊处理程序(

also can noted many another errors in your code. say completion routine must not return Irp->IoStatus.Status it must return or StopCompletion (i.e STATUS_MORE_PROCESSING_REQUIRED ) or any another value - usual ContinueCompletion (i.e STATUS_CONTINUE_COMPLETION or 0) also need not hardcode "\\Device\\KeyboardClass0" but use IoRegisterPlugPlayNotification with GUID_CLASS_KEYBOARD if you not wdm driver. also for xp need special handler for IRP_MJ_POWER ( Passing Power IRPs ) but may be this is already not actual if xp support not actual.

代码示例如下所示:

struct DEVICE_EXTENSION
{
    PDEVICE_OBJECT _NextDeviceObject;
};

NTSTATUS KbdPower(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    PoStartNextPowerIrp(Irp);

    IoSkipCurrentIrpStackLocation(Irp);

    return PoCallDriver(
        reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject, Irp);
}

NTSTATUS OnComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID /*Context*/)
{
    ObfDereferenceObject(DeviceObject);

    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);

    if (Irp->PendingReturned)
    {
        IrpSp->Control |= SL_PENDING_RETURNED;
    }

    if (IrpSp->MajorFunction == IRP_MJ_READ &&
        Irp->IoStatus.Status == STATUS_SUCCESS && 
        (Irp->Flags & IRP_BUFFERED_IO))
    {
        if (ULONG n = (ULONG)Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA))
        {
            PKEYBOARD_INPUT_DATA pkid = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;

            do 
            {
                DbgPrint("Port%x> %x %x\n", pkid->UnitId, pkid->MakeCode, pkid->Flags);
            } while (pkid++, --n);
        }
    }

    return ContinueCompletion;
}

NTSTATUS KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    IoCopyCurrentIrpStackLocationToNext(Irp);

    if (0 > IoSetCompletionRoutineEx(DeviceObject, Irp, OnComplete, NULL, TRUE, TRUE, TRUE))
    {
        IoSkipCurrentIrpStackLocation(Irp);
    }
    else
    {
        ObfReferenceObject(DeviceObject);
    }

    return IofCallDriver(
        reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject, Irp);
}

NTSTATUS KbdNotifyCallback(PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification, PDRIVER_OBJECT DriverObject)
{
    if (::RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID))
    {
        DbgPrint("++%wZ\n", Notification->SymbolicLinkName);

        HANDLE hFile;
        OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, Notification->SymbolicLinkName, OBJ_CASE_INSENSITIVE };
        IO_STATUS_BLOCK iosb;

        if (0 <= IoCreateFile(&hFile, SYNCHRONIZE, &oa, &iosb, 0, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, 0, 0, 0, CreateFileTypeNone, 0, IO_ATTACH_DEVICE))
        {
            PFILE_OBJECT FileObject;

            NTSTATUS status = ObReferenceObjectByHandle(hFile, 0, 0, 0, (void**)&FileObject, 0);

            NtClose(hFile);

            if (0 <= status)
            {
                PDEVICE_OBJECT DeviceObject, TargetDevice = IoGetAttachedDeviceReference(FileObject->DeviceObject);

                ObfDereferenceObject(FileObject);

                if (0 <= IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0, 
                    TargetDevice->DeviceType, 
                    TargetDevice->Characteristics & (FILE_REMOVABLE_MEDIA|FILE_DEVICE_SECURE_OPEN), 
                    FALSE, &DeviceObject))
                {
                    DeviceObject->Flags |= TargetDevice->Flags & 
                        (DO_BUFFERED_IO|DO_DIRECT_IO|DO_SUPPORTS_TRANSACTIONS|DO_POWER_PAGABLE|DO_POWER_INRUSH);

                    DEVICE_EXTENSION* pExt = (DEVICE_EXTENSION*)DeviceObject->DeviceExtension;

                    if (0 > IoAttachDeviceToDeviceStackSafe(DeviceObject, TargetDevice, &pExt->_NextDeviceObject))
                    {
                        IoDeleteDevice(DeviceObject);
                    }
                    else
                    {
                        DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

                        DbgPrint("++DeviceObject<%p> %x\n", DeviceObject, DeviceObject->Flags);
                    }
                }

                ObfDereferenceObject(TargetDevice);
            }
        }
    }

    return STATUS_SUCCESS;
}

PVOID NotificationEntry;

void KbdUnload(PDRIVER_OBJECT DriverObject)
{
    DbgPrint("KbdUnload(%p)\n", DriverObject);

    if (NotificationEntry) IoUnregisterPlugPlayNotification(NotificationEntry);

    PDEVICE_OBJECT NextDevice = DriverObject->DeviceObject, DeviceObject;

    while (DeviceObject = NextDevice)
    {
        NextDevice = DeviceObject->NextDevice;
        DbgPrint("--DeviceObject<%p>\n", DeviceObject);
        IoDetachDevice(reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject);
        IoDeleteDevice(DeviceObject);
    }
}

NTSTATUS KbdInit(PDRIVER_OBJECT DriverObject, PUNICODE_STRING /*RegistryPath*/)
{       
    DbgPrint("KbdInit(%p)\n", DriverObject);

    DriverObject->DriverUnload = KbdUnload;

#ifdef _WIN64
    __stosq
#else
    __stosd
#endif
        ((PULONG_PTR)DriverObject->MajorFunction, (ULONG_PTR)KbdDispatch, RTL_NUMBER_OF(DriverObject->MajorFunction));

    ULONG MajorVersion;
    PsGetVersion(&MajorVersion, 0, 0, 0);
    if (MajorVersion < 6) DriverObject->MajorFunction[IRP_MJ_POWER] = KbdPower; 

    IoRegisterPlugPlayNotification(
        EventCategoryDeviceInterfaceChange,
        PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
        (void*)&GUID_CLASS_KEYBOARD, DriverObject,
        (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)KbdNotifyCallback,
        DriverObject, &NotificationEntry);

    return STATUS_SUCCESS;
}

这篇关于键盘筛选器驱动程序卸载BSOD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆