zoukankan      html  css  js  c++  java
  • 应用层与内核的几种通信方式

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

    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

  • 相关阅读:
    python中的编码问题
    CVPR2018 Tutorial 之 Visual Recognition and Beyond
    hdu 1376 Octal Fractions
    hdu 1329 Hanoi Tower Troubles Again!
    hdu 1309 Loansome Car Buyer
    hdu 1333 Smith Numbers
    hdu 1288 Hat's Tea
    hdu 1284 钱币兑换问题
    hdu 1275 两车追及或相遇问题
    hdu 1270 小希的数表
  • 原文地址:https://www.cnblogs.com/endenvor/p/9057856.html
Copyright © 2011-2022 走看看