Ring3/Ring0的四种通信方式

21.1.6  Ring3/Ring0的四种通信方式

21.1.5节中提到了Ring3/Ring0通信的四种内存访问方式分别为:METHOD_BUFFERED、METHOD_IN_DIRECT、METHOD_OUT_DIRECT和METHOD_NEITHER。

METHOD_BUFFERED可称为"缓冲方式",是指Ring3指定的输入、输出缓冲区的内存读和写都是经过系统的"缓冲",具体过程如图21.1.12所示。

这种方式下,首先系统会将Ring3下指定的输入缓冲区(UserInputBuffer)数据,按指定的输入长度(InputBufferLen)复制到Ring0中事先分配好的缓冲内存(SystemBuffer,通过pIrp->AssociatedIrp.SystemBuffer得到)中。驱动程序就可以将SystemBuffer视为输入数据进行读取,当然也可以将SystemBuffer视为输出数据的缓冲区,也就是说SystemBuffer既可以读也可以写。驱动程序处理完后,系统会按照pIrp->IoStatus->Information指定的字节数,将SystemBuffer上的数据复制到Ring3指定的输出缓冲区(UserOutputBuffer)中。可见这个过程是比较安全的,避免了驱动程序在内核态直接操作用户态内存地址的问题,这种方式是推荐使用的方式。

METHOD_NEITHER可称为"其他方式",这种方式与METHOD_BUFFERED方式正好相反。METHOD_BUFFERED方式相当于对Ring3的输入输出都进行了缓冲,而METHOD_ NEITHER方式是不进行缓冲的,在驱动中可以直接使用Ring3的输入输出内存地址,如图21.1.13所示。

驱动程序可以通过pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer得到Ring3的输入缓冲区地址(其中pIrpStack是IoGetCurrentIrpStackLocation(pIrp)的返回);通过pIrp-> UserBuffer得到Ring3的输出缓冲区地址。

由于METHOD_NEITHER方式并不安全,因此最好对Type3InputBuffer读取之前使用ProbeForRead函数进行探测,对UserBuffer写入之前使用ProbeForWrite函数进行探测,当没有发生异常时,再进行读取和写入操作。

METHOD_IN_DIRECT和METHOD_OUT_DIRECT可称为"直接方式",是指系统依然对Ring3的输入缓冲区进行缓冲,但是对Ring3的输出缓冲区并没有缓冲,而是在内核中进行了锁定。这样Ring3输出缓冲区在驱动程序完成I/O请求之前,都是无法访问的,从一定程度上保障了安全性。如图21.1.14所示。

这两种方式,对于Ring3的输入缓冲区和METHOD_BUFFERED方式是一致的。对于Ring3的输出缓冲区,首先由系统锁定,并使用pIrp->MdlAddress来描述这段内存,驱动程序需要使用MmGetSystemAddressForMdlSafe函数将这段内存映射到内核内存地址(OutputBuffer),然后可以直接写入OutputBuffer地址,最终在驱动派遣例程返回后,由系统解除这段内存的锁定。

METHOD_IN_DIRECT和METHOD_OUT_DIRECT方式的区别,仅在于打开设备的权限上,当以只读权限打开设备时,METHOD_IN_DIRECT方式的IoControl将会成功,而METHOD_OUT_DIRECT方式将会失败。如果以读写权限打开设备,两种方式都会成功。

 

posted @ 2012-11-29 21:11  legendmaner  阅读(1247)  评论(0)    收藏  举报