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

windows内核研究(驱动开发-0环与3环的通信)

驱动开发


0环与3环的通信

设备对象

在之前开发窗口程序时,消息都是被封装成一个结构体(MSG),在内核开发时,消息被封装成另外一个结构体:IRP(I/O Request Package)

在窗口程序中,能够接收消息的只能是窗口对象,在内核中,能够接收IRP消息的只能是设备对象

创建设备对象

// 创建设备名称
UNICODE_STRING deviceName;
RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");/*
NTSTATUS IoCreateDevice([in]           PDRIVER_OBJECT  DriverObject,			// 驱动对象[in]           ULONG           DeviceExtensionSize,	// 指定要为设备对象的 设备扩展 分配的驱动程序确定字节数[in, optional] PUNICODE_STRING DeviceName,			// 设备名称[in]           DEVICE_TYPE     DeviceType,			// 设备类型[in]           ULONG           DeviceCharacteristics,	// 设备特征[in]           BOOLEAN         Exclusive,				// 指定设备对象是否表示 独占设备[out]          PDEVICE_OBJECT  *DeviceObject			// 指向接收指向新创建的 DEVICE_OBJECT 结构的指针的变量的指针
);
*/// 创建设备对象
NTSTATUS ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);

数据的交互方式

// 设置数据的交互方式
driverObject->Flags |= DO_BUFFERED_IO;
  • 缓存区方式读写(DO_BUFFERED_IO):操作系统将应用程序提供缓冲区的数据复制到内核模式下的地址中
  • 直接方式读写(DO_DIRECT_IO):操作系统会将用户模式下的缓冲区锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍,这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存(缺点就是要单独占用物理页面)
  • 其他方式读写(在调用IoCreateDevice创建设备后对drivceObjcet->Flags既不设置DO_BUFFERED_IO也不设置DO_DIRECT_IO此时就是其它方式):在使用其他方式读写设备时,派遣函数直接读写应用程序提供的缓冲地址。在驱动程序中,直接操作应用程序的缓冲区是很危险的,只有驱动程序与应用程序运行在相同线程上下文的情况下,才能使用这种方式

IRP的类型

当应用层通过CreateFile,ReadFile,WriteFile,CloseHandle等函数打开,从设备读取数据,向设备写入数据,关闭设备的时候,会使操作系统系统产出不同的IRP_CREATE,IPR_MJ_READ,IRP_MJ_WRITE等IRP

其它类型

IRP类型来源
IRP_MJ_DEVICE_CONTROLDeviceControl函数会产生些IRP
IRP_MJ_POWER在操作系统处理电源消息时,产生此IRP
IRP_MJ_SHUTDOWN关闭系统前会产生些IRP

IRP_MJ_DEVICE_CONTROL才是我们Ring3与驱动交互的常规方式

测试代码

3环应用程序代码

#include<iostream>
#include<windows.h>#define IN_BUFFER_MAXLENGIT			0x10			// 输入缓存最大长度
#define OUT_BUFFER_MAXLENGTH		0x10			// 输出缓存最大长度
// 参数说明:1,设备类型,2,操作码,3,以什么方式进行访问,4,访问权限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) 
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define SYMBOLICLINK_NAME "\\\\.\\MyTestDriver"HANDLE g_hDriver;BOOL open(const CHAR* pLinkName) {TCHAR szBuffer[10] = { 0 };g_hDriver = CreateFileA(pLinkName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);DWORD errorCode = GetLastError();swprintf(szBuffer,sizeof(szBuffer),L"%d:\n",errorCode);if (g_hDriver != INVALID_HANDLE_VALUE)return TRUE;else return FALSE;
}/*
BOOL DeviceIoControl([in]                HANDLE       hDevice,			设备句柄[in]                DWORD        dwIoControlCode,	控制代码[in, optional]      LPVOID       lpInBuffer,		向0环传递的缓冲区的地址[in]                DWORD        nInBufferSize,		缓冲区的大小[out, optional]     LPVOID       lpOutBuffer,		向3还传递的缓冲区的地址[in]                DWORD        nOutBufferSize,	缓冲区的大小[out, optional]     LPDWORD      lpBytesReturned,	实际返回的长度(字节数)[in, out, optional] LPOVERLAPPED lpOverlapped		
);
*/BOOL ioControl(DWORD dwIoCode,PVOID InBuffer,DWORD InBuffLen,PVOID OutBuff,DWORD OutBuffLen) { DWORD dw;DeviceIoControl(g_hDriver,dwIoCode,InBuffer,InBuffLen,OutBuff,OutBuffLen,&dw,NULL);return TRUE;
}int main() {DWORD dwInBuffer = 0x11112222;TCHAR szOutBuffer[OUT_BUFFER_MAXLENGTH] = { 0 };// 通过符号链接 打开设备if (open(SYMBOLICLINK_NAME)) {printf("open device success\n");}else {printf("open device failed\n");}ioControl(OPER2, &dwInBuffer, IN_BUFFER_MAXLENGIT, szOutBuffer, OUT_BUFFER_MAXLENGTH);CloseHandle(g_hDriver);system("pause");return 0;
} 

0环驱动程序

#include <ntddk.h>#define DEVICE_NAME L"\\Device\\MyDevice"
// Ring3用CreateDevice打开设备时用 \\\\.\\MyTestDriver
#define SYMBOLICLINK_NAME L"\\??\\MyTestDriver"#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)// IRP_MJ_CREATE 处理函数
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj,PIRP pIrp) {DbgPrint("设备创建了...");// 设置返回状态pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_CLOSE 处理函数
NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {DbgPrint("设备关闭了...");// 设置返回状态pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_DEVICE_CONTROL 处理函数
NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {NTSTATUS stauts = STATUS_INVALID_DEVICE_REQUEST;PIO_STACK_LOCATION pIrpStack;ULONG uIoControlCode;PVOID pIoBuffer;ULONG uInLength;ULONG uOutLength;ULONG uRead;ULONG uWrite;// 设置临时变量的值uRead = 0;uWrite = 0x12345678;//获取IRP数据pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//获取控制码uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 获取缓冲区地址(输入和输出的缓冲区都是一个)pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;// Ring3 发送数据的长度uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// Ring0 发送数据的长度uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;pIrp->IoStatus.Information = 0;switch (uIoControlCode) {case OPER1:{DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 1");// 设置返回状态pIrp->IoStatus.Information = 1;stauts = STATUS_SUCCESS;break;}case OPER2:{DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 接收字节数:%d\n", uInLength);DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 输出字节数:%d\n", uOutLength);// 读缓存memcpy(&uRead,pIoBuffer,4);DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 地址:%llx",uRead);// 写缓存memcpy(pIoBuffer,&uWrite,4);// 设置返回状态pIrp->IoStatus.Information = 2;stauts = STATUS_SUCCESS;break;}}// 设置返回状态pIrp->IoStatus.Status = stauts;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;}// 卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("驱动被卸载了\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING reg_path) {NTSTATUS ntIoCreate = 0;PDEVICE_OBJECT pDeviceObject = NULL;UNICODE_STRING deviceName;UNICODE_STRING symbolicLinkName;// 创建设备名称RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");// 创建设备对象ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);if (ntIoCreate != STATUS_SUCCESS) {DbgPrint("设备对象创建失败!\n");return ntIoCreate;}// 设置数据的交互方式driverObject->Flags |= DO_BUFFERED_IO;// 创建符号链接名称(给Ring3访问)// Ring3用CreateFile打开设备时用 \\\\.\\MyTestDriverRtlInitUnicodeString(&symbolicLinkName, L"\\??\\MyTestDriver");// 创建符号链接ntIoCreate = IoCreateSymbolicLink(&symbolicLinkName, &deviceName);if(ntIoCreate != STATUS_SUCCESS) {DbgPrint("符号链接创建失败!\n");	IoDeleteDevice(pDeviceObject);return ntIoCreate;}// 设置派遣函数和卸载函数driverObject->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;driverObject->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceControlProc;driverObject->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

演示效果

在这里插入图片描述

http://www.xdnf.cn/news/1150921.html

相关文章:

  • Kotlin泛型约束
  • 多表查询-8-练习总结
  • 数据库练习3
  • Flowable31动态表单-----------------------终章
  • 博图SCL语言中常用运算符使用详解及实战案例(下)
  • OpenCV 官翻 3 - 特征检测 Feature Detection
  • 【无标题】重点阅读——如何在信息层面区分和表征卷曲维度,解析黑洞内部的维度区分机制
  • 《命令行参数与环境变量:从使用到原理的全方位解析》
  • 搭建比分网服务器怎么选数据不会卡顿?
  • lvs原理及实战部署
  • 【I2C】01.I2C硬件连接I2C总线时序图讲解
  • Go语言pprof性能分析指南
  • Temperature 是在LLM中的每一层发挥作用,还是最后一层? LLM中的 Temperature 参数 是怎么计算的
  • 操作系统-分布式同步
  • TCP/UDP协议深度解析(四):TCP的粘包问题以及异常情况处理
  • GaussDB 数据库架构师修炼(六) 集群工具管理-1
  • 异步解决一切问题 |消息队列 |减少嵌套 |hadoop |rabbitmq |postsql
  • 深入解析 Amazon Q:AWS 推出的企业级生成式 AI 助手
  • 【设计模式C#】外观模式(用于解决客户端对系统的许多类进行频繁沟通)
  • LangGraph教程10:LangGraph ReAct应用
  • 访问 gitlab 跳转 0.0.0.0
  • 深入理解设计模式:策略模式的艺术与实践
  • XSS原型与原型链
  • 告别项目混乱:基于 pnpm + Turborepo 的现代化 Monorepo 工程化最佳实践
  • C++控制台贪吃蛇开发:从0到1绘制游戏世界
  • Git 完全手册:从入门到团队协作实战(2)
  • GaussDB union 的用法
  • Maven 依赖管理
  • Java从入门到精通:全面学习路线指南
  • uniapp props、$ref、$emit、$parent、$child、$on