Fast I/O和IRP_笔记

1. IRP and Fast I/O

http://excel.fit.vutbr.cz/submissions/2019/019/19_poster.pdf

Fast I/O和IRP_笔记_第1张图片

2. Minifilter 拦截FileMapping IO事件

https://blog.csdn.net/zj510/article/details/85059638#FileMapping_17

3 文件过滤

https://wenku.baidu.com/view/c1791d596d85ec3a87c24028915f804d2b1687cc.html

Fast I/O和IRP_笔记_第2张图片

4 文件上下文与缓冲处理  -- STOPAT

https://blog.csdn.net/wxyyxc1992/article/details/27842841

Windows操作系统为用户提供了巧妙的缓存机制,即只要一个文件被以缓冲方式打开过,则其内容的全部或者一部分就已经保存在了内存里。一般来说,一个文件无论有多少个进程在访问,都只有一份文件缓冲。一般的应用层的读写请求都是普通的读写请求(不带IRP_PAGING_IO/IRP_SYNCHRONOUS_PAGING_IO/IRP_NOCACHE),这种请求的特点是文件系统会直接调用CcCopyRead和CcCopyWrite函数完成,这两个函数会直接从缓冲中读数据,如果缓冲中没有,才会转换为分页读写请求。而如果系统中已经存在了该文件的文件缓冲,那么应用层的读写请求往往会被转化为Fast IO请求。

    对于IO操作,Irp机制是最基本、默认的处理机制。Irp机制可以用于同步的、异步的、cached或者noncached IO操作。当遇到“缺页中断”时,Memory Manager也会通过发送相应的Irp包给文件系统来处理。 而 FastIO 的设计初衷则是用来处理快速的、同步的、并且“on cached files”的IO操作。当进行 FastIO 操作时,所需处理的数据是直接在用户buffer和系统缓存中进行传输的,而不是通过文件系统和存储器驱动栈(storage driver stack)。事实上存储器驱动并不使用FastIO机制。当需要处理的数据已经存在于系统缓存,则采用FastIO机制的读写操作立刻就可以完成。否则,系统会产生一个缺页中断,这会导致系统发送相应的IRP包来完成用户所需的读写操作。通常发生这种情况(指:所需的数据不在系统缓存的情况)的时候,FastIO函数会返回FALSE,或者一直等到缺页中端响应函数把所需的数据都加载到系统缓存中。(注:如果FastIO处理函数返回FALSE,那么调用者必须自己创建相应Irp来完成所需的处理。

Fast I/O和IRP_笔记_第3张图片

关于文件缓冲的清理本驱动放置在了IRP_MJ_CLEANUP的预操作回调中,首先使用 FltGetFileNameInformation函数获取当前文件绝对路径,然后根据文件名判断是否为机密文件。对于非机密文件,安全起见我们也是默认清除其缓存,而对于机密文件,也是需要强制清除其缓存,但是excel文件是一个特例。如果操作excel文件的缓存,会出发写磁盘的操作而导致部分excel文件的数据被加密,最终使得加密标识被破坏而文件被损坏无法再次打开。

对于文件缓冲清除的具体操作由Cc_ClearFileCache()函数完成,函数声明如下:

VOID Cc_ClearFileCache(

__in PFILE_OBJECT FileObject,

__in BOOLEAN bIsFlushCache,

__in PLARGE_INTEGER FileOffset, 

__in ULONG Length) ;

本函数中,首先需要获取文件对象对应的FCB,即FSRTL_COMMON_FCB_HEADER结构体对象: Fcb = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext ;

然后使用ExAcquireResourceExclusiveLite()函数获取到Fcb->Resource或者 Fcb->PagingIoResource这个资源锁,这里可以使用true循环,可能需要多次操作才能获取到。获取到资源锁之后,依次调用CcFlushCache、MmFlushImageSection、CcPurgeCacheSection这三个函数实现对于缓冲的清除,这一点和传统的文件过滤驱动的方式是一样的。

在实际操作中,如果有用户同时在编辑机密文件的时候不小心使用非机密进程导致文件缓冲被清除,会造成用户的信息流失,整个驱动程序的稳定性与兼容性也不是很好。并且频繁地清除缓冲,也会对系统的性能造成较大的影响。

双缓冲机制

缓冲管理器必需维护每个文件的缓冲信息,这个信息用缓冲位图来维护,对于每个文件,缓冲管理器分配一个共享缓冲位图(Shared Cache Map)结构来保存这个文件和这个文件相关联的其他信息的映射位图。这个共享缓冲位图结构在这个文件缓冲被文件系统驱动或者网络重定向请求初始化的时候分配。此外,共享缓冲位图对每个文件是唯一的,因此只有在首次为文件建立缓冲的时候分配,每次用一个特定的文件对象发出一个初始化缓冲的时候,缓冲管理器就分配一个私有的缓冲位图(Priviate Cache Map)机构。缓冲管理器用这个结构来标记缓冲已使用,其中还包含缓冲管理器用于预读控制的信息和其他的数据。需要特别说明的是,共享缓冲位图结构和私有缓冲位图的结构都是由缓冲管理器分配和维护的。为了创建两个缓冲区,必需利用缓冲管理器向文件系统驱动提供的接口,接口可以分为四类即文件操作接口:用来初始化文件缓冲区,刷新缓冲数据到磁盘,修改文件大小,清除缓冲数据等。

在本驱动程序中,借鉴了Windows WDK中提供的例程:Swap Buffer,即对于同一机密文件而言为机密进程与非机密进程创建了两个缓冲区(非机密进程访问的系统分配的缓冲区,机密进程访问的是我们申请的附加在文件上下文中的缓冲区),并且控制仅有机密进程可以访问明文缓冲区,这部分的具体实现方法的介绍请参照3.6数据加解密模块。
 

5. Word and notepad

https://community.osr.com/profile/discussions/Bryan_G

 

6. 关于Fast I/O和IRP

https://blog.csdn.net/wwwgeyang777/article/details/6914844

NT 下 Fast I/O 是一套 IO MANAGER 与 DEVICE DRIVER 沟通的另外一套 API。在进行基于 IRP 为基础的接口调用前, IO MANAGER 会尝试使用Fast I/O接口来加速各种 IO操作.

Fast I/O is specifically designed for rapid synchronous I/O on cached files. In fast I/O operations, data is transferred directly between user buffers and the system cache, bypassing the file system and the storage driver stack. (Storage drivers do not use fast I/O.) If all of the data to be read from a file is resident in the system cache when a fast I/O read or write request is received, the request is satisfied immediately. Otherwise, a page fault can occur, causing one or more IRPs to be generated. When this happens, the fast I/O routine either returns FALSE, or puts the caller into a wait state until the page fault is processed. If the fast I/O routine returns FALSE, the requested operation failed and the caller must create an IRP.
 

7. Windows文件系统过滤驱动在防病毒方面的应用

http://m.e-works.net.cn/articles/article71754.htm

Fast I/O和IRP_笔记_第4张图片

8. 驱动对象(DRIVER_OBJECT)

https://blog.csdn.net/yourenhello/article/details/17100135

https://blog.csdn.net/wishfly/article/details/90411672

Fast I/O和IRP_笔记_第5张图片

9 Forcing the Cache Manager to release its reference to a File Object

https://community.osr.com/discussion/291055/forcing-the-cache-manager-to-release-its-reference-to-a-file-object

 

10 IRP中的三种缓冲区

https://www.cnblogs.com/LittleHann/p/3450436.html

 

11 关于“IRP_MJ_CREATE ” 的Dispatch中判断FileObject是文件还是目录问题

https://blog.csdn.net/kaylc/article/details/6780238

当Ring3 CreateFile发起对某个文件对象的请求时,如:C:/Program Files/Microsoft Visual Studio/VC98/LIB/LIBC.lib"。请求进入Ring0,Fs会把该请求生成多个IRP_MJ_CREATE,逐层的打开目录对象,直至到目标文件LIBC.lib,所以在
IRP_MJ_CREATE的Dispatch中的IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE可以判断到达目标文件对象前的那些请求,肯定就是目录。

    注意:但在IRP_MJ_CREATE的Dispatch中无法使用IrpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE来判断目标文件对象(LIBC.lib)是文件还是目录,得将IRP传递到底层后,在完成例程中判断目标文件对象是文件还是目录。而上述是因为目标文件前的一定是目录,所以可以判断。
 

12 双缓冲机制的具体实现

https://blog.csdn.net/wxyyxc1992/article/details/27842841

Ⅰ:预回调函数处理

这里以文件的读过程为例说明双缓冲机制及文件解密的具体过程。

首先在IRP_MJ_READ的Pre函数中,分别使用FltGetVolumeContext函数获取到文件对象所属的卷上下文(包含了该文件对象所拥有的加解密密钥)以及Ctx_FindOrCreateStreamContext()函数获取到流上下文。然后会判断读写是否为Fast IO,如果为Fast IO则设置返回状态为FLT_PREOP_DISALLOW_FASTIO,此返回状态在MSDN中的定义如下:

The operation is a fast I/O operation, and the minifilter driver is not allowing the fast I/O path to be used for this operation. The filter manager does not send the fast I/O operation to any minifilter drivers below the caller in the driver stack or to the file system. In this case, the filter manager only calls the post-operation callback routines of the minifilter drivers above the caller in the driver stack.

在过滤了Fast IO和非机密文件的IRP请求之后,我们会为机密文件的IRP请求申请新的内存空间用于存放解密之后的明文信息。最后申请属于该IRP的MDL空间并通过PPRE_2_POST_CONTEXT结构体传递到Post函数中。在这里要注意一点,在修改了回调数据包Data之后务必调用FltSetCallbackDataDirty()函数通知系统对于回调数据包做的修改。

Ⅱ:后回调函数处理

当文件磁盘驱动完成对于文件内容的分页读写之后,会自动将数据传入到IRP_MJ_READ的后回调函数之中。

在Post函数的处理中,我们首先要获取到系统分配的缓冲区,鉴于系统会采取三种方式(缓冲区读写、直接读写与其他方式读写)进行内存读写,要进行不同的判断。

首先使用 MmGetSystemAddressForMdlSafe( iopb->Parameters.Read.MdlAddress, NormalPagePriority )函数尝试获取到系统分配的MDL的缓冲区地址,如果不存在,则对回调数据包的Flags1进行判断,如果Flags中存在 FLTFL_CALLBACK_DATA_SYSTEM_BUFFER或者

FLTFL_CALLBACK_DATA_FAST_IO_OPERATION则说明系统使用缓冲区读写的方式,那么可以直接从iopb->Parameters.Read.ReadBuffer中获取到系统分配的缓冲区地址。

如果系统不是用的上述两种读写方式,那么说明系统使用的是其他方式读写,此时在DPC的中断级别下是无法获取到正确的缓冲区地址,需要更改我们的IRQL;

此时使用fltKernel中提供的API:

FltDoCompletionProcessingWhenSafe( Data,

                                FltObjects,

                                CompletionContext,

                                Flags,

                                PostReadWhenSafe,

                                &FltStatus )

其中PostReadWhenSafe是我们定义的回调函数,该回调函数执行的中断级别就是我们所需要的安全的中断级别。

此时我们已经获取到了系统分配的缓冲区地址,换言之,即是系统分配的应用程序的内存地址,而我们真实的明文数据存放在p2pCtx->SwappedBuffer中。在Post函数的最后,我们调用RtlCopyMemory函数将明文数据复制到用户的内存空间,至此完成了对于机密进程的数据读取功能。
 

13 IRP_MJ_DIRECTORY_CONTROL

13.1 IRP_MJ_DIRECTORY_CONTROL是怎么回事? 

http://bbs3.driverdevelop.com/read.php?tid=109756

  //  IRP_MJ_DIRECTORY_CONTROL
    //
 
    union {
 
        //
        //  IRP_MN_QUERY_DIRECTORY or IRP_MN_QUERY_OLE_DIRECTORY
        //
 
        struct {
            ULONG Length;
            PUNICODE_STRING FileName;
            FILE_INFORMATION_CLASS FileInformationClass;
            ULONG POINTER_ALIGNMENT FileIndex;
 
            PVOID DirectoryBuffer;  //Not in IO_STACK_LOCATION parameters list
            PMDL MdlAddress;        //Mdl address for the buffer  (maybe NULL)
        } QueryDirectory;
 
        //
        //  IRP_MN_NOTIFY_CHANGE_DIRECTORY
        //
 
        struct {
            ULONG Length;
            ULONG POINTER_ALIGNMENT CompletionFilter;
 
            //
            // These spares ensure that the offset of DirectoryBuffer is
            // exactly the same as that for QueryDirectory minor code. This
            // needs to be the same because filter manager code makes the assumption
            // they are the same
            //
 
            ULONG POINTER_ALIGNMENT Spare1;
            ULONG POINTER_ALIGNMENT Spare2;
 
            PVOID DirectoryBuffer;  //Not in IO_STACK_LOCATION parameters list
            PMDL MdlAddress;        //Mdl address for the buffer  (maybe NULL)
        } NotifyDirectory;
 
    } DirectoryControl;
 


  
13.2 Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer

https://community.osr.com/discussion/132007

you are type casting wrong member. you should verify first that which type of buffer is this (compare Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass) and than typecast

Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer

to that type structure.

13.3 DirectoryBuffer

https://community.osr.com/discussion/59370

pData = Buffer; // User Buffer
pInfo= (PFILE_BOTH_DIR_INFORMATION)pData;
 
while (TRUE && pInfo!=NULL)
{ 
//(%C, %S, %lc, %ls, %wc, %ws, %wZ) 
DbgPrint    ("\n\tINQUESTFSD @ FatQueryDirectory->ADDRESS ---- pInfo %08lx",pInfo);
DbgPrint("\n\tINQUESTFSD @ FatQueryDirectory->END END Name = %ws",pInfo->FileName);
 
if (pInfo->NextEntryOffset == 0 )
break;
// Increment the variables
pData += pInfo->NextEntryOffset;
pInfo = (PFILE_BOTH_DIR_INFORMATION) pData;
Count++;
}


14 麦洛克菲内核开发第八课

https://max.book118.com/html/2016/1223/76159509.shtm

Mini filter安装 -  info和动态加载

 

15. 深入理解IRP的完成机制

http://www.feiker.cn/index.php?option=com_zoo&task=item&item_id=8&Itemid=110

 

16. 深入理解IRP概念、传递流程与完成函数

http://www.feiker.cn/index.php?option=com_zoo&task=item&item_id=9&Itemid=110

你可能感兴趣的:(研发管理)