龙马谷

 找回密码
 立即注册

QQ登录

只需一步,快速开始

龙马谷VIP会员办理客服QQ:82926983(如果临时会话没有收到回复,请先加QQ好友再发。)
1 [已完结] GG修改器新手入门与实战教程 31课 2 [已完结] GG修改器美化修改教程 6课 3 [已完结] GG修改器Lua脚本新手入门教程 12课
4 [已完结] 触动精灵脚本新手入门必学教程 22课 5 [已完结] 手游自动化脚本入门实战教程 9课 6 [已完结] C++射击游戏方框骨骼透视与自瞄教程 27课
7 [已完结] C++零基础UE4逆向开发FPS透视自瞄教程 29课 8 [已完结] C++零基础大漠模拟器手游自动化辅助教程 22课
以下是天马阁VIP教程,本站与天马阁合作,赞助VIP可以获得天马阁对应VIP会员,名额有限! 点击进入天马阁论坛
1 [已完结] x64CE与x64dbg入门基础教程 7课 2 [已完结] x64汇编语言基础教程 16课 3 [已完结] x64辅助入门基础教程 9课
4 [已完结] C++x64内存辅助实战技术教程 149课 5 [已完结] C++x64内存检测与过检测技术教程 10课 6 [已完结] C+x64二叉树分析遍历与LUA自动登陆教程 19课
7 [已完结] C++BT功能原理与x64实战教程 29课 8 [已完结] C+FPS框透视与自瞄x64实现原理及防护思路
查看: 1864|回复: 0

DeviceIoControl解读

[复制链接]

11

主题

1

回帖

19

积分

编程入门

Rank: 1

龙马币
66

设备驱动程序可以被当作内核模式函数包来看待,I/O控制代码就是用来指定访问其中的哪个函数的。DeviceIoControl函数的dwIoControlCode参数就是这个代码,它指出了我们需要进行的操作,以及如何进行操作。

控制代码是32位数字型常量,可以CTL_CODE宏来定义,它们定义在winioctl.inc和ntddk.inc文件中。

控制代码中各数据位字段的含义如下:

◎ DeviceType--设备类型(16bit)指出了设备的类型,微软保留了0-7FFFh的取值,剩下的8000h-0FFFFh供开发商定义新的内核模式驱动程序。我们可以在\include\w2k\ntddk.inc文件中找到一组FILE_DEVICE_XXX符号常量,这些值都是微软保留的值,我们可以使用其中的FILE_DEVICE_UNKNOWN。当然你也可以定义另外一个FILE_DEVICE_XXX值

◎ Access--存取代码(2bit)指明应用程序存取设备的方式,由于这个字段只有2位,所以只有4种可能性:
· FILE_ANY_ACCESS (0)--最大的存取权限,就是什么操作都可以
· FILE_READ_ACCESS (1)--读权限,设备将数据传递到指定的缓冲区
· FILE_WRITE_ACCESS (2)--写权限,可以从内存中向设备传递数据
· FILE_READ_ACCESS or FILE_WRITE_ACCESS (3)--读写权限,设备和内存缓冲区之间可以互相传递数据

◎ Function--功能代码(12bit)用来描述要进行的操作,我们可以用800h-0FFFh来定义自己的I/O控制代码,0-7FFh之间的值是被微软保留的,用来定义公用的I/O控制代码

◎ Method--缓冲模式(2bit)表示I/O管理器如何对输入和输出的数据进行缓冲,这个字段的长度是2位,所以有4种可能性:
· METHOD_BUFFERED (0)--对I/O进行缓冲
· METHOD_IN_DIRECT (1)--对输入不进行缓冲
· METHOD_OUT_DIRECT (2)--对输出不进行缓冲
· METHOD_NEITHER (3)--都不缓冲

缓冲模式的管理我们会在后面进行更详细的讨论,当前最重要的是,虽然进行缓冲会带来一些额外的内存开销,但却是最安全的,因为系统已经做好了相关的全部工作。在传输的数据小于一页(4Kb)的时候,驱动程序通常使用缓冲方式的I/O,因为对大量小块内存进行内存锁定带来的开销也是很大的。在 VirtToPhys驱动程序中,我们使用带缓冲的方式。

读者可以手工去定义I/O控制代码,但是使用CTL_CODE宏会方便得多,它提供了创建IOCTL值的算法,具体如下:
  1. CTL_CODE MACRO DeviceType:= <0> , Function:= <0> , Method:= <0> , Access:= <0>

  2. EXITM %(((DeviceType) SHL 16) OR ((Access) SHL 14) OR ((Function) SHL 2) OR (Method))
复制代码



CTL_CODE宏在winioctl.inc文件和ntddk.inc文件中都有定义。

在应用程序里定义的CTL_CODE和驱动中IRP_MJ_DEVICE_CONTROL的函数里控制码对应即可。在驱动程序里取出码值进行对比操作,如:

  1.    dwIoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;

  2.     switch (dwIoControlCode)
  3.     {

  4.      // 我们约定,缓冲区共两个DWORD,第一个DWORD为端口,第二个DWORD为数据

  5.      // 一般做法是专门定义一个结构,此处简单化处理了

  6.      case IOCTL_MYPORT_READ_BYTE:   // 从端口读字节

  7.       pvIOBuffer[1] = _inp(pvIOBuffer[0]);

  8.       Irp->IoStatus.Information = 8;   // 输出长度为8

  9.       break;

  10.      case IOCTL_MYPORT_WRITE_BYTE:   // 写字节到端口

  11.       _outp(pvIOBuffer[0], pvIOBuffer[1]);

  12.       break;

  13.      default:   // 不支持的IOCTL

  14.       Irp->IoStatus.Status = STATUS_INVALID_PARAME
复制代码


应用程序和驱动程序的通信过程是:应用程序使用CreateFile函数打开设备,然后用DeviceIoControl与驱动程序进行通信,包括读和写两种操作。还可以用ReadFile读数据用WriteFile写数据。操作完毕时用CloseHandle关闭设备。我们比较常用的就是用DeviceIoControl对设备进行读写操作。先看看DeviceIoControl是怎么定义的:

BOOL DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped );

Parameters(参数)

hDevice (CreateFile返回的设备句柄)
[in] Handle to the device that is to perform the operation. To obtain a device handle, call the CreateFile function.
dwIoControlCode (应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs )
[in] IOCTL for the operation. This value identifies the specific operation to perform and the type of device on which to perform the operation. There are no specific values defined for the dwIoControlCode parameter. However, you can define custom IOCTL_XXX IOCTLs with the CTL_CODE macro. You can then advertise these IOCTLs and an application can use these IOCTLs with DeviceIoControl to perform the driver-specific functions.
lpInBuffer (应用程序传递给驱动程序的数据缓冲区地址)
[in] Long pointer to a buffer that contains the data required to perform the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not require input data.
nInBufferSize (应用程序传递给驱动程序的数据缓冲区大小,字节数)
[in] Size, in bytes, of the buffer pointed to by lpInBuffer.
lpOutBuffer (驱动程序返回给应用程序的数据缓冲区地址)
[out] Long pointer to a buffer that receives the output data for the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not produce output data.
nOutBufferSize (驱动程序返回给应用程序的数据缓冲区大小,字节数)
[out] Size, in bytes, of the buffer pointed to by lpOutBuffer.
lpBytesReturned (驱动程序实际返回给应用程序的数据字节数地址)
[out] Long pointer to a variable that receives the size, in bytes, of the data stored in lpOutBuffer. The DeviceIoControl function may unnecessarily use this parameter. For example, if an operation does not produce data for lpOutBuffer and lpOutBuffer is NULL, the value of lpBytesReturned is meaningless.
lpOverlapped (重叠操作结构)
[in] Ignored; set to NULL.
Return Values(返回值)

Nonzero indicates success. Zero indicates failure. To obtain extended error information, call the GetLastError function. (非0成功,0失败)

具体使用我们看看列子:

1,向设备传递数据,我们定义一个函数来实现
  1. bool CDeviceOperDlg::SendKeyData(HANDLE handle, BYTE *bData, int iSize)
  2. {
  3. ULONG nOutput;
  4. BYTE bTemp[512];
  5. //将数据放置到发送数组
  6. memset(bTemp,0,sizeof(bTemp));
  7. memcpy(bTemp,&bData[0],iSize);
  8. //向设备发送
  9. if (!DeviceIoControl(handle,        
  10.        ATST2004_IOCTL_WRITE,     //根据具体的设备有相关的定义
  11.        bTemp,                                        //向设备传递的数据地址
  12.        iSize,                                            //数据大小,字节数
  13.        NULL,                                          //没有返回的数据,置为NULL
  14.        0,                                                  //没有返回的数据,置为0
  15.        &nOutput,
  16.        NULL)
  17.     )
  18. {
  19.    return false;
  20. }
  21. return true;
  22. }
复制代码


2,从设备读取数据
  1. bool CDeviceOperDlg::ReviceKeyData(HANDLE handle, BYTE *bData, int iSize)
  2. {
  3. ULONG nOutput;
  4. BYTE bTemp[512];
  5. //数组清零
  6. memset(bTemp,0,sizeof(bTemp));

  7. //向设备发送
  8. if (!DeviceIoControl(handle,
  9.        ATST2004_IOCTL_READ,           //根据具体的设备有相关的定义
  10.        NULL,                                              //没有向设备传递的数据,置为NULL
  11.        0,                                                      //没有向设备传递的数据,置为NULL
  12.        bTemp,                                            //读取设备的数据返回地址
  13.        iSize,                                                //读取数据的字节数
  14.        &nOutput,
  15.        NULL)
  16.     )
  17. {
  18.    return false;
  19. }
  20. //放置到公用数组
  21. memcpy(&bData[0],&bTemp[0],iSize);
  22. return true;
  23. }
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

龙马谷| C/C++辅助教程| 安卓逆向安全| 论坛导航| 免责申明|Archiver|
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表龙马谷立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2018-2021 All Right Reserved.
在线客服
快速回复 返回顶部 返回列表