zoukankan      html  css  js  c++  java
  • 驱动开发之 用DeviceIoControl实现应用程序与驱动程序通信

    Ring3测试程序:http://blog.csdn.net/zj510/article/details/8216321

    1.readfile和writefile可以实现应用程序与驱动程序通信,另外一个Win32 API 是DeviceIoControl。

    应用程序自定义一中IO控制码,然后调用DeviceIoControl函数,IO管理器会产生一个MajorFunction 为IRP_MJ_DEVICE_CONTROL,MinorFunction 为自己定义的控制码的IRP,系统就调用相应的处理IRP_MJ_DEVICE_CONTROL的派遣函数,你在派遣函数中判断MinorFunction ,是自定义的控制码你就进行相应的处理。

    2.首先介绍一下DeviceIoControl函数

     1 BOOL WINAPI DeviceIoControl(
     2   _In_         HANDLE hDevice,      //已经打开的设备句柄
     3   _In_         DWORD dwIoControlCode,//自定义的控制码,稍后介绍怎么定义
     4   _In_opt_     LPVOID lpInBuffer,    //输入缓冲区
     5   _In_         DWORD nInBufferSize,  //输入缓冲区的大小
     6   _Out_opt_    LPVOID lpOutBuffer,   //输出缓冲区
     7   _In_         DWORD nOutBufferSize, //输出缓冲区的大小
     8   _Out_opt_    LPDWORD lpBytesReturned, //实际返回的字节数,对应驱动程序中pIrp->IoStatus.Information。
     9   _Inout_opt_  LPOVERLAPPED lpOverlapped //重叠操作结构指针。同步设为NULL,DeviceIoControl将进行阻塞调用;否则,应在编程时按异步操作设计
    10 );

    例如:

    1 UCHAR InputBuffer[10];
    2 UCHAR OutputBuffer[10];
    3 
    4 //将输入缓冲区全部置成0XBB
    5 memset(InputBuffer,0xBB,10);
    6 DWORD dwOutput;
    7 //输入缓冲区作为输入,输出缓冲区作为输出
    8 BOOL bRet = DeviceIoControl(hDevice, IOCTL_TEST, InputBuffer, 10, OutputBuffer, 10, &dwOutput, (LPOVERLAPPED)NULL);

    3.定义IO控制码

    #define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)

    IOCTL_Device_Function:生成的IRP的MinorFunction 

    DeviceType:设备对象的类型。设备类型可参考:http://blog.csdn.net/liyun123gx/article/details/38058965

    Function :自定义的IO控制码。自己定义时取0x800到0xFFF,因为0x0到0x7FF是微软保留的。

    Method :数据的操作模式。

                  METHOD_BUFFERED:缓冲区模式

                  METHOD_IN_DIRECT:直接写模式

                  METHOD_OUT_DIRECT:直接读模式

                  METHOD_NEITHER :Neither模式

    Access:访问权限,可取值有:

                FILE_ANY_ACCESS:表明用户拥有所有的权限

                FILE_READ_DATA:表明权限为只读

                FILE_WRITE_DATA:表明权限为可写

                也可以 FILE_WRITE_DATA | FILE_READ_DATA:表明权限为可读可写,但还没达到FILE_ANY_ACCESS的权限。

    例如:#define IOCTL_TEST     CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

    4.下面介绍不同的数据操作模式

    (1).METHOD_BUFFERED:缓冲区模式

    用户提供的输入缓冲区的内容被复制到IRP中的pIrp->AssociatedIrp.SystemBuffer内存地址,复制的长度是DeviceIoControl指定的输入字节数。

    驱动程序输出数据时,还可以向pIrp->AssociatedIrp.SystemBuffer中写入,操作系统会将此地址的数据复制到DeviceIoControl的输出缓冲区。

    复制的字节数通过设置pIrp->IoStatus.Information来指定。

    派遣函数中通过下面代码得到输入缓冲区输出缓冲的大小以及IOCTL

    1 //得到当前堆栈
    2 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    3 //得到输入缓冲区大小
    4 ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
    5 //得到输出缓冲区大小
    6 ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
    7 //得到IOCTL码
    8 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

    通过操作pIrp->AssociatedIrp.SystemBuffer来进行数据的输入输出

     1 UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
     2 for (ULONG i=0;i<cbin;i++)
     3 {
     4     KdPrint(("%X
    ",InputBuffer[i]));
     5 }
     6 
     7 //操作输出缓冲区,输出缓冲区和输入缓冲区是一个缓冲区
     8 UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
     9 memset(OutputBuffer,0xAA,cbout);
    10 //设置实际操作输出缓冲区长度
    11  pIrp->IoStatus.Information = cbout;        

    (2) METHOD_IN_DIRECT与METHOD_OUT_DIRECT  直接内存模式

    与缓冲模式相同,用户提供的输入缓冲区的内容被复制到IRP中的pIrp->AssociatedIrp.SystemBuffer内存地址,复制的长度是DeviceIoControl指定的输入字节数。

    直接内存模式中,操作系统会将DeviceIoControl指定的输出缓冲区锁定,然后在内核模式地址下重新映射一段地址。

    派遣函数中IRP中的pIrp->MdlAddress记录DeviceIoControl指定的输出缓冲区。派遣函数应该使用MmGetSystemAddressForMdlSafe将这段内存映射到内核模式下的内存地址。

    得到输入输出缓冲区的大小以及IOCTL的方式与缓冲区模式相同。

    另外需要注意CTL_CODE设置的权限问题,若以只读方式打开设备,METHOD_IN_DIRECT的IOCTL操作会失败。

    派遣函数中处理直接内存模式:

     1 //显示输入缓冲区数据
     2 UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
     3 for (ULONG i=0;i<cbin;i++)
     4 {
     5     KdPrint(("%X
    ",InputBuffer[i]));
     6 }
     7 //pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
     8 KdPrint(("User Address:0X%08X
    ",MmGetMdlVirtualAddress(pIrp->MdlAddress)));
     9 UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
    10 //InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间
    11 memset(OutputBuffer,0xAA,cbout);

    (3)METHOD_NEITHER :Neither模式

    因为此模式直接访问用户模式地址,这是很危险的,所以此模式很少被用到。

    使用用户模式地址必须保证调用DeviceIoControl 的线程与派遣函数运行在同一个线程上下文中。

    派遣函数得到输入缓冲区的方式与前两种不同,此模式是通过IO堆栈的stack->Parameters.DeviceIoControl.Type3InputBuffer;得到输入缓冲区。

    驱动通过pIrp->UserBuffer得到输出缓冲区。

    得到输入输出缓冲区的长度与IOCTL的方式与前两种相同。

    由于驱动程序的派遣函数不能保证传递进来的用户地址是合法地址,所以要对传入的用户模式地址进行可读写判断。这就需要ProbeForRead函数和ProbeForWrite函数与_try _execpt 结合使用。

    下面是驱动派遣函数中Neither模式

     1 //显示输入缓冲区数据
     2 UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
     3 KdPrint(("UserInputBuffer:0X%0X
    ",UserInputBuffer));
     4 
     5 //得到用户模式地址
     6 PVOID UserOutputBuffer = pIrp->UserBuffer;
     7 KdPrint(("UserOutputBuffer:0X%0X
    ",UserOutputBuffer));
     8 
     9 __try
    10 {
    11     KdPrint(("Enter __try block
    "));
    12 
    13     //判断指针是否可读
    14     ProbeForRead(UserInputBuffer,cbin,4);
    15     //显示输入缓冲区内容
    16     for (ULONG i=0;i<cbin;i++)
    17     {
    18         KdPrint(("%X
    ",UserInputBuffer[i]));
    19     }
    20 
    21     //判断指针是否可写
    22     ProbeForWrite(UserOutputBuffer,cbout,4);
    23 
    24     //操作输出缓冲区
    25     memset(UserOutputBuffer,0xAA,cbout);
    26 
    27     //如果在上面引发异常,所以以后语句不会被执行!
    28     pIrp->IoStatus.Information = cbout;
    29 
    30     KdPrint(("Leave __try block
    "));
    31 }
    32 __except(EXCEPTION_EXECUTE_HANDLER)
    33 {
    34     KdPrint(("Catch the exception
    "));
    35     KdPrint(("The program will keep going
    "));
    36     status = STATUS_UNSUCCESSFUL;
    37 }
    38 
    39 pIrp->IoStatus.Information = cbout;
  • 相关阅读:
    稳扎稳打Silverlight(13) 2.0交互之鼠标事件和键盘事件
    稳扎稳打Silverlight(17) 2.0数据之详解DataGrid, 绑定数据到ListBox
    再接再厉VS 2008 sp1 + .NET 3.5 sp1(2) Entity Framework(实体框架)之详解 Linq To Entities 之一
    稳扎稳打Silverlight(8) 2.0图形之基类System.Windows.Shapes.Shape
    稳扎稳打Silverlight(11) 2.0动画之ColorAnimation, DoubleAnimation, PointAnimation, 内插关键帧动画
    稳扎稳打Silverlight(21) 2.0通信之WebRequest和WebResponse, 对指定的URI发出请求以及接收响应
    稳扎稳打Silverlight(16) 2.0数据之独立存储(Isolated Storage)
    稳扎稳打Silverlight(9) 2.0画笔之SolidColorBrush, ImageBrush, VideoBrush, LinearGradientBrush, RadialGradientBrush
    稳扎稳打Silverlight(23) 2.0通信之调用WCF的双向通信(Duplex Service)
    游戏人生Silverlight(1) 七彩俄罗斯方块[Silverlight 2.0(c#)]
  • 原文地址:https://www.cnblogs.com/luzhiyuan/p/4385358.html
Copyright © 2011-2022 走看看