FSD 解释:
File System Driver文件系统 驱动程序,分为本地FSD和远程FSD。
(1) 本地FSD:允许用户访问本地计算机上的数据
——本地FSD负责向I/O管理器注册自己,当开始访问某个卷时,I/O管理器调用FSD来进行卷识别。
——完成卷识别后,本地FSD创建一个设备对象以表示所装载的文件系统。
——I/O管理器通过卷参数块(VPB)在存储管理器创建的卷设备对象和FSD创建的卷设备对象之间建立连接。此连接将I/O管理器的I/O请求转交给FSD设备对象。
(2) 远程FSD:允许用户通过网络访问远程计算机上的数据。
由两部分组成:客户端FSD和服务器端FSD。
——客户端FSD首先接收来自应用程序的I/O请求,并转换为 网络文件系统协议命令,然后通过网络发送给服务器端FSD。
——服务器端FSD监听 网络命令,接收 网络文件系统协议命令并转交给本地FSD去执行。
(3) FSD与文件系统操作
Windows文件系统的有关操作都是通过FSD完成的:
——显示文件I/O:应用程序通过I/O接口函数如CreateFile,ReadFile,WriteFile等来访问文件。
——高速缓存 延迟写:此线程定期对高速缓存中已被修改的页面进行写操作。
——高速缓存提前读:此线程负责提前读数据。
——内存 脏页写:此线程定期清洗缓冲区。
——内存缺页处理

-----------------------------------------------------------------------------------------

首先是FSD HOOK。

网上比较容易找到的是sudami对360superkiller的逆向,映射大小计算上好像有些错误。

这里贴出我的想法,备忘 :)

1.       向ZwQuerySystemInformation传递11号参数,获得SYSTEM_MODULE_INFORMATION结构,通过结构查询ntfs和fastfat的基地址(lpModuleBase)。

2.       通过指定路径打开ntfs.sys和fastfat.sys对应的磁盘文件
L”\\SystemRoot\\system32\\drivers\\ntfs.sys”
L” \\SystemRoot\\system32\\drivers\\fastfat.sys”

3.       根据PE格式获得文件中镜像基地址(imageBase)

4.       使用特征码搜索ntfs.sys和fastfat.sys设置派遣路径的指令。

用IDA反汇编ntfs.sys(fastfat.sys类似)见指令和对应的机器码如下:
名称:  fcbda6d3ccc66519960a16cd.jpg查看次数: 1508文件大小:  70.6 KB
esi指向DriverObject结构,指令字结构分别为

c7 46 XX YY YY YY YY 

c7 86 XX XX XX XX YY YY YY YY (XX为esi的相对偏移,YY为真正的函数地址)

因此可以通过特征搜索此段指令:

名称:  2.jpg查看次数: 1499文件大小:  39.3 KB

获得指令后,根据上述结构分别获取IRP派遣序号index和原始派遣函数地址addr。

在这里真正index的计算方法如下:

名称:  3.jpg查看次数: 1493文件大小:  12.5 KB
同时由于ntfs.sys实际加载的位置和pe文件中存储的位置不同,所以需要重定位:
名称:  4.jpg查看次数: 1494文件大小:  5.8 KB

至此获得了派遣函数的原始路径。

5.       使用ObReferenceObjectByName分别获得

L”\\FileSystem\\Ntfs”

L”\\FileSystem\\Fastfat”

对应的驱动对象(DriverObject)。

将驱动对象中的派遣函数地址与从pe文件读取的地址进行比对,如果发现不同和进行修复。

-----------------------------------------------------------------------------------------

SSDT HOOK
1. 确定windows所使用内核文件时ntoskrnl.exe还是ntkrnlpa.exe。
当电脑内存大于512MB时windows开启PAE使用ntkrnlpa.exe否则使用ntoskrnl.exe这里并没有考虑支持多核处理器的内核。
所以我们只要检测PAE是否开启就能确定内核文件名了。
当cr4寄存器的5 bit置为时说明开启了PAE。
名称:  5.jpg查看次数: 1506文件大小:  39.1 KB

2.       将内核文件映射如内存,首地址为krnlImgBase。
3.       向ZwQuerySystemInformation传递11号参数,得到SYSTEM_MODULE_INFORMATION结构数组,遍历数组得到系统内核在内存中的基地址krnlBase。
4.       根据PE格式解析映射到内存中的文件,获得原始SSDT。
方法是:首先获得系统导出的SSDT表地址,减去基地址后得到SSDT的RVA
名称:  6.jpg查看次数: 1494文件大小:  20.1 KB

找出内存映射的内核文件的节表。
搜索SSDT的RVA处在文件那哪个节中。
内存映射文件的SSDT = SSDT RVA – 所在节 RVA + 所在节 RawOffset + krnlImgBase
名称:  7.jpg查看次数: 1494文件大小:  55.8 KB

5.       对比原始SSDT与当前SSDT内容,不同则替换。
这里存在一个重定位问题需要注意。
代码如下:

名称:  8.jpg查看次数: 1498文件大小:  40.1 KB