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

Windows 驱动开发基础

Windows 驱动开发基础

什么是Windows 驱动

概念

Windows驱动程序(Device Driver)是一种特殊的系统软件,它运行在操作系统的内核模式下,充当硬件设备与操作系统之间的翻译官和协调者。从技术角度来看,驱动程序是一组遵循特定接口规范的函数集合,这些函数能够直接与硬件设备进行通信,同时向操作系统提供标准化的访问接口。

与普通应用程序不同,驱动程序拥有系统的最高权限。它可以访问硬件寄存器、操作物理内存、响应硬件中断,甚至可以修改操作系统内核的数据结构。这种特权级别使得驱动程序既强大又危险——一个设计良好的驱动可以大幅提升系统性能,而一个存在漏洞的驱动则可能导致系统崩溃或成为安全攻击的入口。

作用

驱动程序在现代计算机系统中扮演着不可替代的角色。从功能角度看,它实现了硬件抽象,使得应用程序开发者无需关心底层硬件的具体实现细节。从扩展性角度看,驱动程序机制使得操作系统能够支持无限多样的硬件设备,而无需修改操作系统本身。从安全角度看,驱动程序也被广泛应用于安全软件中,用于实现系统监控、进程保护、网络过滤等功能。

驱动开发环境

  1. 下载Visual Studio(SDK)
  2. WDK 引用网址:
  3. 下载 Windows 驱动程序工具包 (WDK)

注意: WDK和SDK版本需要配套, 先装Visual Studio(SDK),再装WDK。

核心概念

内核态与用户态

Windows 将系统划分为两个特权级别:内核态(Ring 0)用户态(Ring 3)

内核态是操作系统核心与驱动程序的运行环境,代码在此拥有最高权限,可以执行特权指令、访问任意内存并直接操作硬件。用户态则是普通应用程序的运行空间,权限受到严格限制,无法直接访问硬件或内核内存,越权操作会触发保护性异常。

这种隔离机制是系统稳定性的基础:即使应用程序崩溃,也不会影响内核。当用户程序需要执行特权操作时,必须通过系统调用切换到内核态,由内核代为完成。由于该过程涉及上下文保存和权限验证,频繁的切换会带来性能开销。

驱动程序运行在内核态,这既赋予它强大的能力,也意味着必须谨慎编写,否则可能直接影响系统安全与稳定。

设备对象(Device Object)

在 Windows 驱动编程中,设备对象(Device Object)是驱动程序向操作系统注册的内核数据结构,代表驱动能够提供服务的一个逻辑单元。

设备对象不一定对应真实的物理硬件。一个物理设备可能需要多个设备对象来表示不同功能,例如声卡可同时创建音频输出、音频输入和 MIDI 设备对象。设备对象也可以是完全虚拟的,如用于进程间通信的虚拟设备或用于系统监控的过滤设备。

驱动程序通过调用 IoCreateDevice 函数创建设备对象。此后,设备对象成为 I/O 管理器的管理目标,所有针对该设备的 I/O 请求都会以 IRP 的形式路由到驱动程序的处理函数。设备对象中包含设备类型、特性以及关联的驱动对象等关键信息,是驱动与操作系统交互的核心结构。

在 Windows 驱动开发中,符号链接是连接内核空间设备与用户空间程序的桥梁。

驱动程序创建的设备对象存在于内核命名空间中,路径通常类似 \Device\MyDriver,用户态程序无法直接访问。为此,需要创建一个符号链接,将设备对象映射到用户可见的路径,如 \\.\MyDriver\DosDevices\MyDriver

这样,用户态程序便可通过 CreateFile 等标准 API 打开设备,就像操作普通文件一样。符号链接本质上是一个指针,指向真实的设备对象,从而实现内核与用户之间的通信。

IRP(I/O Request Packet)

在 Windows 内核中,IRP(I/O Request Packet)是表示 I/O 操作的标准数据结构。

当用户程序发起 I/O 请求时,I/O 管理器会创建一个 IRP,其中包含操作类型(读、写、控制等)、缓冲区地址和相关参数。IRP 会沿驱动程序栈逐层传递,每个驱动都可以处理或转发,直到最底层驱动完成硬件操作。

IRP 采用异步处理模式,驱动可立即返回,稍后再完成操作并通知 I/O 管理器。这种机制使 Windows 能够高效处理并发 I/O 请求,是内核 I/O 架构的核心。

Hello World 驱动程序

用户层

#include <iostream>
#include <Windows.h>#define wszDeviceSymbolLinkName L"\\\\.\\Yan"#define IOCTL_DEFINE(FUNC_NUM, METHOD) CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800 + FUNC_NUM, METHOD, FILE_ANY_ACCESS)
#define IOCTL_FUNCTION_1 IOCTL_DEFINE(1, METHOD_IN_DIRECT)const int length = 0;
int main()
{HANDLE file = CreateFileW(wszDeviceSymbolLinkName, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (file == INVALID_HANDLE_VALUE){printf("CreateFileW failed %08X\n", GetLastError());return 1;}BOOL result = FALSE;wchar_t msg[] = L"Hello World";DWORD retutnLength = 0;printf("msg ptr: %p\n", msg);printf("length ptr: %p\n", &length);getchar();result = DeviceIoControl(file, IOCTL_FUNCTION_1, msg, sizeof(msg), (PVOID)&length, sizeof(length), &retutnLength, NULL);if (result && retutnLength == sizeof(length)){printf("msg length: %d\n", length);}else{printf("DeviceIoControl IOCTL_FUNCTION_1 failed %08X  retutnLength: %d\n", GetLastError(), retutnLength);}CloseHandle(file);system("pause");return 0;
}

驱动层

#include <ntifs.h>
#include <ntstrsafe.h>
#pragma warning(disable: 4133)#define TRACE(fmt, ...) DbgPrintEx(DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,fmt, __VA_ARGS__ )
#define wszDeviceName L"\\Device\\Yan"
#define wszDeviceSymbolLinkName L"\\DosDevices\\Yan"#define IOCTL_DEFINE(FUNC_NUM, METHOD) CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800 + FUNC_NUM, METHOD, FILE_ANY_ACCESS)
#define IOCTL_FUNCTION_1 IOCTL_DEFINE(1, METHOD_IN_DIRECT)NTSTATUS DeviceCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{TRACE("DeviceCreate\n");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS DevicecClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{TRACE("DevicecClose\n");Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS DevicecUnsupport(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{Irp->IoStatus.Information = 0;Irp->IoStatus.Status = STATUS_SUCCESS;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}NTSTATUS DevicecControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{TRACE("DevicecControl\n");ULONG ctl_code;ULONG ctl_method;ULONG inbuf_size = 0;ULONG outbuf_size = 0;PVOID inbuffer = NULL;PVOID outbuffer = NULL;NTSTATUS status = STATUS_SUCCESS;ULONG_PTR return_length = 0;PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);if (stack_location->MajorFunction != IRP_MJ_DEVICE_CONTROL){status = STATUS_INVALID_DEVICE_REQUEST;Irp->IoStatus.Status = status;IoCompleteRequest(Irp, IO_NO_INCREMENT);return status;}ctl_code = stack_location->Parameters.DeviceIoControl.IoControlCode;ctl_method = METHOD_FROM_CTL_CODE(ctl_code);if (ctl_method == METHOD_IN_DIRECT || ctl_method == METHOD_OUT_DIRECT){inbuffer = Irp->AssociatedIrp.SystemBuffer;inbuf_size = stack_location->Parameters.DeviceIoControl.InputBufferLength;outbuffer = Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : NULL;outbuf_size = stack_location->Parameters.DeviceIoControl.OutputBufferLength;}else{status = STATUS_INVALID_PARAMETER;Irp->IoStatus.Status = status;IoCompleteRequest(Irp, IO_NO_INCREMENT);return status;}//if (inbuffer == NULL || outbuffer == NULL)//{//	status = STATUS_INSUFFICIENT_RESOURCES;//	Irp->IoStatus.Status = status;//	IoCompleteRequest(Irp, IO_NO_INCREMENT);//	return status;//}switch (ctl_code){case IOCTL_FUNCTION_1:{DbgBreakPoint();UNICODE_STRING str;RtlInitUnicodeString(&str, (PWCH)inbuffer);TRACE("IOCTL_FUNCTION_1: %wZ\n", &str);*(int*)outbuffer = str.Length;return_length = sizeof(int);break;}default:{status = STATUS_NOT_IMPLEMENTED;return_length = 0;break;}}Irp->IoStatus.Status = status;Irp->IoStatus.Information = return_length;IoCompleteRequest(Irp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{UNICODE_STRING usDeivceSymbolLinkName = RTL_CONSTANT_STRING(wszDeviceSymbolLinkName);IoDeleteSymbolicLink(&usDeivceSymbolLinkName);PDEVICE_OBJECT device = DriverObject->DeviceObject;while (device){PDEVICE_OBJECT next = device->NextDevice;IoDeleteDevice(device);device = next;}TRACE("DriverUnload\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{NTSTATUS status = STATUS_SUCCESS;UNICODE_STRING usDeivceName = RTL_CONSTANT_STRING(wszDeviceName);UNICODE_STRING usDeivceSymbolLinkName = RTL_CONSTANT_STRING(wszDeviceSymbolLinkName);PDEVICE_OBJECT DeivceObject = NULL;pDriverObject->DriverUnload = DriverUnload;for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i){pDriverObject->MajorFunction[i] = DevicecUnsupport;}pDriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DevicecClose;pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DevicecControl;// 创建设备status = IoCreateDevice(pDriverObject,0,&usDeivceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&DeivceObject);if (!NT_SUCCESS(status)){TRACE("IoCreateDevice Failed status: %08X\n", status);goto LAB_END;}// 可以不清除该标志//DeivceObject->Flags |= DO_DEVICE_INITIALIZING;DeivceObject->Flags |= DO_DIRECT_IO;status = IoCreateSymbolicLink(&usDeivceSymbolLinkName, &usDeivceName);if (!NT_SUCCESS(status)){TRACE("IoCreateSymbolicLink Failed status: %08X\n", status);goto LAB_END;}LAB_END:if (!NT_SUCCESS(status)){DriverUnload(pDriverObject);}return status;
}

验证

  1. 使用第三方驱动加载工具加载驱动

  2. 执行用户程序, 输出如下:

    msg ptr: 000000C17358FAA8
    length ptr: 00007FF62951BF20msg length: 0
    请按任意键继续. . .
    
  3. 驱动程序输出,如下:

    Mon Sep 29 10:19:38.800 2025 (UTC + 8:00): DeviceCreate
    Mon Sep 29 10:19:39.618 2025 (UTC + 8:00): DevicecControl
    Mon Sep 29 10:19:51.615 2025 (UTC + 8:00): IOCTL_FUNCTION_1: Hello World
    Mon Sep 29 10:19:51.623 2025 (UTC + 8:00): DevicecClose

安全防护

VirboxProtector 在保护驱动程序时采用多层次防护策略。驱动程序运行在内核态,一旦被逆向分析成功,攻击者就能了解其安全机制的实现细节,进而绕过杀毒软件监控、突破反外挂检测、或破解授权验证。因此,必须对驱动程序的核心逻辑实施深度保护。

代码虚拟化将驱动中的关键函数转换为自定义虚拟机字节码,原始的x86/x64指令被替换成只有特定虚拟机才能解释的指令序列。逆向分析时看到的不是可读的汇编代码,而是陌生的指令体系。攻击者无法直接定位IRP处理函数、回调例程等关键代码,必须先完整分析虚拟机架构,工作量远超传统驱动逆向。

代码混淆通过控制流平坦化、虚假分支、指令替换等技术打乱驱动结构。简单的权限检查被展开成复杂跳转网络,清晰的函数调用变成间接跳转,原本几行的逻辑膨胀成上百行等效代码。即使能够阅读反汇编,也难以理解驱动的真实工作流程。

http://www.hskmm.com/?act=detail&tid=20747

相关文章:

  • 基于MATLAB实现基于距离的离群点检测算法
  • 国产DevOps工具链的突围之路:Gitee如何重塑企业研发效能
  • 阿里云抵御CC攻击利器边缘安全加速ESA
  • 生产者-消费者问题
  • Manim实现闪电特效
  • QAction的使用
  • Gitee:中国开发者生态的数字化转型加速器
  • 大模型提示词技巧Prompt Engineering,看这一篇就够了 - 知乎
  • sg.测试 PySimpleGUI 取值方法
  • Gitee DevOps:本土化基因驱动中国企业研发效能革命
  • 快速查看Navicat数据库连接密码实战
  • 老旧系统接入统一认证
  • 每周读书与学习-初识JMeter 元件(三)
  • Playwright MCP浏览器自动化全攻略
  • 【IEEE出版、连续3届稳定EI检索】第四届能源互联网及电力系统国际学术会议(ICEIPS 2025)
  • 大内容 Python动漫信息管理系统 Django+Echarts 类型饼图 折线图分析 后台管理 智能推荐(源码)✅
  • 划分子网与连通性
  • Python 之创建虚拟目录
  • 深入解析:从“硬件能力比拼”到“生活价值交付”,方太智慧厨房重构行业竞争内核
  • 题解:CF1548E Gregor and the Two Painters
  • Gitee DevOps:重塑中国软件开发效率的新范式
  • Gitee:中国开发者生态的崛起与数字化转型新动能
  • 悟空博弈框架深度研究:从技术架构到商业应用的全景分析——声明ai研究
  • 油猴脚本-自动刷新网页
  • PostgreSQL数据库查询表是否被锁,以及解锁表的办法
  • 用信号量机制实现互斥,同步,前驱
  • 详细介绍:HDFS和MapReduce——Hadoop的两大核心技
  • 【AI 哲学思考】从大模型演进到生命隐喻:个性、极限与先天后天之问
  • 【AI 哲学思考】记忆的形态:从人脑到 AI 的存储之问
  • ISP DMA TEST