博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DeviceIOControl与驱动层 - 缓冲区模式
阅读量:5780 次
发布时间:2019-06-18

本文共 12190 字,大约阅读时间需要 40 分钟。

IO交互模式中的DeviceIOControl与驱动层交互有三种:缓冲区模式、直接访问模式、其他模式,这里本人学习的是缓冲区访问模式,原理如图:

 

 

驱动中最好不要直接访问用户模式下的内存地址,使用缓冲区方式可以避免程序员访问内存模式下的内存地址。

Win32API DeviceIoControl的内部,用户提供的输入缓冲区的内容呗复制到IRP中的pIrp->AssociateIrp.SystemBuffer内存地址,复制的字节数是由DeviceIoControl指定的输入字节数。
派遣函数可以读取pIrp->AssociateIrp.SystemBuffer的内存地址,从而获得应用程序提供的输入缓冲数据。另外,派遣函数还可以写入pIrp->AssociateIrp.SystemBuffer的内存地址,被当做设备输出的数据。操作系统会将这个地址的数据再次复制到DeviceIoControl提供的输出缓冲区。复制的字节数有pIrp->IoStatus.Information指定。DeviceIoControl也可以通过它的第七个参数(lpBytesReturned)得到这个操作字节数。
派遣函数先通过IoGetCurrentIrpStackLocation函数->得到当前IO堆栈(IO_STACK_LOCATION)->派遣函数通过stack->Parameters.DeviceIoControl.InputBufferLength得到输入缓冲区大小->通过stack->Parameters.DeviceIoControl.OutputBufferLength得到输出缓冲区大小->最后通过stack->Parameters.DeviceIoControl.IoControlCode得到IOCTL
在派遣函数中通过C语言中的switch处理不同的IOCTL

 

代码:

BufferedIO.c

1 #include "BufferedIO.h"  2   3 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)  4 {  5     NTSTATUS Status = STATUS_SUCCESS;  6     PDEVICE_OBJECT  DeviceObject = NULL;  7     UNICODE_STRING  DeviceObjectName;//设备对象名称  8     UNICODE_STRING  DeviceLinkName;  //设备连接名称  9     int i = 0; 10  11  12     DriverObject->DriverUnload = DriverUnload; 13  14     //1.创建设备对象名称 15     RtlInitUnicodeString(&DeviceObjectName, DEVICE_OBJECT_NAME); 16  17     //2.创建设备对象 18     Status = IoCreateDevice( 19         DriverObject,//驱动程序对象. 20         NULL,        //指定驱动程序为设备扩展对象而定义的结构体的大小. 21         &DeviceObjectName,   //(可选的参数)指向一个以零结尾的包含Unicode字符串的缓冲区, 那是这个设备的名称, 该字符串必须是一个完整的设备路径名. 22         FILE_DEVICE_UNKNOWN, //指定一个由一个系统定义的FILE_DEVICE_XXX常量, 表明了这个设备的类型 23         0,                   //一个或多个系统定义的常量, 连接在一起, 提供有关驱动程序的设备其他信息. 24         FALSE,               //设备是独占的,独占的话设置为TRUE,非独占设置为FALSE.一般FALSE 25         &DeviceObject 26     );//成功时返回STATUS_SUCCESS 27  28     if (!NT_SUCCESS(Status)) 29     { 30         return Status; 31     } 32  33     //3.创建设备连接名称 34     RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME); 35  36     //4.将设备连接名称与设备名称关联 37     Status = IoCreateSymbolicLink( 38         &DeviceLinkName, 39         &DeviceObjectName 40     );//创建一个设备链接。 41       //驱动程序虽然有了设备名称,但是这种设备名称只能在内核态可见, 42       //而对于应用程序是不可见的,因此,驱动需要要暴露一个符号链接, 43       //该链接指向真正的设备名称 44  45     if (!NT_SUCCESS(Status)) 46     { 47         IoDeleteDevice(DeviceObject); 48         return Status; 49     } 50  51     //Ring3请求->设备对象-> 驱动对象找到派遣历程 52  53     //5.设置符合我们代码的派遣历程 54     for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) 55     { 56         //MinorFunction ring3 与ring0 的协议 57  58         DriverObject->MajorFunction[i] = PassThroughDispatch; 59     } 60  61     //IRP_MJ_DEVICE_CONTROL  DeviceIOControl函数产生 62     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlThroughDispatch; 63  64      65     return Status; 66 } 67  68 //基本派遣历程 69 NTSTATUS PassThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) 70 { 71     Irp->IoStatus.Status = STATUS_SUCCESS;     //LastError() 72     Irp->IoStatus.Information = 0;             //ReturnLength  73     IoCompleteRequest(Irp, IO_NO_INCREMENT);   //将Irp返回给Io管理器 74     return STATUS_SUCCESS; 75 } 76  77 NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) 78 { 79     NTSTATUS Status; 80     ULONG_PTR Informaiton = 0; 81     PVOID InputData = NULL; 82     ULONG InputDataLength = 0; 83     PVOID OutputData = NULL; 84     ULONG OutputDataLength = 0; 85     ULONG IoControlCode = 0; 86  87     //1.得到当前IO堆栈(IO_STACK_LOCATION) 88     PIO_STACK_LOCATION  IoStackLocation = IoGetCurrentIrpStackLocation(Irp);  //Irp堆栈     89  90     //2.看笔记或者代码中的图 而且在Ring0层中都是SystemBuffer 91     InputData = Irp->AssociatedIrp.SystemBuffer; 92     OutputData = Irp->AssociatedIrp.SystemBuffer; 93      94     //得到输入缓冲区大小 95     InputDataLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength; 96     //输出缓冲区大小 97     OutputDataLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; 98  99 100     //3.得到IOCTL101     IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode;102 103     //在派遣函数中通过Cswitch处理不同的IOCTL104     switch (IoControlCode)105     {106     case CTL_HELLO:107     {108         if (InputData != NULL && InputDataLength > 0)109         {110             DbgPrint("%s\r\n", InputData);111         }112         if (OutputData != NULL&&OutputDataLength >= strlen("Ring0->Ring3") + 1)113         {114             memcpy(OutputData, "Ring0->Ring3", strlen("Ring0->Ring3") + 1);115             Status = STATUS_SUCCESS;116             Informaiton = strlen("Ring0->Ring3") + 1;117         }118         else119         {120             Status = STATUS_INSUFFICIENT_RESOURCES;   //内存不够121             Informaiton = 0;122         }123 124         break;125     }126     default:127         break;128     }129 130 131     Irp->IoStatus.Status = Status;             //Ring3 GetLastError();132     Irp->IoStatus.Information = Informaiton;133     IoCompleteRequest(Irp, IO_NO_INCREMENT);  //将Irp返回给Io管理器134     135     return Status;136 }137 138 VOID DriverUnload(PDRIVER_OBJECT DriverObject)139 {140     UNICODE_STRING  DeviceLinkName;141     PDEVICE_OBJECT    v1 = NULL;142     PDEVICE_OBJECT  DeleteDeviceObject = NULL;143 144     RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);145     IoDeleteSymbolicLink(&DeviceLinkName);146 147     RtlInitUnicodeString(&DeviceLinkName, DEVICE_LINK_NAME);148     IoDeleteSymbolicLink(&DeviceLinkName);149 150     DeleteDeviceObject = DriverObject->DeviceObject;151     while (DeleteDeviceObject != NULL)152     {153         v1 = DeleteDeviceObject->NextDevice;154         IoDeleteDevice(DeleteDeviceObject);155         DeleteDeviceObject = v1;156     }157 158 159     DbgPrint("DriverUnload()\r\n");160 }161 162 /*163 typedef struct _DRIVER_OBJECT {164 CSHORT Type;165 CSHORT Size;166 167 //168 // The following links all of the devices created by a single driver169 // together on a list, and the Flags word provides an extensible flag170 // location for driver objects.171 //172 173 PDEVICE_OBJECT DeviceObject;//174 ULONG Flags;175 176 //177 // The following section describes where the driver is loaded.  The count178 // field is used to count the number of times the driver has had its179 // registered reinitialization routine invoked.180 //181 182 PVOID DriverStart;183 ULONG DriverSize;184 PVOID DriverSection;185 PDRIVER_EXTENSION DriverExtension;186 187 //188 // The driver name field is used by the error log thread189 // determine the name of the driver that an I/O request is/was bound.190 //191 192 UNICODE_STRING DriverName;193 194 //195 // The following section is for registry support.  Thise is a pointer196 // to the path to the hardware information in the registry197 //198 199 PUNICODE_STRING HardwareDatabase;200 201 //202 // The following section contains the optional pointer to an array of203 // alternate entry points to a driver for "fast I/O" support.  Fast I/O204 // is performed by invoking the driver routine directly with separate205 // parameters, rather than using the standard IRP call mechanism.  Note206 // that these functions may only be used for synchronous I/O, and when207 // the file is cached.208 //209 210 PFAST_IO_DISPATCH FastIoDispatch;211 212 //213 // The following section describes the entry points to this particular214 // driver.  Note that the major function dispatch table must be the last215 // field in the object so that it remains extensible.216 //217 218 PDRIVER_INITIALIZE DriverInit;219 PDRIVER_STARTIO DriverStartIo;220 PDRIVER_UNLOAD DriverUnload;221 PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];222 223 } DRIVER_OBJECT;224 225 */226 227 /*228 typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {229 CSHORT Type;230 USHORT Size;231 LONG ReferenceCount;232 struct _DRIVER_OBJECT *DriverObject;233 struct _DEVICE_OBJECT *NextDevice;  //234 struct _DEVICE_OBJECT *AttachedDevice;235 struct _IRP *CurrentIrp;236 PIO_TIMER Timer;237 ULONG Flags;                                // See above:  DO_...238 ULONG Characteristics;                      // See ntioapi:  FILE_...239 __volatile PVPB Vpb;240 PVOID DeviceExtension;241 DEVICE_TYPE DeviceType;242 CCHAR StackSize;243 union {244 LIST_ENTRY ListEntry;245 WAIT_CONTEXT_BLOCK Wcb;246 } Queue;247 ULONG AlignmentRequirement;248 KDEVICE_QUEUE DeviceQueue;249 KDPC Dpc;250 251 //252 //  The following field is for exclusive use by the filesystem to keep253 //  track of the number of Fsp threads currently using the device254 //255 256 ULONG ActiveThreadCount;257 PSECURITY_DESCRIPTOR SecurityDescriptor;258 KEVENT DeviceLock;259 260 USHORT SectorSize;261 USHORT Spare1;262 263 struct _DEVOBJ_EXTENSION  *DeviceObjectExtension;264 PVOID  Reserved;265 266 } DEVICE_OBJECT;267 */

 

BufferIO.h

1 #include 
2 3 4 //设备与设备之间通信 5 #define DEVICE_OBJECT_NAME L"\\Device\\BufferedIODeviceObjectName" 6 7 //设备与Ring3之间通信 8 #define DEVICE_LINK_NAME L"\\DosDevices\\BufferedIODeviceLinkName" 9 10 //Ring3 Ring0 握手协议 CTL_HELLO11 #define CTL_HELLO \12 CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS)13 14 15 16 17 NTSTATUS PassThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);18 NTSTATUS ControlThroughDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);19 20 21 22 23 VOID DriverUnload(PDRIVER_OBJECT DriverObject);

 

缓冲区IO(Ring3).cpp

1 // 缓冲区IO(Ring3).cpp : 定义控制台应用程序的入口点。  2 //  3   4 #include "stdafx.h"  5 #include 
6 7 #define DEVICE_LINK_NAME L"\\\\.\\BufferedIODeviceLinkName"//Ring3格式 8 9 #define CTL_HELLO \ 10 CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) 11 12 13 /* 14 DeviceIoControl内部会使操作系统创建一个 15 IRP_MJ_DEVICE_CONTROL类型的IRP,然后操作系统将这个IRP转发到派遣函数 16 17 我们用DeviceIoControl定义除了读写之外的其他操作,让Ring3程序与Ring0程序通信 18 19 e.g:自定义一种IO控制码,然后用DeviceIoControl将这个控制码和请求一起传递给驱动程序 20 派遣函数中,分别对不同的IO控制码进行处理 21 22 BOOL WINAPI DeviceIoControl( 23 _In_ HANDLE hDevice, //已经打开的设备 24 _In_ DWORD dwIoControlCode,//控制码 25 _In_opt_ LPVOID lpInBuffer, //输入缓冲区 26 _In_ DWORD nInBufferSize, //输入缓冲区大小 27 _Out_opt_ LPVOID lpOutBuffer, //输出缓冲区 28 _In_ DWORD nOutBufferSize, //输出缓冲区大小 29 _Out_opt_ LPDWORD lpBytesReturned,//实际返回字节数 30 _Inout_opt_ LPOVERLAPPED lpOverlapped //是否OverLapp 31 ); 32 33 34 */ 35 36 int main() 37 { 38 39 HANDLE DeviceHandle = CreateFile( 40 DEVICE_LINK_NAME, 41 GENERIC_READ | GENERIC_WRITE, 42 FILE_SHARE_READ | FILE_SHARE_WRITE, 43 NULL, 44 OPEN_EXISTING, 45 FILE_ATTRIBUTE_NORMAL, 46 NULL); 47 48 if (DeviceHandle == INVALID_HANDLE_VALUE) 49 { 50 return 0; 51 } 52 53 char BufferData = NULL; 54 DWORD ReturnLength = 0; 55 56 //操作系统内部是操作系统创建IRP_MJ_DEVICE_CONTROL类型的IRP 57 //Ring3->Ring0 58 BOOL IsOk = DeviceIoControl( 59 DeviceHandle, //已经打开的设备 60 CTL_HELLO,//控制码 61 "Ring3->Ring0",//输入缓冲区 62 strlen("Ring3->Ring0") + 1,//输入缓冲区大小 63 (LPVOID)BufferData,//输出缓冲区 64 0,//输出缓冲区大小 65 &ReturnLength,//实际返回字节数 66 NULL//是否OVERLAP操作 67 ); 68 69 if (IsOk == FALSE) 70 { 71 //上面的nOutBufferSize = 0 所以必定发生错误 72 73 int LastError = GetLastError(); 74 75 if (LastError == ERROR_NO_SYSTEM_RESOURCES) 76 { 77 char BufferData[MAX_PATH] = { 0 }; 78 79 //Ring3请求->设备对象-> 驱动对象找到派遣历程 80 81 IsOk = DeviceIoControl( 82 DeviceHandle, 83 CTL_HELLO, 84 "Ring3->Ring0", 85 strlen("Ring3->Ring0") + 1, 86 (LPVOID)BufferData, 87 MAX_PATH, 88 &ReturnLength, 89 NULL); 90 91 if (IsOk == TRUE) 92 { 93 printf("%s\r\n", BufferData); 94 } 95 } 96 } 97 98 if (DeviceHandle != NULL) 99 {100 CloseHandle(DeviceHandle);101 DeviceHandle = NULL;102 }103 printf("Input AnyKey To Exit\r\n");104 105 getchar();106 107 return 0;108 }

 

转载于:https://www.cnblogs.com/1228073191Blog/p/7524850.html

你可能感兴趣的文章
分形之康托(Cantor)三分集
查看>>
《软件测试自动化之道》读书笔记 之 底层的Web UI 测试
查看>>
ostringstream的使用方法
查看>>
python_smtplib
查看>>
Speeding up image loading in WPF using thumbnails
查看>>
[WCF编程]12.事务:事务传播
查看>>
1.PHP内核探索:从SAPI接口开始
查看>>
每日一句(2014-10-17)
查看>>
poj万人题
查看>>
Nutch+Lucene搜索引擎开发实践
查看>>
POJ 2417 Discrete Logging 离散对数
查看>>
深入浅出JMS(一)——JMS简单介绍
查看>>
iOS IAP教程
查看>>
通用权限管理系统记录登录日志中的一个问题
查看>>
c++ const enum #define
查看>>
PID教程
查看>>
开源作业调度框架
查看>>
Android APK反编译详解(附图)
查看>>
[转]ubuntu安装gcc
查看>>
js 延时
查看>>