当前位置: 首页 > news >正文

# Windows驱动程序开发入门:从原理到实践

Windows驱动程序开发入门:从原理到实践

前言

Windows驱动程序是操作系统与硬件设备之间的桥梁,它们在系统的最底层运行,拥有访问硬件资源的特权。本文将从基础概念开始,逐步深入Windows驱动开发的核心知识,并通过代码示例帮助读者理解驱动程序的工作原理。

一、什么是Windows驱动程序?

Windows驱动程序(Device Driver)是一种特殊的软件组件,运行在内核模式下,负责管理特定的硬件设备。它们充当应用程序和硬件之间的翻译器,将操作系统的标准化调用转换为特定硬件能够理解的指令。

驱动程序的特点

  • 内核模式执行:拥有系统的最高权限
  • 硬件抽象:为上层应用提供统一的接口
  • 中断处理:响应硬件产生的中断信号
  • 内存管理:直接操作物理内存和I/O端口

二、Windows驱动架构

Windows驱动程序遵循Windows驱动模型(WDM)或更现代的Windows驱动框架(WDF)

2.1 WDM架构层次

应用程序层↓
Win32 API↓
I/O管理器↓
功能驱动程序 (Function Driver)↓
总线驱动程序 (Bus Driver)↓
硬件设备

2.2 驱动程序类型

按功能分类:

  • 功能驱动程序(FDO):实现设备的主要功能
  • 物理设备对象驱动程序(PDO):表示总线上的设备
  • 筛选驱动程序(Filter Driver):在设备栈中添加功能

按框架分类:

  • WDM驱动:传统的Windows驱动模型
  • KMDF驱动:内核模式驱动框架
  • UMDF驱动:用户模式驱动框架

三、开发环境搭建

3.1 必需工具

  1. Visual Studio 2019/2022
  2. Windows SDK
  3. Windows Driver Kit (WDK)
  4. 虚拟机(用于测试)

3.2 环境配置

<!-- 项目配置示例 -->
<PropertyGroup><Platform>x64</Platform><Configuration>Debug</Configuration><TargetVersion>Windows10</TargetVersion><UseDebugLibraries>true</UseDebugLibraries><DriverType>KMDF</DriverType><DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>

四、第一个驱动程序:Hello World

让我们从一个最简单的KMDF驱动程序开始。

4.1 驱动程序入口点

#include <ntddk.h>
#include <wdf.h>// 驱动程序卸载回调函数
VOID HelloDriverUnload(IN PDRIVER_OBJECT DriverObject)
{UNREFERENCED_PARAMETER(DriverObject);KdPrint(("HelloDriver: Driver Unload called\n"));
}// 驱动程序入口点
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT  DriverObject,_In_ PUNICODE_STRING RegistryPath
)
{NTSTATUS status;WDF_DRIVER_CONFIG config;// 打印调试信息KdPrint(("HelloDriver: DriverEntry called\n"));// 初始化WDF驱动配置WDF_DRIVER_CONFIG_INIT(&config, NULL);// 设置卸载函数DriverObject->DriverUnload = HelloDriverUnload;// 创建WDF驱动对象status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&config,WDF_NO_HANDLE);if (!NT_SUCCESS(status)) {KdPrint(("HelloDriver: WdfDriverCreate failed: 0x%x\n", status));return status;}KdPrint(("HelloDriver: Driver loaded successfully\n"));return STATUS_SUCCESS;
}

4.2 设备对象创建

// 设备添加回调函数
NTSTATUS HelloEvtDeviceAdd(_In_ WDFDRIVER Driver,_Inout_ PWDFDEVICE_INIT DeviceInit
)
{NTSTATUS status;WDFDEVICE device;WDF_OBJECT_ATTRIBUTES deviceAttributes;UNREFERENCED_PARAMETER(Driver);KdPrint(("HelloDriver: HelloEvtDeviceAdd called\n"));// 初始化设备属性WDF_OBJECT_ATTRIBUTES_INIT(&deviceAttributes);// 创建设备对象status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);if (!NT_SUCCESS(status)) {KdPrint(("HelloDriver: WdfDeviceCreate failed: 0x%x\n", status));return status;}// 创建设备接口status = WdfDeviceCreateDeviceInterface(device,&GUID_DEVINTERFACE_HELLO,  // 自定义GUIDNULL);if (!NT_SUCCESS(status)) {KdPrint(("HelloDriver: WdfDeviceCreateDeviceInterface failed: 0x%x\n", status));return status;}return status;
}

五、I/O请求处理

驱动程序的核心功能是处理来自应用程序的I/O请求。

5.1 I/O队列配置

NTSTATUS HelloCreateIoQueue(WDFDEVICE Device)
{NTSTATUS status;WDF_IO_QUEUE_CONFIG queueConfig;WDFQUEUE queue;// 配置默认I/O队列WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,WdfIoQueueDispatchSequential);// 设置I/O回调函数queueConfig.EvtIoRead = HelloEvtIoRead;queueConfig.EvtIoWrite = HelloEvtIoWrite;queueConfig.EvtIoDeviceControl = HelloEvtIoDeviceControl;// 创建I/O队列status = WdfIoQueueCreate(Device,&queueConfig,WDF_NO_OBJECT_ATTRIBUTES,&queue);if (!NT_SUCCESS(status)) {KdPrint(("HelloDriver: WdfIoQueueCreate failed: 0x%x\n", status));}return status;
}

5.2 读取操作处理

VOID HelloEvtIoRead(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request,_In_ size_t Length
)
{NTSTATUS status;PVOID buffer;size_t bufferLength;UNREFERENCED_PARAMETER(Queue);KdPrint(("HelloDriver: Read request, Length = %zu\n", Length));// 获取请求缓冲区status = WdfRequestRetrieveOutputBuffer(Request,Length,&buffer,&bufferLength);if (!NT_SUCCESS(status)) {KdPrint(("HelloDriver: WdfRequestRetrieveOutputBuffer failed: 0x%x\n", status));WdfRequestComplete(Request, status);return;}// 向缓冲区写入数据const char* message = "Hello from Kernel Driver!";size_t messageLength = strlen(message);if (bufferLength >= messageLength) {RtlCopyMemory(buffer, message, messageLength);WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, messageLength);} else {WdfRequestComplete(Request, STATUS_BUFFER_TOO_SMALL);}
}

5.3 写入操作处理

VOID HelloEvtIoWrite(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request,_In_ size_t Length
)
{NTSTATUS status;PVOID buffer;size_t bufferLength;UNREFERENCED_PARAMETER(Queue);KdPrint(("HelloDriver: Write request, Length = %zu\n", Length));// 获取输入缓冲区status = WdfRequestRetrieveInputBuffer(Request,Length,&buffer,&bufferLength);if (!NT_SUCCESS(status)) {KdPrint(("HelloDriver: WdfRequestRetrieveInputBuffer failed: 0x%x\n", status));WdfRequestComplete(Request, status);return;}// 处理写入的数据KdPrint(("HelloDriver: Received %zu bytes of data\n", bufferLength));// 完成请求WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, bufferLength);
}

六、设备控制代码处理

DeviceIoControl是驱动程序与应用程序通信的重要方式。

#define IOCTL_HELLO_GET_VERSION \CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_READ_DATA)#define IOCTL_HELLO_SET_DATA \CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)VOID HelloEvtIoDeviceControl(_In_ WDFQUEUE Queue,_In_ WDFREQUEST Request,_In_ size_t OutputBufferLength,_In_ size_t InputBufferLength,_In_ ULONG IoControlCode
)
{NTSTATUS status = STATUS_SUCCESS;size_t bytesTransferred = 0;UNREFERENCED_PARAMETER(Queue);UNREFERENCED_PARAMETER(OutputBufferLength);UNREFERENCED_PARAMETER(InputBufferLength);switch (IoControlCode) {case IOCTL_HELLO_GET_VERSION:{PVOID outputBuffer;size_t outputBufferSize;ULONG version = 0x00010001; // 版本1.1status = WdfRequestRetrieveOutputBuffer(Request,sizeof(ULONG),&outputBuffer,&outputBufferSize);if (NT_SUCCESS(status)) {RtlCopyMemory(outputBuffer, &version, sizeof(ULONG));bytesTransferred = sizeof(ULONG);KdPrint(("HelloDriver: Get version: 0x%x\n", version));}}break;case IOCTL_HELLO_SET_DATA:{PVOID inputBuffer;size_t inputBufferSize;status = WdfRequestRetrieveInputBuffer(Request,1,&inputBuffer,&inputBufferSize);if (NT_SUCCESS(status)) {KdPrint(("HelloDriver: Set data, size = %zu\n", inputBufferSize));// 处理设置的数据bytesTransferred = inputBufferSize;}}break;default:status = STATUS_INVALID_DEVICE_REQUEST;KdPrint(("HelloDriver: Unknown IOCTL: 0x%x\n", IoControlCode));break;}WdfRequestCompleteWithInformation(Request, status, bytesTransferred);
}

七、用户态测试程序

为了测试我们的驱动程序,需要编写一个用户态应用程序。

#include <Windows.h>
#include <iostream>
#include <SetupAPI.h>#define IOCTL_HELLO_GET_VERSION \CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_READ_DATA)int main()
{HANDLE hDevice;DWORD bytesReturned;char buffer[256];ULONG version;// 打开设备hDevice = CreateFile(L"\\\\.\\HelloDevice",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hDevice == INVALID_HANDLE_VALUE) {std::cout << "Failed to open device: " << GetLastError() << std::endl;return -1;}std::cout << "Device opened successfully!" << std::endl;// 读取数据if (ReadFile(hDevice, buffer, sizeof(buffer), &bytesReturned, NULL)) {buffer[bytesReturned] = '\0';std::cout << "Read from driver: " << buffer << std::endl;}// 写入数据const char* writeData = "Hello from user application!";if (WriteFile(hDevice, writeData, strlen(writeData), &bytesReturned, NULL)) {std::cout << "Successfully wrote " << bytesReturned << " bytes" << std::endl;}// 发送控制代码if (DeviceIoControl(hDevice,IOCTL_HELLO_GET_VERSION,NULL, 0,&version, sizeof(version),&bytesReturned,NULL)) {std::cout << "Driver version: " << std::hex << version << std::endl;}CloseHandle(hDevice);return 0;
}

八、调试技巧

8.1 内核调试

使用WinDbg进行内核调试是驱动开发的重要技能:

// 设置调试输出级别
!ed nt!Kd_DEFAULT_Mask 0xFFFFFFFF// 查看驱动加载状态
lm m hello*// 设置断点
bp HelloEvtIoRead// 查看调用栈
kb

8.2 调试宏定义

#ifdef DBG
#define DebugPrint(x) DbgPrint x
#else
#define DebugPrint(x)
#endif// 使用示例
DebugPrint(("HelloDriver: Processing request, ID = %d\n", requestId));

九、最佳实践

9.1 错误处理

NTSTATUS ProcessRequest(WDFREQUEST Request)
{NTSTATUS status = STATUS_SUCCESS;__try {// 处理请求的代码status = DoActualWork();} __except (EXCEPTION_EXECUTE_HANDLER) {status = GetExceptionCode();KdPrint(("HelloDriver: Exception caught: 0x%x\n", status));}return status;
}

9.2 资源管理

NTSTATUS AllocateResources()
{PVOID buffer = NULL;buffer = ExAllocatePoolWithTag(NonPagedPool,BUFFER_SIZE,'lleH'  // 'Hell' tag);if (buffer == NULL) {return STATUS_INSUFFICIENT_RESOURCES;}// 使用buffer...// 清理资源if (buffer) {ExFreePoolWithTag(buffer, 'lleH');}return STATUS_SUCCESS;
}

十、总结

Windows驱动程序开发是一个复杂但充满挑战的领域。本文介绍了:

  1. 基础概念:驱动程序的作用和特点
  2. 架构理解:WDM和WDF框架
  3. 开发实践:从Hello World到完整的I/O处理
  4. 调试技巧:内核调试和错误处理
  5. 最佳实践:资源管理和异常处理

进阶学习方向

  • 高级I/O模型:异步I/O和DMA
  • 电源管理:设备电源状态管理
  • 即插即用:PnP和电源管理事件
  • 过滤驱动:上层和下层过滤驱动
  • UMDF开发:用户模式驱动框架

驱动开发需要深厚的系统知识和仔细的编程态度。建议在虚拟机环境中进行开发和测试,避免因驱动错误导致系统崩溃。

参考资源

  • Microsoft Windows Driver Kit Documentation
  • Windows Internals (Mark Russinovich)
  • OSR Online (驱动开发社区)
  • Windows Hardware Dev Center

希望这篇文章能为Windows驱动开发的初学者提供有价值的入门指导。驱动开发是一个需要不断实践和学习的过程,祝愿大家在这个充满挑战的领域中取得成功!


文章转载自:

http://bD7A617q.kqyfn.cn
http://OhKQw6vp.kqyfn.cn
http://EOwaqG5F.kqyfn.cn
http://aiwLizre.kqyfn.cn
http://Y2stWhHH.kqyfn.cn
http://S5B4H8zP.kqyfn.cn
http://8yonDod2.kqyfn.cn
http://I86KdTba.kqyfn.cn
http://FBmwEgjo.kqyfn.cn
http://XiQgszYo.kqyfn.cn
http://ClY4eIem.kqyfn.cn
http://Iwr0dFOQ.kqyfn.cn
http://pwaz7Z5O.kqyfn.cn
http://O4cpqmN7.kqyfn.cn
http://GqpDiKts.kqyfn.cn
http://JAmBggVC.kqyfn.cn
http://6rUYYu0D.kqyfn.cn
http://8tXsCq3j.kqyfn.cn
http://7W3PdvJY.kqyfn.cn
http://d41YBxXQ.kqyfn.cn
http://IXQdeuEM.kqyfn.cn
http://aTlxDMZJ.kqyfn.cn
http://NjpT1sqt.kqyfn.cn
http://30V7KhN6.kqyfn.cn
http://0IPPaiWs.kqyfn.cn
http://Ltz1BLOq.kqyfn.cn
http://ImNIoKRU.kqyfn.cn
http://NaqjfoKo.kqyfn.cn
http://adQvIvZA.kqyfn.cn
http://KshwG18e.kqyfn.cn
http://www.dtcms.com/a/380326.html

相关文章:

  • 在Webpack中集成Vite的开发服务器时,可能会遇到哪些兼容性问题?如何解决?
  • DCA1000 AWR1843 环境安装
  • 零公网IP 跨设备协同OctoPrint+cpolar3D打印远程管理新方法
  • 【Spring】原理解析:Spring Boot 自动配置的核心机制与实战剖析
  • Linux挂在目录空间问题--随手
  • Linux:线程控制详解
  • 花漾TK功能重要更新:界面重大更新、新增店铺数字面板(Dashboard)等(20250820)
  • 【计算机网络 | 第14篇】应用层协议
  • 三坐标测量仪:高精度测量内径检测手段及其实际运用
  • MQTT Dashboard
  • Spark广播变量HttpBroadcast和TorrentBroadcast对比
  • lvgl修改输入设备驱动使其支持鼠标右键、双击、滑轮...
  • 什么是 SaaS 安全?
  • LeetCode力扣-hot100系列(5)
  • 【Vue2手录12-单文件组件SFC】
  • MATLAB | 这是屎吗?抱歉打错了,这是什么?
  • leedcode 算法刷题第三十三天
  • 认知语义学对人工智能中自然语言处理的深层语义分析的影响与启示
  • 第四章:AI集成与机器学习
  • Redis面试相关
  • Python获取Windows已安装的所有应用程序列表
  • 计算机视觉(opencv)实战十六——图像像素直方图 与 掩膜
  • SSH登录管理
  • 利用OpenCV进行指纹识别的案例
  • 知识点 | “比选”和“询价”
  • HarmonyOS多媒体开发:音视频播放与录制全解析
  • Linux文件IO——系统IO
  • Class51 深度循环神经网络
  • URLSearchParams
  • 使用 C# 设置 Excel 单元格格式