0%

使用MiniFilter拦截MountPoint操作(1)

前言

某些情况下,我们需要保护文件或文件夹,不被恶意 MountPointHardLink 等操作。
有以下几种可选方案:
1、在操作文件之前,先检测是否被 MountPoint ,如果有则解除。
2、利用MiniFilter过滤驱动,来拦截所有的 MountPoint 等操作。
3、使用DACL权限管理机制,在 MountPoint 时,请求的是 FILE_WRITE_ATTRIBUTES 权限,
所以可以在目标中添加 拒绝Users组的写入属性 权限,而Users组在CreateFile时,需要排除请求
写入属性权限,即 FILE_ALL_ACCESS & ~FILE_WRITE_ATTRIBUTES,否则会因为权限被拒绝而
打开文件失败。注:只是修改的Users组,其他组不受影响。修改父目录的权限后,其所有子目录
可以自动继承该权限。重要:目标的拥有者不能是Users组,因为拥有者具有全部权限

使用MiniFilter过滤

MountPoint操作对应到MiniFilter驱动中,主功能码为 IRP_MJ_FILE_SYSTEM_CONTROL
内部控制码是 FSCTL_SET_REPARSE_POINT
HardLink操作对应到MiniFilter驱动中,主功能码是 IRP_MJ_SET_INFORMATION,对应的
FileInformationClassFileLinkInformation

注册 FLT_OPERATION_REGISTRATION 的结构体,如下所示

1
2
3
4
5
FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_SET_INFORMATION, 0, PtPreSetInfromation, NULL },
{ IRP_MJ_FILE_SYSTEM_CONTROL, 0, PtPreFileSystemControl, NULL },
{ IRP_MJ_OPERATION_END }
};

过滤文件映射的处理函数如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
FLT_POSTOP_CALLBACK_STATUS PtPreSetInfromation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Out_ PVOID *CompletionContext)
{
ULONG ProcessID = 0;
PEPROCESS EProcess = NULL;
NTSTATUS Status = STATUS_SUCCESS;
PFLT_FILE_NAME_INFORMATION NameInfo = NULL;
UNREFERENCED_PARAMETER(CompletionContext);
// 获取本次操作的进程信息
EProcess = FltGetRequestorProcess(Data);
ProcessID = FltGetRequestorProcessId(Data);
// 检查是不是硬链接操作
if (Data->Iopb->Parameters.SetFileInformation.FileInformationClass
!= FileLinkInformation) return FLT_PREOP_SUCCESS_NO_CALLBACK;
// 获取文件名信息
Status = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &NameInfo);
if (!NT_SUCCESS(Status) return FLT_PREOP_SUCCESS_NO_CALLBACK;
// 转换文件名信息
Status = FltParseFileNameInformation(NameInfo);
if (!NT_SUCCESS(Status))
{
FltReleaseFileNameInformation(NameInfo);
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
// 本次操作的文件对象
Data->Iopb->TargetFileObject;
// 根据已获得的PID,NameInfo,FileObject决定动作
if (IsProtectFile(NameInfo))
{
FltReleaseFileNameInformation(NameInfo);
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
return FLT_PREOP_COMPLETE;
}
// 释放文件名内存空间
FltReleaseFileNameInformation(NameInfo);
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
FLT_POSTOP_CALLBACK_STATUS PtPreFileSystemControl(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Out_ PVOID *CompletionContext)
{
ULONG ProcessID = 0;
PEPROCESS EProcess = NULL;
NTSTATUS Status = STATUS_SUCCESS;
PFLT_FILE_NAME_INFORMATION NameInfo = NULL;
UNREFERENCED_PARAMETER(CompletionContext);
// 获取本次操作的进程信息
EProcess = FltGetRequestorProcess(Data);
ProcessID = FltGetRequestorProcessId(Data);
// 检查是不是MountPoint操作
if (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode
!= FSCTL_SET_REPARSE_POINT) return FLT_PREOP_SUCCESS_NO_CALLBACK;
// 获取文件名信息
Status = FltGetFileNameInformation(Data,
FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &NameInfo);
if (!NT_SUCCESS(Status) return FLT_PREOP_SUCCESS_NO_CALLBACK;
// 转换文件名信息
Status = FltParseFileNameInformation(NameInfo);
if (!NT_SUCCESS(Status))
{
FltReleaseFileNameInformation(NameInfo);
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
// 本次操作的文件对象
Data->Iopb->TargetFileObject;
// 根据已获得的PID,NameInfo,FileObject决定动作
if (IsProtectFile(NameInfo))
{
FltReleaseFileNameInformation(NameInfo);
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
return FLT_PREOP_COMPLETE;
}
// 释放文件名内存空间
FltReleaseFileNameInformation(NameInfo);
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

注意:无论是 MountPoint 还是 HardLink 都存在 源对象目的对象,这里只处理了 源对象
可以参考链接 http://www.sinkland.cn/?p=204 中的例子来处理 目的对象