24、Windows派遣函数(2)Windows驱动开发详解笔记,直接读写方式

摘要:
MmGetMdlByteCount宏返回给定NDL记录的缓冲区字节长度。http://msdn.microsoft.com/en-us/library/ff554530%28VS.85%29.aspxReadFile的第三个参数是所需的读取长度,它等于stack-˃Parameters。阅读长调度函数设置pRrp-˃IoStatus信息告诉ReadFile实际读取了多少字节,对应于第四个参数=UlReadLength)26{27//MDL的长度应等于读取的长度,否则操作应设置为不成功28pIp-˃IoStatus。信息=0;29status=STATUS_unsuccessful;30}else31{32//在内核模式33PVOIDkernel_address=MmGetSystemAddressForMdlSafe;34KdPrint;35memset;36pIrp-˃IoStatus.Information=ulReadLength;//bytesxfer ed37}3839pIrp-˃IoStatus Status=Status;4041完成请求;42Kd打印;4344返回状态;45}462.设备IoControl功能向指定的设备驱动程序发送控制代码,使响应设备执行响应操作以读取和写入,并在应用程序和驱动程序之间进行通信。需要输入/输出控制代码。DeviceIoControl将此控制代码和请求传递给驱动程序,并在调度功能中处理不同的I/O控制代码。DeviceIoControl通过第七个参数获得此字节数。

 

1、直接读写方式

操作系统将用户模式下的缓冲区锁住,然后操作系统将这段缓冲区在内核模式地址再映射一遍。这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理地址。

操作系统将用户模式的地址锁定后,用内存描述符MDL记录这段内存。

wps_clip_image-25695

MDL 示意图

比如mdl->ByteCount就是记录的虚拟内存的大小。可以用几个宏来得到其值。

The MmGetMdlByteCount macro returns the length in bytes of the buffer described by a given MDL.

http://msdn.microsoft.com/en-us/library/ff554530%28VS.85%29.aspx

ReadFile的第三个参数为希望读的长度,等于stack->Parameters.Read.Length.派遣函数设置pRrp->IoStatus.Infomation告诉ReadFile实际读了多少字节,对应第四个参数。

pIrp->MdlAddress记录了MDL数据结构

示例代码 P206

24、Windows派遣函数(2)Windows驱动开发详解笔记,直接读写方式第2张24、Windows派遣函数(2)Windows驱动开发详解笔记,直接读写方式第3张代码
1 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
2 IN PIRP pIrp)
3 {
4 KdPrint(("Enter HelloDDKRead\n"));
5 //扩展设备
6   PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
7 NTSTATUS status = STATUS_SUCCESS;
8 //当前I/O堆栈
9   PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
10 //获取指定的的读字节数
11   ULONG ulReadLength = stack->Parameters.Read.Length;
12 KdPrint(("ulReadLength:%d\n",ulReadLength));
13
14 //得到锁到的缓冲区的长度
15   ULONG mdl_length = MmGetMdlByteCount(pIrp->MdlAddress);
16 //得到锁到的缓冲区的首地址
17   PVOID mdl_address = MmGetMdlVirtualAddress(pIrp->MdlAddress);
18 //得到锁到的缓冲区的偏移量
19 ULONG mdl_offset = MmGetMdlByteOffset(pIrp->MdlAddress);
20
21 KdPrint(("mdl_address:0X%08X\n",mdl_address));
22 KdPrint(("mdl_length:%d\n",mdl_length));
23 KdPrint(("mdl_offset:%d\n",mdl_offset));
24
25 if (mdl_length!=ulReadLength)
26 {
27 //MDL的长度应该和读长度相等,否则该操作应该设为不成功
28 pIrp->IoStatus.Information = 0;
29 status = STATUS_UNSUCCESSFUL;
30 }else
31 {
32 //用MmGetSystemAddressForMdlSafe得到MDL在内核模式下的映射
33 PVOID kernel_address = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
34 KdPrint(("kernel_address:0X%08X\n",kernel_address));
35 memset(kernel_address,0XAA,ulReadLength);
36 pIrp->IoStatus.Information = ulReadLength; // bytes xfered
37 }
38
39 pIrp->IoStatus.Status = status;
40
41 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
42 KdPrint(("Leave HelloDDKRead\n"));
43
44 return status;
45 }
46
2IO设备控制操作

The DeviceIoControl function sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation.

来进行读写,及应用程序与驱动间的通信。需要一个I/O控制码,DeviceIoControl 把这个控制码和请求一起传递给驱动程序,在派遣函数中分别对不同I/O控制码进行处理。

DeviceIoControl->lpBytesReturned 对应着IRP中的pIrp->IoStatus.Infomation.

wps_clip_image-23998

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

派遣函数读取pIrp->Associate.SystemBuffer内存地址,从而获取应用程序提供的输入数据。派遣函数还可以写入pIrp->Associate.SystemBuffer的内存地址,这被当作设备输出数据。系统会把这个地址的数据再次复制到DeviceIoControl提供的缓冲区。复制的字节由pIrp->IoStatus.Infomation指定。DeviceIoControl通过第7个参数得到这个字节数。

示例代码 P211

24、Windows派遣函数(2)Windows驱动开发详解笔记,直接读写方式第5张24、Windows派遣函数(2)Windows驱动开发详解笔记,直接读写方式第6张代码
1 #pragma PAGEDCODE
2 NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
3 IN PIRP pIrp)
4 {
5 NTSTATUS status = STATUS_SUCCESS;
6 KdPrint(("Enter HelloDDKDeviceIOControl\n"));
7
8 //得到当前堆栈
9 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
10 //得到输入缓冲区大小
11 ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
12 //得到输出缓冲区大小
13 ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
14 //得到IOCTL码
15 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
16
17 ULONG info = 0;
18
19 switch (code)
20 { // process request
21 case IOCTL_TEST1:
22 {
23 KdPrint(("IOCTL_TEST1\n"));
24 //缓冲区方式IOCTL
25 //显示输入缓冲区数据
26 UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
27 for (ULONG i=0;i<cbin;i++)
28 {
29 KdPrint(("%X\n",InputBuffer[i]));
30 }
31
32 //操作输出缓冲区
33 UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
34 memset(OutputBuffer,0xAA,cbout);
35 //设置实际操作输出缓冲区长度
36 info = cbout;
37 break;
38 }
39 case IOCTL_TEST2:
40 {
41 KdPrint(("IOCTL_TEST2\n"));
42 //缓冲区方式IOCTL
43 //显示输入缓冲区数据
44
45 //缓冲区方式IOCTL
46 //显示输入缓冲区数据
47 UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
48 for (ULONG i=0;i<cbin;i++)
49 {
50 KdPrint(("%X\n",InputBuffer[i]));
51 }
52
53 //pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
54 KdPrint(("User Address:0X%08X\n",MmGetMdlVirtualAddress(pIrp->MdlAddress)));
55
56 UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
57 //InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间
58 memset(OutputBuffer,0xAA,cbout);
59 //设置实际操作输出缓冲区长度
60 info = cbout;
61 break;
62 }
63 case IOCTL_TEST3:
64 {
65 KdPrint(("IOCTL_TEST3\n"));
66 //缓冲区方式IOCTL
67
68 //缓冲区方式IOCTL
69 //显示输入缓冲区数据
70 UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
71 KdPrint(("UserInputBuffer:0X%0X\n",UserInputBuffer));
72
73 //得到用户模式地址
74 PVOID UserOutputBuffer = pIrp->UserBuffer;
75
76 KdPrint(("UserOutputBuffer:0X%0X\n",UserOutputBuffer));
77
78 __try
79 {
80 KdPrint(("Enter __try block\n"));
81
82 //判断指针是否可读
83 ProbeForRead(UserInputBuffer,cbin,4);
84 //显示输入缓冲区内容
85 for (ULONG i=0;i<cbin;i++)
86 {
87 KdPrint(("%X\n",UserInputBuffer[i]));
88 }
89
90 //判断指针是否可写
91 ProbeForWrite(UserOutputBuffer,cbout,4);
92
93 //操作输出缓冲区
94 memset(UserOutputBuffer,0xAA,cbout);
95
96 //由于在上面引发异常,所以以后语句不会被执行!
97 info = cbout;
98
99 KdPrint(("Leave __try block\n"));
100 }
101 __except(EXCEPTION_EXECUTE_HANDLER)
102 {
103 KdPrint(("Catch the exception\n"));
104 KdPrint(("The program will keep going\n"));
105 status = STATUS_UNSUCCESSFUL;
106 }
107
108 info = cbout;
109 break;
110 }
111
112 default:
113 status = STATUS_INVALID_VARIANT;
114 }
115
116 // 完成IRP
117 pIrp->IoStatus.Status = status;
118 pIrp->IoStatus.Information = info; // bytes xfered
119 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
120
121 KdPrint(("Leave HelloDDKDeviceIOControl\n"));
122
123 return status;
124 }
参考

[1]驱动详解

免责声明:文章转载自《24、Windows派遣函数(2)Windows驱动开发详解笔记,直接读写方式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇开源倾情奉献:基于.NET打造IP智能网络视频监控系统(四)服务端介绍‘ActiveX component can’t create object解决方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

驱动开发之 用DeviceIoControl实现应用程序与驱动程序通信

Ring3测试程序:http://blog.csdn.net/zj510/article/details/8216321 1.readfile和writefile可以实现应用程序与驱动程序通信,另外一个Win32 API 是DeviceIoControl。 应用程序自定义一中IO控制码,然后调用DeviceIoControl函数,IO管理器会产生一个Maj...

ip黑白名单防火墙frdev的原理与实现

汤之盘铭曰 苟日新 日日新 又日新 康诰曰 作新民 诗曰 周虽旧邦 其命维新 是故 君子无所不用其极                           ——礼记·大学 在上一篇文章《DDoS攻防战 (二) :CC攻击工具实现与防御理论》中,笔者阐述了一个防御状态机,它可用来抵御来自应用层的DDoS攻击,但是该状态机依赖一个能应对大量条目快速增删的ip黑白...

V4L2驱动的移植与应用(一)

V4L2(video for linux) 可以支持多种设备,它可以有以下5种接口: 1、视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.下面也是着重讲解这种应用; 2、视频输出接口(video output interface):可以驱动计算机的外围视频图像设备...

Android之 MTP框架和流程分析

概要 本文的目的是介绍Android系统中MTP的一些相关知识。主要的内容包括:第1部分 MTP简介对Mtp协议进行简单的介绍。第2部分 MTP框架介绍Android系统下MTP的框架。第3部分 MTP启动流程详细分析MTP服务的启动流程,包括Java层, JNI层, kernel相关知识的介绍。第4部分 MTP协议之I->R流程以"PC中打开一个M...

MDL

1 先是mdl的数据结构。 2 下面根据用法逐步的讲解mdl数据结构的含义:一般用法,先是 IoAllocateMdl :原型为: 最常用的是VirtualAddress和Length。把自己的NonPageable buffer的起始地址传给IoAllocateMdl ,长度也传给他。可是这个函数具体做了啥呢(下面只是些基本的影响理解的部分,具体更多的...

Simulink仿真入门到精通(八) M语言对Simulink模型的自动化操作及配置

8.1 M语言控制模型的仿真 M语言与Simulink结合的方式: 在Simulink模型或模块中使用回调函数 在M语言中调用与模型相关的命令,控制模型的建立,设置模块的属性,增删信号线,以及运行模型仿真等 为了调用和操作Simulink模型,M语言中最常用的函数有sim、set_param、get_param。 8.1.1 sim控制模型仿真及参数配...