news 2026/5/15 16:11:18

ring0与ring3通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ring0与ring3通信

前置知识

IRP是什么

IRP的处理机制类似于windows窗口程序中的“消息处理”机制,驱动程序接收到不同类型的IRP后,会进入不同的派遣函数,在派遣函数中IRP得到处理。

派遣函数是什么

用户模式下所有对驱动程序的I/O请求,全部由操作系统转换为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”道不同的派遣函数中,这也是派遣函数名字的由来。

驱动程序并不是“被直接调用”的,而是由操作系统根据 IRP 的类型进行派遣。

每一种 IRP 都有一个“主功能码(Major Function)”,例如:

  • IRP_MJ_CREATE:打开设备(CreateFile)
  • IRP_MJ_CLOSE:关闭设备(CloseHandle)
  • IRP_MJ_DEVICE_CONTROL:设备控制(DeviceIoControl)

驱动通过注册 派遣函数,告诉系统:

“当收到某种类型的 IRP 时,请调用我这个函数来处理。”

用户模式发起操作(如 DeviceIoControl) 操作系统将其转换为 IRP 根据 IRP 类型,进入驱动中对应的派遣函数 驱动在派遣函数中完成处理并返回结果

什么是设备对象(DEVICE_OBJECT)?

设备对象是驱动在内核中创建的、用于接收 I/O 请求的内核对象。

在 Windows 中,驱动程序本身并不能直接接收 IRP,
真正接收 IRP 的,是驱动创建的 设备对象(DEVICE_OBJECT)。

在代码中,对应的就是:

IoCreateDevice(...)

创建成功后,系统会为该驱动生成一个设备对象,
之后所有发往该设备的 IRP,都会被派遣到这个设备对象所属的驱动中。

对于我们这种 0 环 / 3 环通信驱动来说:

这个设备并不对应真实硬件, 而是一个“纯软件设备”, 用来承载用户态与驱动之间的通信。

设备名(\Device\xxx)是做什么的?

设备对象在内核中必须有一个唯一的名字,
这个名字存在于 内核对象命名空间 中,通常以 \Device\ 开头,例如:

\\Device\\MyDevice

这个名字的特点是:

  • 只在内核态可见

  • Ring3 程序不能直接使用这个名字打开设备

  • 它的主要作用是:在内核中唯一标识一个设备对象

为什么还需要符号链接?

既然 Ring3 不能直接访问 \Device\MyDevice,
那用户程序如何找到这个设备呢?

答案是:通过符号链接(Symbolic Link)。

驱动可以创建一个符号链接,例如:

\\??\\MyDevice->\\Device\\\MyDevice

代码

ring3

#include<stdio.h>#include<windows.h>#include<winioctl.h>#defineOPER1CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)#defineOPER2CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)/***************************************************************************///打开驱动服务句柄//打开三环链接名:\\\\.\\Device/***************************************************************************/intmain(void){DWORD dwInBuffer=0x123456789;TCHAR szOutBuffer[10]={0};DWORD dw;//1. 通过符号链接,打开设备HANDLE g_hDevice=CreateFileW(L"\\\\.\\MyDevice",// 设备名,例如 "\\\\.\\MyDevice"GENERIC_READ|GENERIC_WRITE,// 读写权限0,// 共享模式:0 表示不共享0,// 安全属性:NULL = 默认OPEN_EXISTING,// 只能打开已存在的设备FILE_ATTRIBUTE_NORMAL,// 普通文件属性(对设备来说一般无所谓)0// 模板句柄:不用,传0);//2. 测试通信DeviceIoControl(g_hDevice,//设备句柄OPER2,//操作码&dwInBuffer,//输入缓冲区地址sizeof(dwInBuffer),//输入缓冲区长度szOutBuffer,//输出缓冲区地址sizeof(szOutBuffer),//输出缓冲区长度&dw,//返回长度NULL);//指向OVERLAPPED 此处为NULLprintf("%x",*(int*)szOutBuffer);//3. 关闭设备CloseHandle(g_hDevice);system("pause");return0;}

ring0

#include<ntifs.h>#defineOPER1CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)#defineOPER2CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)#defineDEVICE_NAMEL"\\Device\\MyDevice"// Ring3用CreateFile打开设备时,用"\\\\.\\MyDevice"#defineSYMBOLICLINK_NAMEL"\\??\\MyDevice"// IRP_MJ_CREATE处理函数//参数1:一个驱动可以有多个 DEVICE_OBJECT,所以同一个分发函数可以用 pDevObj 区分“这次是哪个设备收到的 IRP”。//参数2:这次 I/O 请求对应的 IRP 结构体,里面记录了://1.这是一个 Create 请求(MajorFunction = IRP_MJ_CREATE)//2.打开方式、共享模式等参数//3.一个 IO_STATUS_BLOCK:pIrp->IoStatusNTSTATUSIrpCreateProc(PDEVICE_OBJECT pDevObj,PIRP pIrp){DbgPrint("(mydriver)DispatchCreate ... \n");//每个 IRP 里都有一个 IO_STATUS_BLOCK IoStatus//IoStatus.Status:本次 I/O 请求的 NTSTATUS 返回码//IoStatus.Information:与这次请求相关的“额外信息”(比如读/写了多少字节)//你必须显式把 IoStatus.Status 设置成成功或失败,//否则就是“垃圾值”,I/O 管理器按照那个垃圾值判断,于是 Ring3 的 CreateFile 返回失败。pIrp->IoStatus.Status=STATUS_SUCCESS;//这个字段的含义取决于 是什么 IRP://对 IRP_MJ_READ:常常表示“实际读取了多少字节”//对 IRP_MJ_WRITE:常常表示“实际写入了多少字节”//对 IRP_MJ_DEVICE_CONTROL:表示“返回给用户缓冲区的数据长度”//对 IRP_MJ_CREATE / IRP_MJ_CLOSE:一般没有额外数据需要告诉 Ring3,所以设为 0pIrp->IoStatus.Information=0;//告诉 I/O 管理器:“这个 IRP 我处理完了,可以结束这次 I / O 请求了。”//如果不调用IoCompleteRequest,Ring3 那边的 CreateFile 会一直等(同步调用),永远等不到结果,表现就是程序卡死/挂住。IoCompleteRequest(pIrp,IO_NO_INCREMENT);//return STATUS_SUCCESS; 和 IoStatus.Status 的关系//这里返回值也是 NTSTATUS,I / O 管理器确实也会用这个值,但真正传回 Ring3 的是 pIrp->IoStatus.Status。returnSTATUS_SUCCESS;}// IRP_MJ_CLOSE处理函数NTSTATUSIrpCloseProc(PDEVICE_OBJECT pDevObj,PIRP pIrp){DbgPrint("(mydriver)DispatchClose ... \n");pIrp->IoStatus.Status=STATUS_SUCCESS;pIrp->IoStatus.Information=0;IoCompleteRequest(pIrp,IO_NO_INCREMENT);returnSTATUS_SUCCESS;}// IRP_MJ_DEVICE_CONTROL处理函数 用来处理与Ring3交互NTSTATUSIrpDeviceControlProc(PDEVICE_OBJECT pDevObj,PIRP pIrp){NTSTATUS status=STATUS_INVALID_DEVICE_REQUEST;ULONG uRead;//当设置交互模式为pDeviceObj->Flags |= DO_BUFFERED_IO;那 I/O 管理器会://1.在内核态分配一块缓冲区:SystemBuffer//2.把 Ring3 的输入缓冲区(InBuff)拷贝过来//3.把 SystemBuffer 指针放到 pIrp->AssociatedIrp.SystemBuffer//4.完成 IRP 时,再把 SystemBuffer 前 IoStatus.Information 个字节拷回 Ring3 的输出缓冲区(OutBuff)//设置临时变量的值PIO_STACK_LOCATION pIrpStack=IoGetCurrentIrpStackLocation(pIrp);// 获取控制码ULONG uIoControlCode=pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 获取缓冲区地址(输入和输出的缓冲区都是一个)PVOID pIoBuffer=pIrp->AssociatedIrp.SystemBuffer;// Ring3 发送数据的长度:用户写进来的数据长度(你最多只能读这么多字节)。ULONG uInLength=pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// Ring0 发送数据的长度:用户预留的输出缓冲区最大长度(你最多填这么多字节)。ULONG uOutLength=pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;switch(uIoControlCode){caseOPER1:{DbgPrint("(mydriver)IrpDeviceControlProc -> OPER1 ... \n");pIrp->IoStatus.Information=0;status=STATUS_SUCCESS;break;}caseOPER2:{DbgPrint("(mydriver)IrpDeviceControlProc -> OPER2 接收字节数:%d \n",uInLength);DbgPrint("(mydriver)IrpDeviceControlProc -> OPER2 输出字节数:%d \n",uOutLength);// Read From Buffermemcpy(&uRead,pIoBuffer,4);DbgPrint("(mydriver)IrpDeviceControlProc -> OPER2 ... %x \n",uRead);// Write To BufferuRead++;memcpy(pIoBuffer,&uRead,4);// Set StatuspIrp->IoStatus.Information=4;status=STATUS_SUCCESS;break;}}// 设置返回状态pIrp->IoStatus.Status=status;IoCompleteRequest(pIrp,IO_NO_INCREMENT);returnstatus;}VOIDDriverUnload(PDRIVER_OBJECT pDriver){UNICODE_STRING SymbolicLinkName={0};DbgPrint("(mydriver)驱动程序停止运行了 . \r\n");// 删除符号链接 删除设备RtlInitUnicodeString(&SymbolicLinkName,SYMBOLICLINK_NAME);IoDeleteSymbolicLink(&SymbolicLinkName);IoDeleteDevice(pDriver->DeviceObject);}NTSTATUSDriverEntry(PDRIVER_OBJECT pDriver,PUNICODE_STRING pReg){DbgPrint("(mydriver)驱动程序开始运行了 . \r\n");//初始化ring0设备名称UNICODE_STRING Devicename;RtlInitUnicodeString(&Devicename,DEVICE_NAME);// 创建设备PDEVICE_OBJECT pDeviceObj=NULL;NTSTATUS status=IoCreateDevice(pDriver,//驱动对象0,//设备扩展大小:为每个设备对象 额外分配的扩展空间大小&Devicename,//设备名称FILE_DEVICE_UNKNOWN,//设备类型FILE_DEVICE_SECURE_OPEN,//设备特性FALSE,//是否“独占设备”:TRUE:同一时间只能有 一个 句柄打开这个设备。第二个进程再 CreateFile 就会失败。//FALSE:多个进程 / 线程可以同时打开。&pDeviceObj);//输出:系统创建好的 PDEVICE_OBJECT 指针,通过它你以后能访问到设备扩展、标志位等等。if(status!=STATUS_SUCCESS){DbgPrint("(mydriver)创建设备失败! \r\n");returnstatus;}//设置交互数据的方式pDeviceObj->Flags|=DO_BUFFERED_IO;// 创建符号链接名称(给ring3用)UNICODE_STRING SymbolicLinkName;RtlInitUnicodeString(&SymbolicLinkName,SYMBOLICLINK_NAME);// 创建符号链接status=IoCreateSymbolicLink(&SymbolicLinkName,&Devicename);if(status!=STATUS_SUCCESS){DbgPrint("(mydriver)创建符号链接失败! \r\n");IoDeleteDevice(pDeviceObj);returnstatus;}// 设置分发函数和卸载函数pDriver->MajorFunction[IRP_MJ_CREATE]=IrpCreateProc;pDriver->MajorFunction[IRP_MJ_CLOSE]=IrpCloseProc;pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL]=IrpDeviceControlProc;pDriver->DriverUnload=DriverUnload;pDriver->DriverUnload=DriverUnload;return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 0:28:53

SWIFT框架全解析:从安装部署到高级训练的一站式AI开发指南

SWIFT框架全解析&#xff1a;从安装部署到高级训练的一站式AI开发指南 【免费下载链接】Qwen3-32B-AWQ 项目地址: https://ai.gitcode.com/hf_mirrors/Qwen/Qwen3-32B-AWQ 引言&#xff1a;开启SWIFT AI开发之旅 在人工智能快速发展的今天&#xff0c;高效开发和部署大…

作者头像 李华
网站建设 2026/5/3 11:17:08

37、商业技术管理的关键要点与策略

商业技术管理的关键要点与策略 1. 项目管理的五项关键技能 在项目管理中,有五项关键技能至关重要: 1. 评估项目成败的能力 :在商业案例获批后,评估项目能否成功、存在哪些风险、谁是最佳项目负责人、是否有合适的团队,以及需要立即解决的问题。在此过程中,诚实是最佳…

作者头像 李华
网站建设 2026/5/7 18:14:00

25、对等网络中的元数据与性能解析

对等网络中的元数据与性能解析 1. 元数据的应用与重要性 元数据能够让对等网络和 Web 应用接入描述性服务市场。以 MP3 服务为例,它在多个方面有着重要应用。 首先是更新 MP3 文件内的元数据,既可以纠正错误,也能添加额外信息。若不清楚某 MP3 文件源自哪张 CD,当获取到…

作者头像 李华
网站建设 2026/5/11 8:07:16

11、企业邮件、版本控制与Postfix、Git使用指南

企业邮件、版本控制与Postfix、Git使用指南 1. 公有云邮件服务分析 将电子邮件托管在公有云十分便捷,但也存在利弊。 优点 无需硬件和软件的资本支出。 无需工程人员维护邮件基础设施。 托管的总体拥有成本可能低于内部基础设施。 缺点 电子邮件安全掌握在他人手中。 …

作者头像 李华
网站建设 2026/5/14 16:00:47

23、智能家居网络搭建与通信指南

智能家居网络搭建与通信指南 在现代智能家居的构建中,网络搭建和通信方式是至关重要的环节。合理的网络布局和多样化的通信手段能够让家居设备更加智能、便捷地运行。以下将详细介绍相关的知识和操作方法。 无线网络接入点设置 无线网络是有线网络的补充,而非替代。WiFi 路…

作者头像 李华
网站建设 2026/5/1 6:09:58

18、SAS 窗口环境操作与定制全解析

SAS 窗口环境操作与定制全解析 在使用 SAS 进行数据处理和分析时,了解如何在其窗口环境中高效工作以及对环境进行定制是非常重要的。下面将详细介绍在 SAS 窗口环境中使用主机编辑器、获取帮助以及定制环境的相关内容。 1. 使用主机编辑器 在 SAS 中使用主机编辑器可以更方便…

作者头像 李华