原文链接
http://www.m5home.com/bbs/thread-5302-4-1.html
文件在读入到内存之前,终归是要经过IRP_MJ_READ的,当打开需要的文件时候,会有IRP_MJ_CREATE,你双击的时候,也是先产生IRP_MJ_CREATE再产生IRP_MJ_WRITE的。会有一个IRP_MJ_READ发送给NTFS驱动。以下的流程是:
NTFS!NtfsFsdRead ->NTFS!NtfsCommonRead-> CcInitializeCacheMap->CcCopyRead。在CcInitializeCacheMap时候,就映射进了内存了。
当有别的程序先于你的驱动打开了这个文件的时候,这个文件就会保存在内存里了。这个时候,我们自然就捕捉不到IRP_MJ_READ操作了。
当对文件进行修改后,文件在内存中被修改,然后这是缓冲管理器会有一个延迟写的技术,把修改后的文件保存在备用列表或者修改列表中,这取决于文件是否被改,最后再由一个系统线程写入硬盘。
当文件要写入硬盘的时候,一定要经过IRP_MJ_WRITE的。
所以,我们只要解决文件的内存映像就可以了。
有关于内存映像的结构在_file_object里面。具体如下:
可捕捉到IRP_MJ_CREATE的,再从中导出_File_object,从而判断是否是你保护的文件,然后再判断是否是可信进程,再从下面SharedCacheMap 那行做文章,更可以把irp和_io_stack_location中的file_object给换掉,换成别的文件的。
d> dt _file_object
nt!_FILE_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Vpb : Ptr32 _VPB
+0x00c FsContext : Ptr32 Void
+0x010 FsContext2 : Ptr32 Void
+0x014 SectionObjectPointer : Ptr32 _SECTION_OBJECT_POINTERS
+0x018 PrivateCacheMap : Ptr32 Void //用来控制预读等操作的。dt _private_cache_map
kd> dt _SECTION_OBJECT_POINTERS
nt!_SECTION_OBJECT_POINTERS
+0x000 DataSectionObject : Ptr32 Void //数据的内存信息,PTE之类的。dt _control_area
+0x004 SharedCacheMap : Ptr32 Void //就是这个啦~本文件相关的Cache信息。dt _share_cache_map
+0x008 ImageSectionObject : Ptr32 Void //运行程序的映像。这个是什么结构笔者不知道。
再提供一个清缓存的函数:CcFlushCache。
再提供一份清空磁盘缓存的代码:
HANDLE hFile = CreateFile("\\\\.\\X:", GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
如果说过滤驱动不能捕捉到read操作的话,可用dispatch hook ntfs的方法,可以在每次记事本打开txt文件的时候,即使是在加载驱动前,还用了一次记事本打开,并不关闭的前提下,都可以捕捉到read操作。
堆栈如下:
00 f7981c40 fa03056e f7981c6c 818e61e8 00160014 nt!DbgBreakPoint (FPO: [0,0,0])
01 f7981c6c 804eefe3 81bc33c0 818fae70 806d12d0 ntfs_create!fake_create_dispatch+0xbe (FPO: [Non-Fpo]) (CONV: stdcall) ---------->我用Dispatch hook后的fake read例程,不是create
02 f7981c7c 80574dce 818fafb8 818fae70 818e61b8 nt!IopfCallDriver+0x31 (FPO: [0,0,0])
03 f7981c90 80571e16 81bc33c0 818fae70 818e61b8 nt!IopSynchronousServiceTail+0x60 (FPO: [7,0,4])
04 f7981d38 8053da28 000000e4 00000000 00000000 nt!NtReadFile+0x580 (FPO: [Non-Fpo])
05 f7981d38 7c92eb94 000000e4 00000000 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f7981d64)
想必是nt!IopSynchronousServiceTail或者IopfCallDriver中把过滤驱动跳过了吧~