Minifilter 拦截FileMapping IO事件
Posted zj510
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Minifilter 拦截FileMapping IO事件相关的知识,希望对你有一定的参考价值。
Minifilter 拦截FileMapping IO事件
IO类型
在Windows上一般常见的两种IO:
- 普通IO, 如通过ReadFile,WriteFile等Windows API进行读写
- FileMapping,通过CreateFile打开一个文件,然后通过CreateFileMapping创建FileMapping对象,通过MapViewOfFile映射,之后就像操作内存一样(memcpy, strcpy等等),这些数据的变更会被操作系统同步到对应的文件上。
Minifilter拦截
针对IO类型的(1),其实,绝大多数人都会在minifilter中拦截,因为很简单,只需要拦截IRP_MJ_WRITE/IRP_MJ_READ就可以了。如下。
IRP_MJ_WRITE,
0,
PreWrite,
PostWrite
每当应用程序调用WriteFile的时候,这两个函数都会进来,然后里面可以做一些过滤,阻断,加密等等。
但是对于(2),FileMapping,可能会有一些迷惑。
FileMapping拦截
比如应用程序这样写文件:
void TestIOFileMapping()
HANDLE hFile;
hFile = CreateFile(L"testfilemapping.foo",
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
// CREATE_ALWAYS,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return;
HANDLE hMapping = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,
MAX_FILESIZE,
NULL);
if (hMapping == NULL)
CloseHandle(hFile);
return;
char* puchData = (char*)MapViewOfFile(hMapping,
FILE_MAP_WRITE,
0,
0,
0);
if (puchData == NULL)
CloseHandle(hMapping);
CloseHandle(hFile);
return;
for (int i = 0; i < 10; i++)
memset(puchData + i * 1024, 0x41 + i, 1024);
UnmapViewOfFile(puchData);
// FlushFileBuffers(hFile);
CloseHandle(hMapping);
CloseHandle(hFile);
那么很可能在不同的操作系统上会得到不同的结果。基本分这么几类:
- IRP_MJ_WRITE的对应函数(比如PreWrite),直接就被调用,然后进程号就是当前应用。
- PreWrite很快被调用,但是发现进程号是System进程的,也就是4号
- PreWrite过了好长一会才被调用,进程号是System进程的,也就是4号
- PreWrite一直都没有被调用
其实这里有个有趣的问题:
我们在上面的测试代码里面把FlushFileBuffers(hFile);给禁用了。
那么得到的结果就取决于操作系统了。
上面四种情况都有可能发生。对于第四种,其实,操作系统会在关机前把内容写入磁盘(只是你不容易看到)
针对FileMapping,当应用层调用了memset或者strcpy之类的操作内存后,这些内容变更什么时候反映到磁盘(不调用FlushFilebuffers),是由操作系统决定的。
但是有一点是肯定的,就是内容要写入磁盘,一定会经过IRP, 也就是PreWrite一定会被调用。只是时间点有操作系统决定
那么如果我们把 FlushFileBuffers(hFile);打开,那么基本就是第一种情况了,也就是IRP马上被调用,因为应用程序要立即把内容flush到磁盘。
其实,当我们编写FileMapping代码的时候,是需要调用FlushFileBuffers的,不然,假如突然断电,就有可能丢失内容(还没写入磁盘)。只是很多人会遗漏,然后大多数情况,也确实不会有问题。
结论
无论是ReadFile,WriteFile等常规IO手段,还是FileMapping,IRP事件一定有,只是FileMapping可能会有一点点迷惑,因为在没有调用FlushFileBuffers的时候,有时看到的情况不太一样。但是数据要写入磁盘,IRP一定有。
附:
HANDLE hMapping = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,
MAX_FILESIZE,
NULL);
这个调用会触发一个IRP:
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
0,
AcquireForSectionSynchronization,
PostAcquireForSectionSynchronization
这里有时也可以做一些事情,比如查看索要的权限等等。
那么在IRP_MJ_WRITE里面怎么获取当前IRP操作文件的文件名呢?这个对于WriteFile和FileMapping还有一些不一样,后面再讲吧。
以上是关于Minifilter 拦截FileMapping IO事件的主要内容,如果未能解决你的问题,请参考以下文章