5.Windows驱动-创建驱动设备对象与三环通信

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

本次游戏没法给

内容参考于:微尘网络安全

上一个内容:4.Windows驱动-DbgPringtEx详解(驱动名、驱动卸载、驱动注册表)

首先创建一个MFC的项目,如下图右击选择新建项目

选择MFC应用,然后点击下一步

然后点击创建

根据下图选择完直接点击完成

然后添加一个按钮

然后双击下图红框的按钮

双击完写的代码

代码说明:

// ###########################################################################
// 宏定义:用户态访问内核驱动的符号链接路径(与内核驱动中的"三环符号"完全一致)
// 核心映射关系(必须重点理解):
//   内核态定义:L"\\??\\myhellWord" → 用户态实际访问路径:L"\\\\.\\myhellWord"
//   系统自动将用户态的 L"\\??\\" 映射为 L"\\\\.\\",因此两种写法等价
//   作用:用户态程序通过该路径找到内核中对应的设备对象(\\Device\\myhellWord)
// 注意:该宏必须与内核驱动中的"三环符号"完全一致,否则无法找到驱动设备
// ###########################################################################
#define 三环符号 L"\\??\\myhellWord"

// ###########################################################################
// MFC按钮点击事件处理函数:用户点击按钮时触发,核心功能是"用户态访问内核驱动"
// 作用:通过 CreateFile API 打开内核驱动创建的设备,建立用户态与内核态的通信通道
// 这是用户态程序与内核驱动交互的第一步(打开设备)
// ###########################################################################
void CMFCApplication1Dlg::OnBnClickedButton1()
{
    // #######################################################################
    // CreateFile:Windows核心API,用于打开/创建文件、设备、管道等对象
    // 此处用于打开内核驱动创建的设备对象(用户态与内核态通信的核心入口)
    // 参数详细说明(结合内核驱动场景):
    // #######################################################################
    HANDLE nDeviveHandle = CreateFile(
        三环符号,                          // 参数1:设备路径(用户态符号链接,与内核驱动一致)
                                           // 可取值:必须是内核驱动中 IoCreateSymbolicLink 创建的符号链接
                                           // 等价写法:L"\\\\.\\myhellWord"(用户态更直观的写法,与三环符号等价)
        GENERIC_READ | GENERIC_WRITE,       // 参数2:访问权限(请求读+写权限)
                                           // 可取值:
                                           //   GENERIC_READ → 读权限(对应内核 IRP_MJ_READ)
                                           //   GENERIC_WRITE → 写权限(对应内核 IRP_MJ_WRITE)
                                           //   0 → 仅打开设备,无读写权限
                                           // 注意:权限需与内核驱动的安全设置匹配,否则会返回权限不足(错误码5)
        FILE_SHARE_READ,                    // 参数3:共享模式(允许其他进程同时读该设备)
                                           // 可取值:
                                           //   FILE_SHARE_READ → 共享读
                                           //   FILE_SHARE_WRITE → 共享写
                                           //   FILE_SHARE_DELETE → 共享删除
                                           //   0 → 独占访问(不允许其他进程打开)
        NULL,                               // 参数4:安全属性(NULL=使用默认安全描述符)
                                           // 内核驱动创建设备时若设置了安全属性,需在此匹配
        OPEN_EXISTING,                      // 参数5:打开方式(必须设为"打开已存在的设备")
                                           // 可取值:仅 OPEN_EXISTING 有效(设备是内核驱动创建的,已存在)
                                           //   若设为 CREATE_NEW/CREATE_ALWAYS 会失败(错误码80:文件已存在)
        FILE_ATTRIBUTE_NORMAL,              // 参数6:文件/设备属性(普通属性,无特殊要求)
                                           // 可取值:FILE_ATTRIBUTE_NORMAL(默认)、FILE_FLAG_OVERLAPPED(异步I/O)等
        NULL                                // 参数7:模板文件句柄(设备访问无需模板,设为NULL)
    );

    // #######################################################################
    // 格式化输出结果:显示设备句柄和错误码(排查打开失败的关键)
    // 关键说明:
    //   - 若 nDeviveHandle == INVALID_HANDLE_VALUE(值为-1)→ 打开设备失败
    //   - GetLastError() → 获取失败原因(错误码对应具体问题,见下方注释)
    // #######################################################################
    char a[256];
    sprintf_s(a, "am:nDeviveHandle = %d GetLastError = %d", 
              nDeviveHandle,               // 设备句柄:非-1表示打开成功,后续可通过该句柄与驱动通信
              GetLastError());             // 错误码:打开失败时的具体原因

    // 弹窗显示结果(用户态直观查看是否打开成功)
    MessageBoxA(0, a, 0, 0);
}

// ###########################################################################
// 关键补充注释(用户态与内核驱动通信的核心注意事项)
// ###########################################################################
// 1. 常见错误码及排查方向(结合之前的内核驱动):
//    - 错误码 2(系统找不到指定文件):
//      → 内核驱动未加载(未执行 sc create + sc start)
//      → 内核驱动中 IoCreateSymbolicLink 调用失败(符号链接未创建)
//      → 宏定义"三环符号"与内核驱动中的"三环符号"不一致(路径写错)
//    - 错误码 5(拒绝访问):
//      → CreateFile 的访问权限(如GENERIC_WRITE)内核驱动不允许
//      → 内核驱动创建设备时设置了严格的安全属性(需在IoCreateDevice时指定FILE_ALL_ACCESS)
//      → 程序未以管理员身份运行(用户态访问内核设备需管理员权限)
//    - 错误码 1275(此驱动程序被阻止加载):
//      → 内核驱动未签名,测试模式未开启(需执行 bcdedit /set testsigning on + 重启)
//      → 安全引导未关闭(VMware需在虚拟机设置中禁用Secure Boot)
//    - 错误码 32(另一个程序正在使用此文件):
//      → 其他进程已独占打开该设备(CreateFile 共享模式设为0)
//
// 2. 成功条件(必须同时满足):
//    - 内核驱动已加载(sc start 启动成功)
//    - 内核驱动成功创建设备对象(IoCreateDevice 返回 STATUS_SUCCESS)
//    - 内核驱动成功创建符号链接(IoCreateSymbolicLink 返回 STATUS_SUCCESS)
//    - 测试模式已开启 + 驱动已自签名(或关闭驱动完整性校验)
//    - MFC程序以管理员身份运行(右键→以管理员身份启动)
//
// 3. 后续通信:
//    - 打开成功后,可通过 ReadFile(读驱动)、WriteFile(写驱动)、DeviceIoControl(控制驱动)与内核交互
//    - 需内核驱动实现对应的 IRP_MJ_READ、IRP_MJ_WRITE、IRP_MJ_DEVICE_CONTROL 处理函数
// ###########################################################################

驱动的代码

代码说明:

// 包含Windows内核驱动开发核心头文件
// 来源:Windows Driver Kit (WDK),提供内核API、数据结构(如NTSTATUS、PDRIVER_OBJECT)、宏定义
// 作用:驱动开发必备,所有内核函数/类型均依赖此头文件声明
#include "ntifs.h"

// ###########################################################################
// 驱动卸载函数:系统卸载驱动(sc stop 或关机)时自动调用
// 作用:释放驱动创建的资源(原代码未实现资源释放,需注意)
// 参数说明:
//   _In_ struct _DRIVER_OBJECT* DriverObject:驱动对象指针
//     - 来源:系统传入,指向当前被卸载的驱动对象
//     - 作用:通过该对象可访问驱动创建的设备对象、符号链接等资源
//   _In_ 标注:WDK定义的注解,表示该参数为"输入型"(仅读取,不修改)
// 注意:原代码未释放符号链接和设备对象,会导致资源泄漏(系统重启才能释放)
// ###########################################################################
VOID
MyUnload(
	_In_ struct _DRIVER_OBJECT* DriverObject
) {
	// DbgPrintEx:增强版内核调试打印(支持组件ID+调试级别过滤)
	// 参数1:DPFLTR_IHVDRIVER_ID → 第三方驱动组件ID(预定义,来源dpfilter.h)
	// 参数2:0 → 调试级别(0-31,数值越小优先级越高)
	// 参数3:格式化字符串,%wZ → 专门打印UNICODE_STRING类型(驱动名称)
	DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "DbgPrintEx hello am 卸载 = %wZ\n", DriverObject->DriverName);
}

// ###########################################################################
// IRP_MJ_CREATE 处理函数:用户态程序调用 CreateFile 打开驱动设备时触发
// 作用:处理设备的"打开"请求(如权限校验、初始化等)
// 参数说明:
//   _In_ struct _DEVICE_OBJECT* DeviceObject:被打开的设备对象指针
//     - 来源:系统传入,指向用户态要打开的内核设备对象
//   _Inout_ struct _IRP* Irp:I/O请求包(用户态请求的核心载体)
//     - 来源:系统创建并传入,包含请求类型、参数、结果存储位置
//     - _Inout_ 标注:输入输出型参数(读取请求信息,写入处理结果)
// 关键风险:原代码未设置 Irp->IoStatus 且未调用 IoCompleteRequest
//   → 系统会一直等待该请求完成,导致用户态程序卡死、甚至系统蓝屏!
// ###########################################################################
NTSTATUS
MyCreate(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) {
	// 打印设备创建(打开)日志,无其他处理逻辑
	DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "创建\n");
}

// ###########################################################################
// 宏定义:设备路径与用户态符号链接(内核态与用户态通信的关键标识)
// 1. 驱动符号(内核态设备路径):
//    - 格式规范:\\Device\\[设备名](固定格式,设备名自定义)
//    - 作用:内核态唯一标识设备,仅内核程序可见
//    - 可取值:自定义设备名(需唯一,避免与系统设备冲突,如L"\\Device\\MyDriver")
// 2. 三环符号(用户态符号链接):
//    - 格式规范:\\??\\[符号名](固定格式,符号名需与驱动设备名对应)
//    - 作用:映射内核设备路径到用户态,用户态通过 \\.\myhellWord 访问该设备
//    - 可取值:必须与驱动符号的设备名一致,仅前缀固定为\\??\\
// ###########################################################################
#define 驱动符号 L"\\Device\\myhellWord"  // 内核态设备路径(唯一标识内核设备)
#define 三环符号 L"\\??\\myhellWord"     // 用户态符号链接(用户态访问入口)

// ###########################################################################
// 驱动入口函数:系统加载驱动时优先调用(内核驱动的"main函数")
// 作用:初始化驱动核心配置(绑定卸载函数、IRP处理函数、创建设备/符号链接)
// 参数说明:
//   PDRIVER_OBJECT DriverObject:驱动对象指针
//     - 来源:系统创建并传入,代表当前加载的驱动本身
//     - 核心作用:存储驱动配置(卸载函数、IRP处理函数数组、设备对象链表等)
//   PUNICODE_STRING RegistryPath:驱动注册表路径
//     - 来源:系统传入,对应驱动服务在注册表中的键路径(如L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\[驱动名]")
//     - 作用:读取驱动的注册表配置(如启动参数、服务设置)
// 返回值:NTSTATUS → 驱动加载状态(STATUS_SUCCESS 表示加载成功)
// ###########################################################################
NTSTATUS DriverEntry(PDRIVER_OBJECT  DriverObject, PUNICODE_STRING RegistryPath) {

	// 打印驱动名称(DriverObject->DriverName 是系统分配的驱动名)和注册表路径
	DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "DbgPrintEx hello am 驱动名字 = %wZ\n", DriverObject->DriverName);
	KdPrintEx((DPFLTR_IHVDRIVER_ID, 0, "KdPrintEx hello am 注册表2222 = %wZ\n", RegistryPath));

	// 绑定驱动卸载函数:告知系统驱动卸载时要执行的函数(必须设置,否则无法正常卸载)
	DriverObject->DriverUnload = MyUnload;

	// 绑定 IRP_MJ_CREATE 处理函数:
	// MajorFunction 是IRP处理函数数组,下标为IRP请求类型,值为对应处理函数地址
	// 下标 IRP_MJ_CREATE → 对应"打开设备"请求,触发 MyCreate 函数
	// 常见IRP类型可取值(WDK预定义):
	//   IRP_MJ_CREATE → 打开设备(本示例用)
	//   IRP_MJ_CLOSE → 关闭设备
	//   IRP_MJ_READ → 读取设备数据
	//   IRP_MJ_WRITE → 写入设备数据
	//   IRP_MJ_DEVICE_CONTROL → 设备控制(用户态DeviceIoControl调用)
	DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreate;

	UNICODE_STRING uString;  // 存储内核态设备路径的UNICODE字符串(需初始化后使用)
	DEVICE_OBJECT uDevice_Object;  // 设备对象(原代码此处定义为局部变量,存在严重错误!)
	// 初始化UNICODE字符串:绑定到"驱动符号"(内核态设备路径)
	// RtlInitUnicodeString:WDK提供的内核API,用于初始化UNICODE_STRING类型
	RtlInitUnicodeString(&uString, 驱动符号);

	// 创建设备对象:内核态与用户态通信的核心载体
	// IoCreateDevice:WDK提供的内核API,用于创建内核设备对象
	// 参数说明:
	//   参数1:DriverObject → 设备所属的驱动对象
	//   参数2:sizeof(DriverObject->DriverExtension) → 设备扩展大小(原代码错误!应为自定义设备扩展大小,无需则设为0)
	//         正确用法:设备扩展是用户自定义的附加数据结构大小,与DriverExtension(驱动扩展)无关
	//   参数3:&uString → 设备路径(内核态可见)
	//   参数4:FILE_DEVICE_UNKNOWN → 设备类型(预定义可取值见下方)
	//   参数5:FILE_DEVICE_SECURE_OPEN → 设备特性标志(表示设备需要安全访问校验)
	//   参数6:FALSE → 是否独占设备(FALSE=允许多进程同时打开,TRUE=仅单进程打开)
	//   参数7:&uDevice_Object → 输出参数,接收创建的设备对象指针(原代码错误!应为PDEVICE_OBJECT类型指针)
	// 设备类型(参数4)预定义可取值(WDK提供):
	//   FILE_DEVICE_UNKNOWN → 未知设备(通用设备,本示例用)
	//   FILE_DEVICE_DISK → 磁盘设备
	//   FILE_DEVICE_KEYBOARD → 键盘设备
	//   FILE_DEVICE_MOUSE → 鼠标设备
	//   FILE_DEVICE_NETWORK → 网络设备
	NTSTATUS uStatus = IoCreateDevice(DriverObject, sizeof(DriverObject->DriverExtension),&uString, FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&uDevice_Object);

	if (uStatus == STATUS_SUCCESS) {  // 检查设备对象创建是否成功
		UNICODE_STRING uThreeString;  // 存储用户态符号链接路径的UNICODE字符串
		RtlInitUnicodeString(&uThreeString, 三环符号);  // 初始化符号链接路径

		// 创建用户态符号链接:映射内核设备路径到用户态,让用户态程序可访问
		// IoCreateSymbolicLink:WDK提供的内核API,用于创建符号链接
		// 参数1:&uThreeString → 用户态符号链接路径(三环符号)
		// 参数2:&uString → 对应的内核态设备路径(驱动符号)
		uStatus = IoCreateSymbolicLink(&uThreeString, &uString);
		if (uStatus == STATUS_SUCCESS) {  // 检查符号链接创建是否成功
			// DbgPrintEx 参数1设为77(自定义组件ID,未注册,调试器需特殊配置才能显示)
			DbgPrintEx(77, 0, "IoCreateSymbolicLink 成功\n");
		}
		else {
			DbgPrintEx(77, 0, "IoCreateSymbolicLink 失败\n");
		}
	}
	else {
		DbgPrintEx(77, 0, "IoCreateDevice 失败\n");
	}

	// 返回驱动加载状态:STATUS_SUCCESS 表示驱动加载成功(系统会认为驱动初始化完成)
	return STATUS_SUCCESS;
}

// ###########################################################################
// 原代码关键风险标注(仅提醒,不修改代码)
// ###########################################################################
// 1. 设备对象定义错误:DEVICE_OBJECT uDevice_Object 是局部变量,IoCreateDevice 要求传入 PDEVICE_OBJECT(指针)
//    → 会导致编译错误或运行时蓝屏(系统无法写入创建的设备对象)
// 2. IoCreateDevice 设备扩展大小错误:sizeof(DriverObject->DriverExtension) 是驱动扩展大小,而非设备扩展
//    → 设备扩展内存分配错误,可能导致后续访问非法内存
// 3. MyCreate 函数未处理IRP:未设置 Irp->IoStatus.Status 和 Irp->IoStatus.Information,未调用 IoCompleteRequest
//    → 用户态调用 CreateFile 后卡死,系统等待IRP完成超时蓝屏
// 4. 卸载函数未释放资源:未调用 IoDeleteSymbolicLink 和 IoDeleteDevice
//    → 驱动卸载后设备对象和符号链接残留,资源泄漏(需重启系统释放)
// 5. DbgPrintEx 组件ID为77(未注册):调试器默认无法过滤显示该组件日志,需手动注册或改用预定义ID
// ###########################################################################

效果图:未点击下图蓝框的按钮时打印的内容,也就是三环还未访问驱动

点击按钮之后,成功从三环访问到了零环,注意当前的代码没有清理逻辑,所以只能通过重启的方式清理


img

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值