1. 引言
很难为术语 “驱动程序”提供一个精确的定义。 就最基本的意义而言,驱动程序是一个软件组件,可让操作系统和设备彼此通信。
例如,假设应用程序需要从设备中读取某些数据。 应用程序会调用由操作系统实现的函数,操作系统会调用由驱动程序实现的函数。 驱动程序(由设计和制造该设备的同一公司编写)了解如何与设备硬件通信以获取数据。 当驱动程序从设备获取数据后,它会将数据返回到操作系统,操作系统会将数据返回至应用程序。
驱动分为如下几种类型:
堆栈中直接与设备进行通信的驱动程序称为函数驱动程序。
执行辅助处理的驱动程序称为筛选器驱动程序。
-
软件驱动程序
未与设备关联的驱动程序称为“软件驱动程序” 。编写软件驱动程序的主要原因是要获取对仅在内核模式下可用的受保护数据的访问权限。
-
文件系统筛选器驱动程序
截获发往某个文件系统或其他文件系统筛选器驱动程序的请求。
通过在请求到达其预期目标之前截获它,微筛选器可扩展或替换请求的原始目标提供的功能。
-
文件系统驱动程序
对于软件驱动程序,可以使用两个选项:KMDF,以及传统的 Windows NT 驱动程序模型。
使用 KMDF 和传统 Windows NT 模型可以编写驱动程序,而无需考虑即插即用 (PnP) 和电源管理。 你可以改为专心于驱动程序的首要任务上。
我们的建议是使用 KMDF,尤其是当你已熟悉它时。如果你希望驱动程序与 PnP 和电源管理完全无关,请使用传统 Windows NT 模型。
如果需要编写考虑电源转换或 PnP 事件的软件,则不能使用传统 Windows NT 模型,而必须使用 KMDF。
注意:在极少数情况下,你需要编写注意到 PnP 或电源事件的软件驱动程序,并且驱动程序需要访问无法通过 KMDF 获取的数据,你必须使用 WDM。
2. 实现方式
WDM(Windows Driver Model)和WDF(Windows Driver Framework)都是微软为Windows操作系统提供的驱动程序开发框架。
2.1 WDM(Windows Driver Model)
-
Windows操作系统早期使用的驱动程序开发模型。
-
WDM提供了一种编程接口和规范,使开发人员能够编写与硬件设备交互的驱动程序。
-
WDM驱动程序以核心驱动程序、功能驱动程序和过滤器驱动程序为基础,涵盖了广泛的硬件设备类型。
-
开发者需要直接操作硬件资源和处理中断等底层细节。
2.2 WDF(Windows Driver Framework)
-
WDF是微软为简化驱动程序开发而引入的新框架。
-
WDF建立在WDM之上,提供了更高级别和抽象的编程模型。
-
WDF包括两个框架:WDF Kernel-Mode Driver Framework(KMDF)和WDF User-Mode Driver Framework(UMDF)。
-
WDF提供了更多的自动化和简化功能,减少了驱动程序开发的复杂性和错误,提高了开发效率和稳定性。
总结来说,WDM是早期的Windows驱动开发模型,需要开发人员直接操作底层硬件资源,而WDF是在WDM之上的高级和抽象的驱动程序开发框架,提供了更简化和自动化的开发方式。使用WDF可以减少驱动程序开发的复杂性并提高开发效率。
3. 示例
3.1 搭建开发环境
Visual Studio 2022 + Windows 11 版本 22H2 WDK
3.2 创建工程
在Visual Studio中选择Visual C++ -> Driver -> Empty WDM Driver,新建一个空的WDM驱动项目,如图:
3.3 实现
创建源文件Driver.cpp,同时删除用于驱动安装的inf文件。
#include <ntddk.h>
VOID
DRIVERUNLOAD(
_In_ struct _DRIVER_OBJECT* DriverObject
)
{
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint("HelloWorld UnLoad");
}
// MSDN中提示文件扩展名应该选择.c,而不是.cpp,否则会出现编译错误:无法解析的外部符号 DriverEntry,函数 GsDriverEntry 中引用了该符号。
// 因此,在这里通过extern "C"导出C风格的DriverEntry函数。
extern "C"
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
DbgPrint("HelloWorld Load");
DriverObject->DriverUnload = DRIVERUNLOAD;
return STATUS_SUCCESS;
}
3.4 编译
此项目需要缓解了 Spectre 漏洞的库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。了解详细信息: https://aka.ms/Ofhn4c
解决方案:
1)安装对应工具集版本的Spectre缓解库。
2)关闭幽灵漏洞缓解。
右键【工程属性】->【C/C++】->【代码生成】->【Spectre Mitigation】,选择【Disabled】。
3.5 安装
1)使用KmdManager进行安装
2)使用系统命令
管理员权限启动命令提示符:
# install
sc create helloworld binPath="C:\Users\Test\Desktop\HelloWorld.sys" type=filesys
# start
sc start helloworld
# stop
sc stop helloworld
# uninstall
sc delete helloworld
如果启动服务报错,请打开测试模式bcdedit -set testsigning on
,并重启。
[SC] StartService 失败 577:
Windows 无法验证此文件的数字签名。某软件或硬件最近有所更改,可能安装了签名错误或损毁的文件,或者安装的文件可能是来路不明的恶意软件。
可以使用dbgview查看内核消息:
3.6 调试
步骤:
1.设置主机通信端口
# 开启系统调试
C:\Windows\system32>bcdedit /debug on
操作成功完成。
# 设置主机通信端口,生成连接密钥
C:\Windows\system32>bcdedit /dbgsettings net hostip:192.168.91.1 port:60005
Key=2uiemihoo7ya2.u2uwa3l1v2rz.2ge9fbh1z60xk.2i0mkx6wn29uv
2.使用 设备管理器 确定要用于调试的适配器的 PCI 总线、设备和功能编号。 这些值显示在“常规”选项卡的“位置”下的设备管理器中。
C:\Windows\system32>bcdedit /set "{dbgsettings}" busparams 3.0.0
操作成功完成。
3.重启计算机
4.调试器连接
C:\Users\Netvine>"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -k net:port=60005,Key=2uiemihoo7ya2.u2uwa3l1v2rz.2ge9fbh1z60xk.2i0mkx6wn29uv
5.windbg调试
# 设置符号路径
.sympath D:\ISO\Release
# 设置函数断点
bp HelloWorld!DRIVERUNLOAD
bp HelloWorld!DriverEntry