news 2026/9/16 10:20:11

windows 驱动实例分析系列: HidHide 驱动分析 - drivers 篇(一)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
windows 驱动实例分析系列: HidHide 驱动分析 - drivers 篇(一)

HidHide 驱动分析 - drivers 篇(一):驱动框架与对象模型

一、目录概述

在 HidHide 的源码结构中,drivers/目录实际上与HidHide/目录等同,是内核驱动模块HidHide.sys的完整实现所在。该驱动基于Windows Driver Framework (WDF) Kernel-Mode Driver Framework (KMDF) 1.13+开发,充分利用了 WDF 提供的对象模型、即插即用(PnP)支持和电源管理框架,将传统 WDM 驱动的复杂性大幅降低。

本文档从驱动框架和对象模型的角度,深入剖析 HidHide 如何利用 WDF 机制实现一个稳定、高效的过滤驱动。

二、WDF 对象层次结构

WDF 驱动模型的核心是对象层次结构,每个对象都有明确的生命周期和父子关系。HidHide 使用的关键 WDF 对象包括:

WDF 对象类型数量说明
WDFDRIVER1驱动对象,代表整个驱动程序
WDFDEVICEN + 1每个 HID 设备对应一个过滤设备对象 + 一个控制设备对象
WDFQUEUE2控制设备的 I/O 队列 + 默认 I/O 队列
WDFREQUEST动态代表每个传入的 I/O 请求
WDFWAITLOCK1全局同步锁,保护共享数据结构
WDFCOLLECTION2白名单集合 + 黑名单集合(每个控制设备上下文)
WDFSTRINGN每个过滤设备存储其设备实例路径

2.1 WDFDRIVER 对象的创建与配置

DriverEntry中的WdfDriverCreate调用创建了驱动对象:

WDF_DRIVER_CONFIG_INIT(&wdfDriverConfig,NULL);wdfDriverConfig.EvtDriverDeviceAdd=HidHideDriverEvtDeviceAdd;wdfDriverConfig.EvtDriverUnload=HidHideDriverEvtUnload;ntstatus=WdfDriverCreate(pDriverObject,pRegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&wdfDriverConfig,&wdfDriver);

关键配置解析

  • EvtDriverDeviceAdd:PnP 管理器为每个新发现的设备调用此回调。HidHide 在此回调中创建过滤设备对象(Filter DO),附着在 HID 设备栈上。
  • EvtDriverUnload:驱动卸载时调用,负责释放全局资源。

值得注意的是,WDF_DRIVER_CONFIG_INIT的第二个参数为NULL,这意味着驱动不创建自己的EvtIoDeviceControl默认队列,而是由后续的设备对象独立处理 I/O。

2.2 WDFDEVICE 对象的双重角色

HidHide 创建了两种不同类型的 WDFDEVICE 对象:

控制设备(Control Device):通过WdfControlDeviceInitAllocate创建,不绑定到任何物理设备。它提供用户态通信通道(\\.\HidHide),用于接收 IOCTL 配置请求。该设备在驱动加载时创建,在驱动卸载前销毁。

过滤设备(Filter DO):通过标准的WdfDeviceCreate创建,附着在每个 HID 物理设备之上。每个过滤设备都与一个物理设备对象(PDO)相关联,形成设备栈中的一层。

两者的创建流程差异显著:

// 控制设备创建(使用 WdfControlDeviceInitAllocate)wdfDeviceInit=WdfControlDeviceInitAllocate(wdfDriver,&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX);WdfDeviceInitAssignName(wdfDeviceInit,&controlDeviceNtDeviceName);WdfDeviceCreate(&wdfDeviceInit,&wdfObjectAttributes,&wdfControlDevice);WdfControlFinishInitializing(*wdfControlDevice);// 必须显式完成初始化// 过滤设备创建(使用传入的 wdfDeviceInit)WdfFdoInitSetFilter(wdfDeviceInit);// 声明为过滤驱动WdfDeviceCreate(&wdfDeviceInit,&wdfObjectAttributes,&wdfDevice);// 不需要调用 WdfControlFinishInitializing

三、设备上下文的 WDF 对象扩展

WDF 提供了一种优雅的机制来为 WDF 对象附加自定义数据:对象上下文(Object Context)

3.1 设备上下文的声明与访问

HidHide 定义了两个上下文结构:

// 过滤设备上下文typedefstruct_DEVICE_CONTEXT{WDFSTRING deviceInstancePath;// 设备的唯一实例路径}DEVICE_CONTEXT,*PDEVICE_CONTEXT;// 控制设备上下文typedefstruct_CONTROL_DEVICE_CONTEXT{WDFCOLLECTION whitelistedFullImageNames;// 白名单集合WDFCOLLECTION blacklistedDeviceInstancePaths;// 黑名单集合BOOLEAN active;BOOLEAN whitelistedInverse;BOOLEAN shutdownPending;INT32 numberOfDevicesCreated;}CONTROL_DEVICE_CONTEXT,*PCONTROL_DEVICE_CONTEXT;

使用WDF_DECLARE_CONTEXT_TYPE_WITH_NAME宏生成类型安全的访问函数:

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT,DeviceGetContext)WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CONTROL_DEVICE_CONTEXT,ControlDeviceGetContext)

这允许通过DeviceGetContext(wdfDevice)直接获取上下文指针,而无需手动进行类型转换和内存偏移计算。

3.2 上下文的分配与初始化

上下文在WdfDeviceCreate时通过WDF_OBJECT_ATTRIBUTES指定:

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdfObjectAttributes,DEVICE_CONTEXT);wdfObjectAttributes.EvtCleanupCallback=OnDeviceContextCleanup;ntstatus=WdfDeviceCreate(&wdfDeviceInit,&wdfObjectAttributes,&wdfDevice);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE宏自动计算所需上下文大小,并在对象分配时预留内存。EvtCleanupCallback在设备对象销毁时被调用,用于释放上下文中的资源(如WDFSTRING对象)。

这种设计让对象生命周期的内存管理完全由 WDF 框架托管,避免了手动ExAllocatePoolExFreePool带来的复杂性和错误风险。

四、I/O 队列的配置与分发

WDF 通过I/O 队列(WDFQUEUE)管理传入的 I/O 请求。HidHide 为控制设备和过滤设备分别配置了独立的队列。

4.1 控制设备的 I/O 队列

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&wdfIoQueueConfig,WdfIoQueueDispatchParallel);wdfIoQueueConfig.EvtIoDeviceControl=HidHideControlDeviceEvtIoDeviceControl;WdfIoQueueCreate(*wdfControlDevice,&wdfIoQueueConfig,WDF_NO_OBJECT_ATTRIBUTES,&wdfQueue);
  • WdfIoQueueDispatchParallel:请求并行处理,不排队等待。控制设备的请求量很小(仅配置操作),并行处理可最大化响应速度。
  • EvtIoDeviceControl:仅处理IRP_MJ_DEVICE_CONTROL类型请求,其他类型请求(如读写)被自动拒绝。

4.2 过滤设备的默认队列

过滤设备未显式创建 I/O 队列,而是使用 WDF 框架为设备自动创建的默认队列。在OnDeviceFileCreate中,请求被处理的方式如下:

  1. 请求到达默认队列,框架调用EvtIoDefault回调(如果注册)或EvtIoRead/EvtIoWrite等特定回调。
  2. HidHide 使用WdfDeviceInitSetFileObjectConfig注册了EvtDeviceFileCreate回调,该回调在文件对象创建时触发,对应IRP_MJ_CREATE请求。
  3. 对于非 CREATE 请求,驱动不感兴趣,直接传递给下层驱动。
WDF_FILEOBJECT_CONFIG_INIT(&wdfFileObjectConfig,OnDeviceFileCreate,NULL,OnDeviceFileCleanup);WdfDeviceInitSetFileObjectConfig(wdfDeviceInit,&wdfFileObjectConfig,&wdfObjectAttributes);

这种选择性拦截策略大大简化了驱动逻辑,只关心设备打开请求,对数据传输请求完全不干预。

五、请求转发与完成例程

作为过滤驱动,HidHide 对大多数请求不做实质处理,而是转发给下层驱动。

5.1 转发的标准模式

WdfRequestFormatRequestUsingCurrentType(wdfRequest);WdfRequestSetCompletionRoutine(wdfRequest,OnDeviceFileCreateRequestCompletion,WDF_NO_CONTEXT);WDF_REQUEST_SEND_OPTIONS_INIT(&wdfRequestSendOptions,WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&wdfRequestSendOptions,WDF_REL_TIMEOUT_IN_SEC(60));if(FALSE==WdfRequestSend(wdfRequest,WdfDeviceGetIoTarget(wdfDevice),&wdfRequestSendOptions)){WdfRequestComplete(wdfRequest,WdfRequestGetStatus(wdfRequest));}

步骤说明

  1. WdfRequestFormatRequestUsingCurrentType:保持请求类型不变,准备转发。
  2. WdfRequestSetCompletionRoutine:注册完成例程,在下层驱动处理完毕后被调用。
  3. WDF_REQUEST_SEND_OPTIONS_INIT:指定同步发送(WDF_REQUEST_SEND_OPTION_SYNCHRONOUS),即等待下层驱动完成。
  4. WdfRequestSend:将请求发送到 I/O 目标(WdfDeviceGetIoTarget获取的下层驱动)。
  5. 若发送失败,立即完成请求(WdfRequestComplete)。

5.2 完成例程

VOIDOnDeviceFileCreateRequestCompletion(WDFREQUEST wdfRequest,WDFIOTARGET wdfIoTarget,PWDF_REQUEST_COMPLETION_PARAMS wdfRequestCompletionParams,WDFCONTEXT wdfContext){WdfRequestComplete(wdfRequest,wdfRequestCompletionParams->IoStatus.Status);}

完成例程仅将下层驱动的返回状态向上传递,不进行额外处理。

5.3 超时机制

WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&wdfRequestSendOptions,WDF_REL_TIMEOUT_IN_SEC(60));

60 秒超时防止下层驱动挂死导致系统卡顿。这是生产级驱动的重要保障措施。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 10:19:55

链表合并算法详解:迭代与递归双解法

1. 链表合并问题概述链表操作是算法面试中的常客,而合并两个有序链表更是基础中的基础。这道题看似简单,却蕴含着链表操作的核心思想。我在面试候选人时发现,能完整写出解法的人不少,但能清晰解释每一步操作意图的却不多。今天我们…

作者头像 李华
网站建设 2026/9/16 10:19:18

国产MQTT协议栈替换Mosquitto/EMQX:许可证、功能对比与迁移实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 10:19:15

基于ASP.NET的综合教务管理系统开发实战:从数据模型到部署

简介:一套基于ASP.NET的综合教务管理系统毕业设计项目,面向计算机相关专业毕业生和ASP.NET初学者,提供从系统设计到编码实现的完整参考方案。系统以学生信息、课程安排、教师档案、智能排课、成绩统计、在线选课等核心模块为主线,…

作者头像 李华
网站建设 2026/9/16 10:17:52

系统提示词泄露:大模型应用的隐性安全风险

1. 项目概述:这不是漏洞,是提示工程的“照妖镜”最近在多个技术社区和内部分享会上,我反复听到一个词——system_prompts_leaks。它不像传统安全漏洞那样带着CVE编号、高危评级和紧急补丁通知,但它正在 quietly 改变我们对大模型应…

作者头像 李华
网站建设 2026/9/16 10:17:29

大型企业Copilot落地:业务智能体的三层校验与四道防线

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 10:16:39

使用 DataHub Agent Context 构建 Google ADK 自主数据智能体

使用 DataHub Agent Context 构建 Google ADK 自主数据智能体 【免费下载链接】datahub The Context Platform for your Data and AI Stack 项目地址: https://gitcode.com/GitHub_Trending/da/datahub DataHub 的 Agent Context Kit 提供了将企业数据上下文&#xff08…

作者头像 李华