本章目标:完成一个磁盘卷设备的上层类过滤驱动,该过滤驱动的功能是实现对卷的还原,即开启该驱动的功能之后,对还原卷的写操作将只适用于当前,重启电脑后所写入的数据都将清零,类似于还原卡之类的功能。
1、磁盘卷设备
OK,根据章节的主题。首先要知道什么是磁盘卷设备,根据《windows internals》一书中的讲解,Windows的存储结构自上而下分成以下各个部分,如图所示:
(擦,一个图片翻译了N久,尼玛~)
根据图中可以看出各个部分的功能,从中我们可以看见卷设备所处在的层级。
2、上层类过滤驱动
根据驱动的层级,类功能驱动的上下可以添加相应的过滤驱动,添加在上层的称为上层过滤驱动,添加在下层的称为下层过滤驱动(前面的笔记中也有类似的介绍)。
代码分析:
1、 DriverEntry
DriveEntry中有一个API:
VOID IoRegisterBootDriverReinitialization(
_In_ PDRIVER_OBJECTDriverObject,
_In_ PDRIVER_REINITIALIZEDriverReinitializationRoutine,
_In_opt_ PVOID Context
);
该API用来注册一个函数,用于在boot驱动结束之后回调,该函数会在所有boot类型驱动都运行完毕之后执行。
可以看到回调函数中使用了其它盘作为“数据暂存处”,所以需要保证其他盘已经加载OK之后再调用,也就是为什么使用该API进行注册的原因。
2、 AddDevice
AddDevice例程中就是创建对应的过滤设备对象,该例程中有点不一样的是创建了一个内核线程。
NTSTATUS PsCreateSystemThread(
_Out_ PHANDLE ThreadHandle,
_In_ ULONG DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTESObjectAttributes,
_In_opt_ HANDLE ProcessHandle,
_Out_opt_ PCLIENT_ID ClientId,
_In_ PKSTART_ROUTINE StartRoutine,
_In_opt_ PVOID StartContext
);
该线程用于处理读写的操作。
3、 PNP处理
在该例程中主要是对IRP_MN_DEVICE_USAGE_NOTIFICATION进行处理,因为分页文件的存在,根据Parameters.UsageNotification.Type判断是否是特殊文件,若有页面文件的存在则要清除DO_POWER_PAGEABLE,反之加上。对于特殊文件的处理都需要将请求发送给下层驱动去处理,过滤驱动本身不做任何操作,根据下层操作的结果返回状态。
POWER和DeviceIoControl的请求没有基本和其它的类似。
Bitmap的作用和分析
Bitmap是一个位图,实际上是一些内存块,这些内存块的每一个位用来标识一个磁盘的最小访问单位,一般情况下是一个扇区,每一个位可以被置位或被清除,用来表示这个扇区所对应的两种情况(这个让人想起《数学之美》书中讲的布隆过滤器,将所有的数据排放在对应的位上,该位是1,则数据存在,如果是0,则不存在数据,好吧,这个跟很多面试题中,判断几十万个电话号码中是否存在某一电话号码是一个概念~)。
根据Bitmap的信息我们就可以判断内存中哪一片已经使用,而哪一片是空的了。
Boot驱动完成回调函数和稀疏文件
在前面有用到一个函数IoRegisterBootDriverReinitialization,这个函数注册了一个完成回调函数,在该驱动所有操作结束之后就开始执行该函数了。从书的代码中可以看见,这边主要是设置了一个D盘的稀疏文件。
ntStatus = ZwFsControlFile(
gProtectDevExt->TempFile,
NULL,
NULL,
NULL,
&ios,
FSCTL_SET_SPARSE,
NULL,
0,
NULL,
0);
FileEndInfo.EndOfFile.QuadPart= gProtectDevExt->TotalSizeInByte.QuadPart + 10*1024*1024;
ntStatus =ZwSetInformationFile(
gProtectDevExt->TempFile,
&ios,
&FileEndInfo,
sizeof(FILE_END_OF_FILE_INFORMATION),
FileEndOfFileInformation
);
这边使用了一个很有趣的文件类型——稀疏文件,百度了一下这个,发现居然是一个很实用的文件类型,在建立这种文件的时候容量可以设定很大,但是在实际使用的时候却会根据实际磁盘的容量有限制。因为稀疏文件是依赖文件系统的,所以建立该文件的过程就被放在了boot回调函数中进行。
感觉笔记写的很乱~