DeviceIOControl与驱动层 - 缓冲区模式

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.得到IOCTL
101     IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode;
102 
103     //在派遣函数中通过Cswitch处理不同的IOCTL
104     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         else
119         {
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 driver
169 // together on a list, and the Flags word provides an extensible flag
170 // 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 count
178 // field is used to count the number of times the driver has had its
179 // 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 thread
189 // 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 pointer
196 // to the path to the hardware information in the registry
197 //
198 
199 PUNICODE_STRING HardwareDatabase;
200 
201 //
202 // The following section contains the optional pointer to an array of
203 // alternate entry points to a driver for "fast I/O" support.  Fast I/O
204 // is performed by invoking the driver routine directly with separate
205 // parameters, rather than using the standard IRP call mechanism.  Note
206 // that these functions may only be used for synchronous I/O, and when
207 // the file is cached.
208 //
209 
210 PFAST_IO_DISPATCH FastIoDispatch;
211 
212 //
213 // The following section describes the entry points to this particular
214 // driver.  Note that the major function dispatch table must be the last
215 // 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 keep
253 //  track of the number of Fsp threads currently using the device
254 //
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 <ntifs.h>
 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_HELLO
11 #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 <windows.h>
  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 }

 

posted on 2017-09-15 10:06  czhang4  阅读(948)  评论(0编辑  收藏  举报