[/b][note]NTFSI--the NT Cache Manager相关(1)
+++++++++++++++++++++++++++++++++++
+   sudami [xiao_rui_119@163.com] +
+   2007.12.02                        +
+   英文翻译&学习笔记                  +
+++++++++++++++++++++++++++++++++++

IDA还没有去熟悉,连分析IDB都不会.看到那些大牛们逆向的代码,很是羡慕.于是先得打好基础.切入主题---
NTFSI这书的相当不错[可惜只有英文电子版].偶先看第6、7、8章,纪录一些关于cache Manager的学习笔记.共勉之 
------------------------------------------------------------------------------------------------------------------------------------
the NT cache Manager 和 Virtual Memory ManagerI/O Manager 、File System Driver联系密切.

它主要是加速数据的读出和写入.将2级存储设备上的(硬盘什么的)的部分数据缓存在内存中[System Cache]----预先将磁盘的部分内容读进内存,避免用户等待; 延迟写入磁盘.

(1)文件流 [File Streams]

任何打开的文件都一个相对应的文件对象[File Object],
任何线状的、细长的与文件对象相关的数据流被定义为文件流(理解的可能不准确). 对每个文件流的存储通过内存映射[memory mapping],文件系统提供缓存非缓存的权限.

(2)虚拟块存储 [Virtual Block Caching]

说的主要是文件内存映射, MS"操作系统"还有"WINDOWS核心编程"的书都有详细的介绍. 
原来的一些操作系统直接是操作物理地址----在进行文件操作前首先会将虚拟地址转换成物理地址[内存中的实际地址],如果有多的物理地址,操作才会继续进行; 而the NT cache Manager会利用内存映射,不会在意实际的物理内存是否够能够拥有,而是
only use virtual byte offsets in a file to keep track of cached information
,一份数据保存在真正的物理内存中,映射多份到进程的地址空间,利于同步操作. 对于某个进程修改的数据,它会单独复制一个页出来,保存修改的数据,到最后才延迟写入磁盘。

(3)读操作 [Cached Read Operation]

用户进程发出一个"读"请求被kernel层的I/O Manager知晓---->它产生IRP发送至File System Driver, 用户进程的一些数据有3种方式被保存:
映射到系统的高2GB内存空间、运用Memory Descriptor List(MDL)、直接传下去,不用拷贝数据
---->File System Driver接收到IRP,意识到此IRP有文件的打开读取权限.于是检查此文件"缓存"[caching]是否已经初始化,如果没有,调用the cache Manager来初始化,而它会调用Virtual Memory Manager来创建文件映射[section object]来缓存文件---->File System Driver调用 CcCopyRead() 函数把IRP传递给the cache Manager,,现在它有责任把磁盘上的数据拷贝到用户的buffer中---->the cache Manager检查包含用户请求的文件数据是否已经映射了,如果没有则创建之,然后仅仅是把映射的文件数据拷贝到用户的buffer中---->如果产生了缺页中断[page fault],权限移交给Virtual Memory Manager,它产生一个noncachedpaging IRP,此IRP经过 NT I/O Manager 到达File System Driver,然后它产生一个相应的IRP向底层的设备驱动传递,底层的设备从磁盘获得数据后完成请求---->然后the cache Manager继续拷贝数据到用户的buffer. copy完后把控制权限交给File System Driver---->File System Driver完成此IRP请求,返回到I/O Manager----> I/O Manager完成操作后返回到用户进程.结束 

名称:  Snap2.gif
查看次数: 136
文件大小:  128.5 KB

(4) 写操作 [Cached Write Operation]
和上面的差不多,只不过是用户的buffer中开始就包含着大量的数据,Cache Manager从buffer中拷贝数据到映射中,产生缺页中断时,虚拟内存管理器不会向别处发IRP了,而是释放掉部分的物理内存,用于此.

名称:  Snap3.gif
查看次数: 134
文件大小:  194.3 KB

(5) 存储管理器的交互 [Interfaces] [翻译有误,偶也不知道翻译成什么 ]

系统组建可以调用 Cache Manager的许多交互接口:

┎文件流控制函数 [file stream manipulation functions]
┎复制接口 [the copy inerface]
┎MDL接口 [the MDL interface]
┎锁定操作 [the pinning inerface]

the copy inerface是最简单的一个操作,可以在内存和the cache file stream之间任意复制数据
the MDL interface是一种不透明的方式, 它通过DMA得到the system cache的直接访问权限
the pinning inerface可以完成2个任务 ----
┎ Map data into the system cache for direct access using a buffer pointer
┎ Pin (or lock) the physical pages that back the mapped data

如果文件过滤驱动或者系统的其他组件需要频繁性的直接使用物理内存中的数据结构,the pinning inerface可以派上用场;如果要保证物理内存中的数据常驻,不可移出.the pinning inerface同样可以运用

(6) 一些重要的数据结构

┎ FsContext
┎ SectionObjectPointer
┎ PrivateCacheMap

① 当缓存需要被初始化时,FsContext必须被初始化,它指向一个结构体 FSRTL_COMMAN_FCB_HEADER 
名称:  Snap4.gif
查看次数: 133
文件大小:  14.8 KB

一个文件流在内存中对应一个File Control Block(FCB), 参数Flags用来指定用ERESOURCE中的哪个;参数Flags2用来特指 ----> 一般情况下, FSD可能指定对缓存文件流不用延迟写入,但如果Flags2被设置为FSRTL_FLAG2_DO_MODIFIED_WRITE,则缓存管理器会忽略FSD的指令,而运用延迟写入;2个ERESOURCE通过ExInitializeResourceLite()来初始化;

剩下的3个关于Size的很简单:AllocationSize是在硬盘上为文件流分配的存储空间,紧接着,缓存管理器需要时刻标记这个参数的变化;FileSize是面向用户的,包含了文件流数据的大小.任何越界都会导致返回STATUS_END_OF_FILEValidDataLength则是有效的文件长度,任何读操作如果超过了这个范围,都会返回0.这有助于防止对磁盘的不必要的I/O操作,也是为了数据安全; [NTFS、HPFS都支持这个操作]

==>>the NT Cache Manager通过SetFilelnformation IRP来通知ValidDataLength的改变

==>>举个例子来说明ValidDataLength的必要性(理解的可能有偏差)
[ 当用户进程要扩展一个文件长度,这个请求被送到Cache Manager,它首先会检查是否有多个页可用,接着产生缺页中断,page fault最终会被 the file system driver处理,此时它如果保留有ValidDataLength指定的可用长度,便意识到不需要进行读草组,返回0来完成缺页中断即可]

PS: (A.)改变AllocationSize或者FileSize必须和其他读/写请求同步,而且缓存管理器必须立即响应任何的改变,要不然就会出现以下现象----用户扩展了文件的长度,但the cache Manager没有标明新的文件大小,于是用户的读请求的数据地址在旧的数据结束地址以后时,就会被返回STATUS_END_OF_FILE错误;
    (B.)如果是Paging I/O read/write请求,FileSize的改变不需要同步处理

② SectionObjectPointer 指向SECTION_OBJECT_POINTERS这个结构体[需要分配到非分页的kernel memory中],它保存了与文件流相关的文件映射和缓存相关信息. 这让偶联想起来MJ0011的360粉碎机.呵呵,众多猥亵的手法中的一种便是设置ImageSectionObjectDataSectionObject 为空,发IRP删除之.具体可参考
hi.baidu.com/sudami/blog/item/7760f61990997e4643a9adf3.html
或者
bbs.pediy.com/showthread.php

引用:
typedef struct _SECTION_OBJECT_POINTERS {
    PVOID DataSectionObject;
    PVOID SharedCacheMap;
    PVOID ImageSectionObject;
} SECTION_OBJECT_POINTERS;
[only one shared cache map structure is allo-cated by the Cache Manager when caching is first initiated for a file stream viasome file object. This shared cache map is used by all open instances for the file
stream. ]

③ PrivateCacheMap 值得注意:
文件系统驱动检查PrivateCacheMap是否为空而且[唯一的方法],来判断缓存是否通过给定的文件流对应的文件对象而被初始化(相当饶口,没解释好-.=)
"缓存是否被初始化"这个信息不能被保存到任何其他的地方,因为缓存管理器保留有通过暴力方式关闭缓存,这些缓存经过一些或者全部的与文件流想关联的文件对象. [理解的不透彻,嘿嘿,大家可以看看原文]

(7) 数据控制块 [Buffer Control Blocks]
要用锁定操作 [the pinning inerface],就必须用到Buffer Control Blocks(BCB),它分为公共BCB、私有BCBpublic BCB运用在"数据的锁定"和紧接着的"解锁"上

(8) Virtual Address Control Block (VACB)
所有指向同一个文件流的VACB组成一个数组. 而SharedCacheMap保存有指向这个数组首地址的指针.每一个VACB保存有一块数据的虚拟地址和在文件流中的偏移值. the NT Cache Manager通过这个可以决定一个已经映射的view是否包含用户请求的数据,没有则映射之;VACB结构被分配在固定的全局内存池中,所以当一个view需要被创建时,缓存管理器可能找不到空闲的VACBs来分配新的文件流.所以Cache Manager需要unmap以前的一个mapped view,从数组中摘除一个VACB,再分配VACB到新的文件流上去.

名称:  Snap5.gif
查看次数: 134
文件大小:  125.4 KB
名称:  Snap6.gif
查看次数: 132
文件大小:  135.0 KB

看完这个图,偶明晰了不少,特别是关于FCB中的 PrivateCacheMap 和SECTION_OBJECT_POINTERS中的SharedCacheMap

(9) 资源的获取 [Resource Acquisition]
有2个ERESOURCE: MainResource 和 PagingloResource
待续。。。。
-------------------------------------------------------------------------------------------------------

hi.baidu.com/sudami/blog/item/1e1227d0550d428ca0ec9c2c.html