首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

WDK 鍵盤過濾驅動程式範例程式碼深度解析

     編輯:關於C語言

WDK 鍵盤過濾驅動程式 (kbfiltr.c) 核心邏輯解析

本文整理自 Microsoft WDK 範例程式碼 kbfiltr.c,展示一個鍵盤類別過濾驅動的完整實作,涵蓋裝置掛載、IRP 分派、電源管理、PnP 處理、鍵盤連接鏈攔截與資料過濾等核心機制。

驅動程式進入點與分派表初始化

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
    ULONG i;
    UNREFERENCED_PARAMETER(RegistryPath);

    // 所有 MajorFunction 預設導向 PassThrough
    for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
        DriverObject->MajorFunction[i] = KbFilter_DispatchPassThrough;

    // 明確攔截需要處理的 IRP
    DriverObject->MajorFunction[IRP_MJ_CREATE] =
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbFilter_CreateClose;
    DriverObject->MajorFunction[IRP_MJ_PNP] = KbFilter_PnP;
    DriverObject->MajorFunction[IRP_MJ_POWER] = KbFilter_Power;
    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = KbFilter_InternIoCtl;

    DriverObject->DriverUnload = KbFilter_Unload;
    DriverObject->DriverExtension->AddDevice = KbFilter_AddDevice;
    return STATUS_SUCCESS;
}

關鍵點:先將所有分派函數設為通用的 KbFilter_DispatchPassThrough,再覆寫需特殊處理的 IRP 類型。AddDevice 回呼由 PnP 管理器在偵測到裝置時調用。

裝置新增與過濾器掛載

NTSTATUS KbFilter_AddDevice(PDRIVER_OBJECT Driver, PDEVICE_OBJECT PDO) {
    PDEVICE_OBJECT device;
    PDEVICE_EXTENSION devExt;
    NTSTATUS status = IoCreateDevice(Driver, sizeof(DEVICE_EXTENSION), NULL,
                                     FILE_DEVICE_KEYBOARD, 0, FALSE, &device);
    if (!NT_SUCCESS(status)) return status;

    RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION));
    devExt = (PDEVICE_EXTENSION)device->DeviceExtension;
    devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO); // 掛載至裝置堆疊
    if (!devExt->TopOfStack) { IoDeleteDevice(device); return STATUS_DEVICE_NOT_CONNECTED; }

    devExt->Self = device; devExt->PDO = PDO; devExt->DeviceState = PowerDeviceD0;
    devExt->SurpriseRemoved = FALSE; devExt->Removed = FALSE; devExt->Started = FALSE;
    device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
    device->Flags &= ~DO_DEVICE_INITIALIZING;
    return STATUS_SUCCESS;
}

IoAttachDeviceToDeviceStack 將過濾裝置物件掛載到鍵盤裝置堆疊頂端,TopOfStack 指向下一層驅動(通常是 i8042 埠驅動)。

內部裝置控制:攔截鍵盤連接與資料回報

KbFilter_InternIoCtl 處理兩個關鍵 IOCTL:

  • IOCTL_INTERNAL_KEYBOARD_CONNECT:類別驅動連接埠驅動時調用。驅動儲存原始 ClassService 回呼,並替換為自身的 KbFilter_ServiceCallback,從而攔截所有鍵盤輸入封包。
  • IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:針對 PS/2 鍵盤初始化與 ISR 的鉤子,允許修改初始化流程或攔截中斷資料(若僅需過濾封包可不處理此 IOCTL)。

服務回呼:過濾鍵盤輸入資料

VOID KbFilter_ServiceCallback(PDEVICE_OBJECT DeviceObject,
                              PKEYBOARD_INPUT_DATA InputDataStart,
                              PKEYBOARD_INPUT_DATA InputDataEnd,
                              PULONG InputDataConsumed) {
    PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
    // 呼叫原始 ClassService,可在此修改、刪除或插入封包
    (*(PSERVICE_CALLBACK_ROUTINE)devExt->UpperConnectData.ClassService)(
        devExt->UpperConnectData.ClassDeviceObject,
        InputDataStart, InputDataEnd, InputDataConsumed);
}

此處可實作按鍵重映射、巨集記錄、遊戲模式禁用特定鍵等功能。

PnP 與電源管理

  • IRP_MN_START_DEVICE:同步等待下層驅動完成啟動,設定 Started = TRUE。
  • IRP_MN_SURPRISE_REMOVAL / IRP_MN_REMOVE_DEVICE:標記移除狀態,傳遞 IRP 後分離並刪除裝置物件。
  • 電源 IRP:記錄裝置電源狀態(DevicePowerState),呼叫 PoCallDriver 向下傳遞(Vista 以上需用 PoCallDriver 處理電源 IRP)。

ISR 鉤子與初始化例程

若處理 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD,驅動可攔截鍵盤控制器初始化(KbFilter_InitializationRoutine)與中斷服務例程(KbFilter_IsrHook),實現更底層的硬體控制(如修改 LED、掃描碼轉換等)。

卸載處理

VOID KbFilter_Unload(PDRIVER_OBJECT Driver) {
    PAGED_CODE();
    UNREFERENCED_PARAMETER(Driver);
    ASSERT(NULL == Driver->DeviceObject); // 確認所有裝置已刪除
}

此範例展示了標準的鍵盤過濾驅動架構,是開發鍵盤相關過濾、記錄、重映射驅動的絕佳參考基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved