应用程序与驱动程序6种通信方式

应用程序与驱动程序6种通信方式   

---来源于互联网,交流学习--- 

       应用程序与驱动程序通信方式据我所知,细分可以分6种,ReadFile,WirteFile方式的缓冲区设备读写,直接方式读写,和其他方式读写。Io设备控制操作(即 DeviceControl)的缓冲内存模式IOCTL,直接内存方式的IOCTL,其他内存方式的IOCTL!当然还有一种就是创建文件,然后文件读写也应该算是一种通信吧,这里不讨论这个!

下面是方式都是用ReadFile,WirteFile设备控制操作的方法基本上与上面3中相对应!

1、缓冲区方式设备读写:

在创建Device后,须要指定方式为Device的Flags有 DO_BUFFERED_IO!通过应用层Api函数ReadFile,WriteFile,等函数,ntoskrnl.exe创建Irp 后,ReadFile和WriteFile参数的缓冲区就在irp->AssociatedIrp.Systembuffer,同时要求读写的偏移量,和长度都在PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp) 数据类型中的 stack->Parameters.Read.Length,stack->Parameters.Read.ByteOffset(该类型为Large_Interge类型),

2、直接方式读写

在创建Device后,须要指定方式为Device的Flags有 DO_DIRECT_IO!通过应用层APi函数ReadFile,WriteFile等函数,ntoskrnl.exe创建的Irp 后,ReadFile和WriteFile参数的缓冲区将被锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍,这样应用层的缓冲区和内存层的就指向同一个物理内存!而内核模式用MDL数据结构记录这段内存,这个虚拟内存大小在 MmGetByteCount(pIrp->MdlAddress),首地址在 MmGetMdlVirtualAddress(pIrp->MdlAddress);偏移量为 MmGetMdlByteOffset(pIrp->MdlAddress)(这里的偏移量不是文件读写的偏移量,而是在MDL中的偏移量)然后文件的长度还是stack->Parameters.Read.Length,这个值和 MmGetByteCount(pIrp->MdlAddress)是一样的,要不然就出错了,而真正的读写偏移量还是在 stack->Parameters.Read.ByteOffset!这里无论是读还是写,都要得到MDL在内核模式下的映射,因此还要用 MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority)将其转化为内核模式,然后可以读写该地址,就会转化到应用层相应的内存!!

3、其他方式读写

这种方式很少用到,在创建Device后,Flags既不标志 DO_BUFFERED_IO也不标志DO_DIRECT_IO,ReadFile和WriteFile提供的缓冲区内存地址,可以再IRP的 pIrp->UserBuffer字段得到,而长度和偏移量还是在stack->Paameters.Read中,但是用这种方法须要注意的是ReadFile可能把空指针地址或者非法地址传递给驱动程序,因此驱动程序使用用户模式地址钱须要检查是否可读或者可写,可以用 ProbeForWrite或者ProbeForWrite函数和try模块。

这里有个问题困扰着我,就是应用层用GetFileSize函数时用第一种方法处理该Irp时结果是正确的,就是冲pIrp->AssociatedIrp.SystemBuffer;得到 PFILE_STANDARD_INFORMATION结构指针,然后讲该结构的EndOfFile设置为你自己文件的长度,然后结束该 IRP,GetFileSize就能得到正确的文件长度,但是用方法三就是的时候用GetFileSize,我同样用 pIrp->UserBufer得到PFILE_STANDARD_INFORMATION结构指针,然后设置后,在GetFileSize里面去得不到正确的长度!!这个是为什么?还有就是该Irp的CurrentStackLocation-stack,该字段里面的 stack->Parameters.QueryFile.Length指的是什么,显示的都是24,无论文长度为多少,还是用哪种方法都市24,很郁闷!!!

下面是方式都是用IO设备控制操作的方法基本上与上面3中相对应!

对于IO设备控制操作,不知道为什么可以用设置DO_DIRECT_IO后就能对三种方式都适用,而且stack->Parameters.Read.Length/Write.Length 都是对应应用层的DeviceIoControl函数中的第6个参数也就是输出缓冲区!DeviceIoControl函数的输入输出缓冲区长度都再 stack->Parameters.DeviceioControl.InputBufferLength/OutputBufferLength 中

4、缓冲内存IOCTL,在DeviceIoControl函数第二个参数的时候,使用CTL_CODE来产生该常数,其中Method字段设置为METHOD_BUFFERED,在内核模式中输入缓冲区很输出缓冲区都为 pIrp->AssociatedIrp.SystemBuffer,

5、直接方式IOCTL,在DeviceIoControl函数第二个参数的时候,使用CTL_CODE来产生该常数,其中Method字段设置为METHOD_IN_DIRECT/METHOD_OUT_DIRECT(最好使用第一个,因为第一个对所有的打开设备方式都通用)!对于第4中的区别是输入缓冲区还在pIrp->AssocatedIrp.Systembuffer 中,但是输出缓冲区却是pIrp->MdlAddress,因此在内核对输出的写应该写在 MmGetSystemAddressForMdlSafe(pIrp->MdlAddress)中,

6、其他方式IOCTL,在DeviceIoControl函数第二个参数的时候,使用CTL_CODE来产生该常数,其中Method字段设置为MEHTOD_NEITHER,输入缓冲区为 stack->Parameters.DeviceIoControl.Tyep3InputBuffer;输出缓冲区为 pIrp->Userbuffer

发布了19 篇原创文章 · 获赞 34 · 访问量 94万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览