• 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
    ", 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()
    ");
    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
    ", BufferData);
     94             }
     95         }
     96     }
     97 
     98     if (DeviceHandle != NULL)
     99     {
    100         CloseHandle(DeviceHandle);
    101         DeviceHandle = NULL;
    102     }
    103     printf("Input AnyKey To Exit
    ");
    104 
    105     getchar();
    106 
    107     return 0;
    108 }
  • 相关阅读:
    Access使用记录
    html js 表单提交前检测数据
    asp.net mvc5 action多个参数
    asp.net mvc Areas 母版页动态获取数据进行渲染
    asp.net mvc 自定义全局过滤器 验证用户是否登录
    .net 报错汇总——持续更新
    数据库基础
    Python协程
    Python 线程
    Python 队列
  • 原文地址:https://www.cnblogs.com/1228073191Blog/p/7524850.html
Copyright © 2020-2023  润新知