涿鹿镇做网站,91永久海外地域网名,长沙营销型网页制作公司,已备案个人网站做淘宝客前置知识
IRP是什么
IRP的处理机制类似于windows窗口程序中的“消息处理”机制#xff0c;驱动程序接收到不同类型的IRP后#xff0c;会进入不同的派遣函数#xff0c;在派遣函数中IRP得到处理。
派遣函数是什么用户模式下所有对驱动程序的I/O请求#xff0c;全部由操作系统…前置知识IRP是什么IRP的处理机制类似于windows窗口程序中的“消息处理”机制驱动程序接收到不同类型的IRP后会进入不同的派遣函数在派遣函数中IRP得到处理。派遣函数是什么用户模式下所有对驱动程序的I/O请求全部由操作系统转换为一个叫做IRP的数据结构不同的IRP数据会被“派遣”道不同的派遣函数中这也是派遣函数名字的由来。驱动程序并不是“被直接调用”的而是由操作系统根据 IRP 的类型进行派遣。每一种 IRP 都有一个“主功能码Major Function”例如IRP_MJ_CREATE打开设备CreateFileIRP_MJ_CLOSE关闭设备CloseHandleIRP_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#includestdio.h#includewindows.h#includewinioctl.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 dwInBuffer0x123456789;TCHAR szOutBuffer[10]{0};DWORD dw;//1. 通过符号链接打开设备HANDLE g_hDeviceCreateFileW(L\\\\.\\MyDevice,// 设备名例如 \\\\.\\MyDeviceGENERIC_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#includentifs.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_BLOCKpIrp-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.StatusSTATUS_SUCCESS;//这个字段的含义取决于 是什么 IRP//对 IRP_MJ_READ常常表示“实际读取了多少字节”//对 IRP_MJ_WRITE常常表示“实际写入了多少字节”//对 IRP_MJ_DEVICE_CONTROL表示“返回给用户缓冲区的数据长度”//对 IRP_MJ_CREATE / IRP_MJ_CLOSE一般没有额外数据需要告诉 Ring3所以设为 0pIrp-IoStatus.Information0;//告诉 I/O 管理器“这个 IRP 我处理完了可以结束这次 I / O 请求了。”//如果不调用IoCompleteRequestRing3 那边的 CreateFile 会一直等同步调用永远等不到结果表现就是程序卡死/挂住。IoCompleteRequest(pIrp,IO_NO_INCREMENT);//return STATUS_SUCCESS; 和 IoStatus.Status 的关系//这里返回值也是 NTSTATUSI / O 管理器确实也会用这个值但真正传回 Ring3 的是 pIrp-IoStatus.Status。returnSTATUS_SUCCESS;}// IRP_MJ_CLOSE处理函数NTSTATUSIrpCloseProc(PDEVICE_OBJECT pDevObj,PIRP pIrp){DbgPrint((mydriver)DispatchClose ... \n);pIrp-IoStatus.StatusSTATUS_SUCCESS;pIrp-IoStatus.Information0;IoCompleteRequest(pIrp,IO_NO_INCREMENT);returnSTATUS_SUCCESS;}// IRP_MJ_DEVICE_CONTROL处理函数 用来处理与Ring3交互NTSTATUSIrpDeviceControlProc(PDEVICE_OBJECT pDevObj,PIRP pIrp){NTSTATUS statusSTATUS_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 pIrpStackIoGetCurrentIrpStackLocation(pIrp);// 获取控制码ULONG uIoControlCodepIrpStack-Parameters.DeviceIoControl.IoControlCode;// 获取缓冲区地址(输入和输出的缓冲区都是一个)PVOID pIoBufferpIrp-AssociatedIrp.SystemBuffer;// Ring3 发送数据的长度:用户写进来的数据长度你最多只能读这么多字节。ULONG uInLengthpIrpStack-Parameters.DeviceIoControl.InputBufferLength;// Ring0 发送数据的长度:用户预留的输出缓冲区最大长度你最多填这么多字节。ULONG uOutLengthpIrpStack-Parameters.DeviceIoControl.OutputBufferLength;switch(uIoControlCode){caseOPER1:{DbgPrint((mydriver)IrpDeviceControlProc - OPER1 ... \n);pIrp-IoStatus.Information0;statusSTATUS_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.Information4;statusSTATUS_SUCCESS;break;}}// 设置返回状态pIrp-IoStatus.Statusstatus;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 pDeviceObjNULL;NTSTATUS statusIoCreateDevice(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);// 创建符号链接statusIoCreateSymbolicLink(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-DriverUnloadDriverUnload;pDriver-DriverUnloadDriverUnload;return0;}