MiniFilter实现硬链接和软链接监控

  • 内容
  • 评论
  • 相关

对于MiniFilter监控软链接和硬链接这块的资料还是挺少的。

这里整理并实现了以下功能:

#include <fltKernel.h>

PFLT_FILTER gFilterHandle = NULL;

FLT_POSTOP_CALLBACK_STATUS FsFilterPostSetInformation(
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __in_opt PVOID CompletionContext,
    __in FLT_POST_OPERATION_FLAGS Flags
)
{
    FILE_INFORMATION_CLASS Class = 
        Data->Iopb->Parameters.SetFileInformation.FileInformationClass;
    PFILE_RENAME_INFORMATION pRenameInfo = (PFILE_RENAME_INFORMATION)
        Data->Iopb->Parameters.SetFileInformation.InfoBuffer;

    PFLT_FILE_NAME_INFORMATION pSrcNameInfo = NULL;
    PFLT_FILE_NAME_INFORMATION pLinkNameInfo = NULL;

    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    if (Class == FileLinkInformation)
    {
        Status = FltGetFileNameInformation(
            Data, 
            FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, 
            &pSrcNameInfo
        );
        if (!NT_SUCCESS(Status))
        {
            goto END;
        }

        Status = FltParseFileNameInformation(pSrcNameInfo);
        if (!NT_SUCCESS(Status))
        {
            goto END;
        }

        Status = FltGetDestinationFileNameInformation(
            FltObjects->Instance,
            Data->Iopb->TargetFileObject, 
            pRenameInfo->RootDirectory, 
            pRenameInfo->FileName, 
            pRenameInfo->FileNameLength, 
            FLT_FILE_NAME_NORMALIZED, 
            &pLinkNameInfo
        );
        if (!NT_SUCCESS(Status))
        {
            goto END;
        }

        KdPrint(("[HardLink] FilePath:%S, HardLink:%S\n", 
            pSrcNameInfo->Name.Buffer, pLinkNameInfo->Name.Buffer));
    }
END:
    if (pSrcNameInfo != NULL)
    {
        FltReleaseFileNameInformation(pSrcNameInfo);
    }
    if (pLinkNameInfo != NULL)
    {
        FltReleaseFileNameInformation(pLinkNameInfo);
    }
    return FLT_POSTOP_FINISHED_PROCESSING;
}

FLT_POSTOP_CALLBACK_STATUS FsFilterPostFileSystemControl(
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __in_opt PVOID CompletionContext,
    __in FLT_POST_OPERATION_FLAGS Flags
)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PWCHAR pwzFilePath = NULL;
    PFLT_FILE_NAME_INFORMATION NameInfo = NULL;

    ULONG FsControlCode = Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode;
    if (FsControlCode == FSCTL_SET_REPARSE_POINT)
    {
        ULONG InputBufferLength = Data->Iopb->Parameters.FileSystemControl.Neither.InputBufferLength;
        if (InputBufferLength == sizeof(REPARSE_GUID_DATA_BUFFER) ||
            InputBufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
        {
            goto END;
        }

        PREPARSE_DATA_BUFFER DataBuffer = Data->Iopb->Parameters.FileSystemControl.Neither.InputBuffer;
        if (DataBuffer == NULL)
        {
            goto END;
        }

        PUCHAR pPathBuffer = NULL;
        USHORT uNameOffset = 0;
        USHORT uNameLength = 0;
        if (DataBuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK)
        {
            pPathBuffer = (PUCHAR)DataBuffer->SymbolicLinkReparseBuffer.PathBuffer;
            uNameOffset = DataBuffer->SymbolicLinkReparseBuffer.PrintNameOffset;
            uNameLength = DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength;
        }
        else if (DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
        {
            pPathBuffer = (PUCHAR)DataBuffer->MountPointReparseBuffer.PathBuffer;
            uNameOffset = 0;
            uNameLength = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
        }
        else
        {
            goto END;
        }

        pwzFilePath = ExAllocatePoolWithTag(NonPagedPool, uNameLength + sizeof(WCHAR), 'TAG_');
        if (pwzFilePath == NULL)
        {
            goto END;
        }
        RtlCopyMemory(pwzFilePath, pPathBuffer + uNameOffset, uNameLength);
        pwzFilePath[uNameLength / 2] = L'\0';

        NTSTATUS Status = STATUS_UNSUCCESSFUL;
        Status = FltGetFileNameInformation(
            Data, 
            FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, 
            &NameInfo
        );
        if (!NT_SUCCESS(Status))
        {
            goto END;
        }

        Status = FltParseFileNameInformation(NameInfo);
        if (!NT_SUCCESS(Status))
        {
            goto END;
        }

        KdPrint(("[SymboLink] FilePath:%S, SymbolicPath:%S\n", pwzFilePath, NameInfo->Name.Buffer));
    }

END:
    if (pwzFilePath != NULL)
    {
        ExFreePool(pwzFilePath);
    }
    if (NameInfo != NULL)
    {
        FltReleaseFileNameInformation(NameInfo);
    }
    return FLT_POSTOP_FINISHED_PROCESSING;
}

CONST FLT_OPERATION_REGISTRATION Callbacks[] = 
{
    { 
        IRP_MJ_SET_INFORMATION,
        0,
        NULL,
        FsFilterPostSetInformation 
    },
    { 
        IRP_MJ_FILE_SYSTEM_CONTROL,
        0,
        NULL,
        FsFilterPostFileSystemControl
    },
    { 
        IRP_MJ_OPERATION_END 
    }
};

NTSTATUS
FsFilterUnload(
    _In_ FLT_FILTER_UNLOAD_FLAGS Flags
)
{
    FltUnregisterFilter(gFilterHandle);
    return STATUS_SUCCESS;
}

CONST FLT_REGISTRATION FilterRegistration = 
{
    sizeof(FLT_REGISTRATION),
    FLT_REGISTRATION_VERSION,
    0,  
    NULL,  
    Callbacks,
    FsFilterUnload,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL, 
    NULL, 
    NULL 
};

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    KdPrint(("DriverEntry\n"));

    NTSTATUS Status = STATUS_SUCCESS;

    Status = FltRegisterFilter(
        DriverObject,
        &FilterRegistration,
        &gFilterHandle);
    if (!NT_SUCCESS(Status))
    {
        return Status;
    }

    Status = FltStartFiltering(gFilterHandle);
    if (!NT_SUCCESS(Status))
    {
        FltUnregisterFilter(gFilterHandle);
    }
    return Status;
}

测试:

// 创建硬链接
mklink /h xxHardLink xxx.txt

// 创建软链接
mklink /d xxSymbolLink xxx.txt