1、课程目标
- 理解Windows驱动程序架构
- 掌握WDK开发环境配置
- 编写第一个内核驱动程序
- 学会驱动的加载和卸载
2、名词解释
| 术语 |
解释 |
| WDK |
Windows Driver Kit,驱动开发包 |
| KMDF |
Kernel-Mode Driver Framework |
| WDM |
Windows Driver Model |
| DriverEntry |
驱动入口函数 |
| DriverUnload |
驱动卸载函数 |
| IRP |
I/O Request Packet |
3、使用工具
| 工具 |
用途 |
| Visual Studio |
IDE开发环境 |
| WDK |
驱动开发包 |
| WinDbg |
内核调试 |
| OSR Driver Loader |
驱动加载工具 |
| DebugView |
查看调试输出 |
4、技术原理
4.1、驱动程序架构
┌─────────────────────────────────────────────────────────────┐
│ Windows驱动架构 │
│ │
│ 用户模式 (Ring3) │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 应用程序 → CreateFile/DeviceIoControl/ReadFile │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ ─────────────────── 系统调用边界 ──────────────────── │
│ ↓ │
│ 内核模式 (Ring0) │
│ ┌────────────────────────────────────────────────────┐ │
│ │ I/O Manager → 创建IRP → 发送到驱动 │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Driver Object │ │
│ │ ├─ DriverEntry() - 初始化 │ │
│ │ ├─ DriverUnload() - 卸载清理 │ │
│ │ ├─ MajorFunction[] - IRP处理函数数组 │ │
│ │ └─ DeviceObject - 设备对象 │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
4.2、驱动类型
| 类型 |
说明 |
适用场景 |
| Legacy NT驱动 |
传统驱动模型 |
简单驱动、安全工具 |
| WDM驱动 |
支持PnP和电源管理 |
硬件驱动 |
| KMDF驱动 |
框架封装、简化开发 |
现代驱动开发 |
| 微型过滤器 |
文件系统过滤 |
文件监控/杀毒 |
5、代码实现
5.1、示例1:最简单的驱动程序
// FirstDriver.c - 第一个驱动程序
#include <ntddk.h>
// 驱动卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint("[FirstDriver] Driver unloaded!\n");
}
// 驱动入口函数
NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
) {
UNREFERENCED_PARAMETER(RegistryPath);
DbgPrint("[FirstDriver] Driver loaded!\n");
DbgPrint("[FirstDriver] DriverObject: 0x%p\n", DriverObject);
// 设置卸载函数
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
5.2、示例2:完整的驱动框架
// CompleteDriver.c - 完整驱动框架
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\MyDevice"
#define SYMBOLIC_NAME L"\\DosDevices\\MyDevice"
// 全局设备对象
PDEVICE_OBJECT g_DeviceObject = NULL;
// IRP处理 - 创建/关闭
NTSTATUS DispatchCreateClose(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
) {
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// IRP处理 - 读取
NTSTATUS DispatchRead(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
) {
UNREFERENCED_PARAMETER(DeviceObject);
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG readLength = irpStack->Parameters.Read.Length;
PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
DbgPrint("[Driver] Read request, length: %u\n", readLength);
// 返回一些数据
if (buffer && readLength >= 5) {
RtlCopyMemory(buffer, "Hello", 5);
Irp->IoStatus.Information = 5;
} else {
Irp->IoStatus.Information = 0;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// IRP处理 - 写入
NTSTATUS DispatchWrite(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
) {
UNREFERENCED_PARAMETER(DeviceObject);
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG writeLength = irpStack->Parameters.Write.Length;
PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
DbgPrint("[Driver] Write request, length: %u\n", writeLength);
if (buffer && writeLength > 0) {
DbgPrint("[Driver] Data: %.*s\n", writeLength, (char*)buffer);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = writeLength;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// IRP处理 - DeviceIoControl
NTSTATUS DispatchDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
) {
UNREFERENCED_PARAMETER(DeviceObject);
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
PVOID inputBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG bytesReturned = 0;
NTSTATUS status = STATUS_SUCCESS;
DbgPrint("[Driver] IOCTL: 0x%X\n", ioControlCode);
switch (ioControlCode) {
case 0x222000: // 自定义IOCTL码
if (inputBuffer && inputLength > 0) {
DbgPrint("[Driver] Input: %.*s\n", inputLength, (char*)inputBuffer);
}
if (outputLength >= 4) {
*(ULONG*)inputBuffer = 0x12345678;
bytesReturned = 4;
}
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = bytesReturned;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
// 驱动卸载
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {
UNICODE_STRING symbolicName;
RtlInitUnicodeString(&symbolicName, SYMBOLIC_NAME);
// 删除符号链接
IoDeleteSymbolicLink(&symbolicName);
// 删除设备对象
if (DriverObject->DeviceObject) {
IoDeleteDevice(DriverObject->DeviceObject);
}
DbgPrint("[Driver] Unloaded\n");
}
// 驱动入口
NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
) {
NTSTATUS status;
UNICODE_STRING deviceName;
UNICODE_STRING symbolicName;
UNREFERENCED_PARAMETER(RegistryPath);
DbgPrint("[Driver] DriverEntry\n");
// 创建设备名称
RtlInitUnicodeString(&deviceName, DEVICE_NAME);
RtlInitUnicodeString(&symbolicName, SYMBOLIC_NAME);
// 创建设备对象
status = IoCreateDevice(
DriverObject, // 驱动对象
0, // 设备扩展大小
&deviceName, // 设备名称
FILE_DEVICE_UNKNOWN, // 设备类型
0, // 设备特征
FALSE, // 非独占
&g_DeviceObject // 返回设备对象
);
if (!NT_SUCCESS(status)) {
DbgPrint("[Driver] IoCreateDevice failed: 0x%X\n", status);
return status;
}
// 创建符号链接(供用户模式访问)
status = IoCreateSymbolicLink(&symbolicName, &deviceName);
if (!NT_SUCCESS(status)) {
DbgPrint("[Driver] IoCreateSymbolicLink failed: 0x%X\n", status);
IoDeleteDevice(g_DeviceObject);
return status;
}
// 设置IRP处理函数
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
// 设置卸载函数
DriverObject->DriverUnload = DriverUnload;
// 设置IO方式为缓冲IO
g_DeviceObject->Flags |= DO_BUFFERED_IO;
g_DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DbgPrint("[Driver] Device created: %wZ\n", &deviceName);
return STATUS_SUCCESS;
}
5.3、示例3:用户模式测试程序
// TestDriver.c - 用户模式测试程序
#include <windows.h>
#include <stdio.h>
#define DEVICE_NAME "\\\\.\\MyDevice"
#define IOCTL_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
int main() {
HANDLE hDevice;
DWORD bytesReturned;
char readBuffer[256];
char writeData[] = "Hello from user mode!";
ULONG ioctlInput = 0x1234;
ULONG ioctlOutput = 0;
// 打开设备
hDevice = CreateFileA(
DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("Failed to open device: %d\n", GetLastError());
return 1;
}
printf("Device opened successfully!\n");
// 写入数据
if (WriteFile(hDevice, writeData, sizeof(writeData), &bytesReturned, NULL)) {
printf("Write successful, bytes: %d\n", bytesReturned);
}
// 读取数据
memset(readBuffer, 0, sizeof(readBuffer));
if (ReadFile(hDevice, readBuffer, sizeof(readBuffer), &bytesReturned, NULL)) {
printf("Read successful, bytes: %d, data: %s\n", bytesReturned, readBuffer);
}
// 发送IOCTL
if (DeviceIoControl(
hDevice,
IOCTL_TEST,
&ioctlInput, sizeof(ioctlInput),
&ioctlOutput, sizeof(ioctlOutput),
&bytesReturned,
NULL)) {
printf("IOCTL successful, output: 0x%X\n", ioctlOutput);
}
CloseHandle(hDevice);
return 0;
}
5.4、示例4:驱动加载服务
// LoadDriver.c - 驱动加载程序
#include <windows.h>
#include <stdio.h>
BOOL LoadDriver(const char* driverPath, const char* serviceName) {
SC_HANDLE hSCManager = NULL;
SC_HANDLE hService = NULL;
BOOL result = FALSE;
// 打开服务控制管理器
hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCManager) {
printf("OpenSCManager failed: %d\n", GetLastError());
return FALSE;
}
// 创建服务
hService = CreateServiceA(
hSCManager,
serviceName, // 服务名
serviceName, // 显示名
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER, // 内核驱动类型
SERVICE_DEMAND_START, // 手动启动
SERVICE_ERROR_IGNORE,
driverPath, // 驱动文件路径
NULL, NULL, NULL, NULL, NULL
);
if (!hService) {
if (GetLastError() == ERROR_SERVICE_EXISTS) {
// 服务已存在,尝试打开
hService = OpenServiceA(hSCManager, serviceName, SERVICE_ALL_ACCESS);
}
if (!hService) {
printf("CreateService failed: %d\n", GetLastError());
CloseServiceHandle(hSCManager);
return FALSE;
}
}
// 启动服务(加载驱动)
if (StartServiceA(hService, 0, NULL)) {
printf("Driver loaded successfully!\n");
result = TRUE;
} else {
DWORD err = GetLastError();
if (err == ERROR_SERVICE_ALREADY_RUNNING) {
printf("Driver already running.\n");
result = TRUE;
} else {
printf("StartService failed: %d\n", err);
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return result;
}
BOOL UnloadDriver(const char* serviceName) {
SC_HANDLE hSCManager = NULL;
SC_HANDLE hService = NULL;
SERVICE_STATUS ss;
BOOL result = FALSE;
hSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCManager) return FALSE;
hService = OpenServiceA(hSCManager, serviceName, SERVICE_ALL_ACCESS);
if (hService) {
// 停止服务(卸载驱动)
if (ControlService(hService, SERVICE_CONTROL_STOP, &ss)) {
printf("Driver unloaded.\n");
}
// 删除服务
if (DeleteService(hService)) {
printf("Service deleted.\n");
result = TRUE;
}
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
return result;
}
int main(int argc, char* argv[]) {
if (argc < 3) {
printf("Usage: %s <load|unload> <driver_path|service_name>\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "load") == 0) {
LoadDriver(argv[2], "MyDriver");
} else if (strcmp(argv[1], "unload") == 0) {
UnloadDriver(argv[2]);
}
return 0;
}
6、Visual Studio项目配置
1. 安装WDK(与VS版本匹配)
2. 新建项目 → 驱动 → Kernel Mode Driver (KMDF) 或 Empty WDM Driver
3. 项目属性配置:
- 配置类型:驱动程序
- 目标平台:Desktop
- 驱动模型设置:WDM 或 KMDF
- 关闭SDL检查(开发期间)
4. 签名配置(测试签名):
- 驱动签名模式:测试签名
- 或使用bcdedit /set testsigning on
5. 编译输出:
- Debug/x64/MyDriver.sys
- Debug/x64/MyDriver.pdb(调试符号)
7、课后作业
- 配置VS+WDK开发环境
- 编写一个可以读写的驱动程序
- 实现自定义IOCTL通信
- 使用WinDbg调试驱动程序
8、扩展阅读
- Windows Driver Development (Penny Orwick)
- WDK文档和示例
- OSR驱动开发资源