minifilter/sfilter较为精确的判断是打开还是新建操作

本文针对minifilter/sfilter中IRP_MJ_CREATE操作,探讨如何准确区分文件是被新建还是打开。通过分析IRP->IoStatus.Information的值,可以在完成例程或PostCreate中判断文件操作类型。测试表明,不同Information值对应不同操作,如FILE_SUPERSEDE表示删除并新建,FILE_OVERWRITE则保留属性并清空内容。
摘要由CSDN通过智能技术生成

写这篇文章的原因是看到一些代码判断不准确,

导致效果很奇怪很奇怪,当时我哭晕在WC.

见过奇奇怪怪的判断,很无语.

于是有了这篇文章.

createfile可以新建文件和打开文件

这个不多说了

在文件过滤系统中IRP_MJ_CREATE

怎么判断是open还是create

无论是minifilter还是sfilter,

判断基本都相同,只不过sfilter在完成例程,minifilter在post操作

在sfilter的完成例程中判断irp->IoStatus.Information

在Minifilter的PostCreate中Data->IoStatus.Information

这个地方的取值如下:

#define FILE_SUPERSEDED                 0x00000000
#define FILE_OPENED                     0x00000001
#define FILE_CREATED                    0x00000002
#define FILE_OVERWRITTEN                0x00000003
#define FILE_EXISTS                     0x00000004
#define FILE_DOES_NOT_EXIST             0x00000005

根据不同的值可以知道此次是新建还是打开

以下是效果:

此图是测试文件全部不存在时

此图测试文件全部存在时

此图是其它文件

第二个图为什么把FILE_SUPERSEDE标记为新文件,

FILE_SUPERSEDE:删除原文件,新建一个文件

FILE_OVERWRITE:保留文件属性,清空内容.

下面是测试的代码:

#include "pch.h"

static WCHAR* g_szTestFileName[] = {
    L"\\??\\C:\\TestOpenIf.dat",
    L"\\??\\C:\\TestOverWriteIf.dat",
    L"\\??\\C:\\TestSupersed.dat"
};

PFLT_FILTER g_FilterHandle = NULL;

EXTERN_C static NTSTATUS FLTAPI
TestUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags) 
{
    PAGED_CODE();
    UNREFERENCED_PARAMETER(Flags);

    FltUnregisterFilter(g_FilterHandle);

    return STATUS_SUCCESS;
}

EXTERN_C static const WCHAR* TestGetDispositionName(ULONG ulDisposition)
{
//#define FILE_SUPERSEDE                  0x00000000
//#define FILE_OPEN                       0x00000001
//#define FILE_CREATE                     0x00000002
//#define FILE_OPEN_IF                    0x00000003
//#define FILE_OVERWRITE                  0x00000004
//#define FILE_OVERWRITE_IF               0x00000005
    WCHAR const *szRet = nullptr;

    switch (ulDisposition)
    {
    case FILE_SUPERSEDE:
        szRet = L"FILE_SUPERSEDE";
        break;
    case FILE_OPEN:
        szRet = L"FILE_OPEN";
        break;
    case FILE_CREATE:
        szRet = L"FILE_CREATE";
        break;
    case FILE_OPEN_IF:
        szRet = L"FILE_OPEN_IF";
        break;
    case FILE_OVERWRITE:
        szRet = L"FILE_OVERWRITE";
        break;
    case FILE_OVERWRITE_IF:
        szRet = L"FILE_OVERWRITE_IF";
        break;
    default:
        szRet = L"Error Disposition";
        break;
    }

    return szRet;
}

EXTERN_C static const WCHAR* TestGetIoStatusInformationName(ULONG ulInformation)
{
    /*
#define FILE_SUPERSEDED                 0x00000000
#define FILE_OPENED                     0x00000001
#define FILE_CREATED                    0x00000002
#define FILE_OVERWRITTEN                0x00000003
#define FILE_EXISTS                     0x00000004
#define FILE_DOES_NOT_EXIST             0x00000005
    */
    WCHAR const *szRet = nullptr;

    switch (ulInformation)
    {
    case FILE_SUPERSEDED:
        szRet = L"FILE_SUPERSEDED";
        break;
    case FILE_OPENED:
        szRet = L"FILE_OPENED";
        break;
    case FILE_CREATED:
        szRet = L"FILE_CREATED";
        break;
    case FILE_OVERWRITTEN:
        szRet = L"FILE_OVERWRITTEN";
        break;
    case FILE_EXISTS:
        szRet = L"FILE_EXISTS";
        break;
    case FILE_DOES_NOT_EXIST:
        szRet = L"FILE_DOES_NOT_EXIST";
        break;
    default:
        szRet = L"Error IoStatusInformation";
        break;
    }

    return szRet;
}

EXTERN_C static FLT_POSTOP_CALLBACK_STATUS FLTAPI
TestPostCreate(_Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_opt_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags) 
{
    UNREFERENCED_PARAMETER(CompletionContext);
    UNREFERENCED_PARAMETER(Flags);

    BOOLEAN isDir = FALSE;
    BOOLEAN bNewFile = FALSE;

    if (KeGetCurrentIrql() != PASSIVE_LEVEL) 
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    auto status = Data->IoStatus.Status;

    if (!NT_SUCCESS(status) || (status == STATUS_REPARSE))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    status = FltIsDirectory(FltObjects->FileObject,
        FltObjects->Instance,
        &isDir);

    if (isDir || !NT_SUCCESS(status))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    //auto ulOptions = Data->Iopb->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
    auto ulDisposition = (Data->Iopb->Parameters.Create.Options & 0xFF000000) >> 24;
    //auto DesiredAccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess;
    //auto Attributes = Data->Iopb->Parameters.Create.FileAttributes;
    
    PFLT_FILE_NAME_INFORMATION fileNameInformation = nullptr;

    status = FltGetFileNameInformationUnsafe(
        FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED,
        &fileNameInformation);
    if (!NT_SUCCESS(status)) 
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    status = FltParseFileNameInformation(fileNameInformation);
    if (!NT_SUCCESS(status)) {
        FltReleaseFileNameInformation(fileNameInformation);
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    if (Data->IoStatus.Information == FILE_CREATED || Data->IoStatus.Information == FILE_SUPERSEDED)
        bNewFile = TRUE;

    if (bNewFile)
        DPRINT("New File:%wZ,%ws,%ws\n", &fileNameInformation->Name, TestGetIoStatusInformationName(Data->IoStatus.Information), TestGetDispositionName(ulDisposition));
    else
        DPRINT("Open File:%wZ,%ws,%ws\n", &fileNameInformation->Name, TestGetIoStatusInformationName(Data->IoStatus.Information), TestGetDispositionName(ulDisposition));

    FltReleaseFileNameInformation(fileNameInformation);

    return FLT_POSTOP_FINISHED_PROCESSING;
}

EXTERN_C static FLT_PREOP_CALLBACK_STATUS FLTAPI TestPreCreate(
    _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Outptr_result_maybenull_ PVOID *CompletionContext) 
{
    UNREFERENCED_PARAMETER(CompletionContext);

    ULONG_PTR stackLow;
    ULONG_PTR stackHigh;
    PFILE_OBJECT FileObject = Data->Iopb->TargetFileObject;

    if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    IoGetStackLimits(&stackLow, &stackHigh);

    if (((ULONG_PTR)FileObject > stackLow) &&
        ((ULONG_PTR)FileObject < stackHigh)) {

        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    if (FlagOn(Data->Iopb->Parameters.Create.Options, FILE_DIRECTORY_FILE)) {

        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    if (FlagOn(Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY)) {

        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    if (FlagOn(Data->Iopb->OperationFlags, SL_OPEN_PAGING_FILE)) {

        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    if (FlagOn(FltObjects->FileObject->Flags, FO_VOLUME_OPEN)) {

        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    return FLT_PREOP_SYNCHRONIZE;
}

EXTERN_C static VOID TestThread(
    _In_ PVOID StartContext
)
{
    HANDLE file_handle = NULL;
    NTSTATUS status;
    IO_STATUS_BLOCK io_status;
    OBJECT_ATTRIBUTES object_attributes;
    UNICODE_STRING ufile_name = { 0 };
    ULONG ulCreateDisposition = FILE_OPEN_IF;

    for (size_t i = 0; i < sizeof(g_szTestFileName) / sizeof(WCHAR*); i++)
    {
        RtlInitUnicodeString(&ufile_name, g_szTestFileName[i]);

        if (i == 0)
            ulCreateDisposition = FILE_OPEN_IF;

        if (i == 1)
            ulCreateDisposition = FILE_OVERWRITE_IF;

        if (i == 2)
            ulCreateDisposition = FILE_SUPERSEDE;

        InitializeObjectAttributes(&object_attributes, &ufile_name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

        status = ZwCreateFile(

            &file_handle,

            GENERIC_READ | GENERIC_WRITE,

            &object_attributes,

            &io_status,

            NULL,

            FILE_ATTRIBUTE_NORMAL,

            FILE_SHARE_READ,

            ulCreateDisposition,

            FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT,

            NULL,

            0

        );

        if (status == STATUS_SUCCESS) {

            DPRINT("file create success %wZ\n", &ufile_name);
            ZwClose(file_handle);
        }

        else {

            DPRINT("file create failed %wZ 0x%x\n", &ufile_name, status);

        }
    }

    PsTerminateSystemThread(STATUS_SUCCESS);
}

EXTERN_C static VOID PostDriverEntry(
    _In_ struct _DRIVER_OBJECT *DriverObject,
    _In_opt_ PVOID Context,
    _In_ ULONG Count
)
{
    HANDLE hThread = NULL;

    PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, TestThread, NULL);

    if (hThread)
        ZwClose(hThread);
}

EXTERN_C NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath) 
{
    const FLT_OPERATION_REGISTRATION fltCallbacks[] = {
        {
            IRP_MJ_CREATE, FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO, 
            TestPreCreate,
            TestPostCreate,
        },
        {IRP_MJ_OPERATION_END} };

    const FLT_REGISTRATION filterRegistration = {
        sizeof(filterRegistration),  //  Size
        FLT_REGISTRATION_VERSION,    //  Version
        0,                           //  Flags
        nullptr,                     //  Context
        fltCallbacks,                //  Operation callbacks
        TestUnload,                 //  FilterUnload
        nullptr,                     //  InstanceSetup
        nullptr,                     //  InstanceQueryTeardown
        nullptr,                     //  InstanceTeardownStart
        nullptr,                     //  InstanceTeardownComplete
        nullptr,                     //  GenerateFileName
        nullptr,                     //  GenerateDestinationFileName
        nullptr,                     //  NormalizeNameComponent
    };

    PAGED_CODE();
    UNREFERENCED_PARAMETER(RegistryPath);

    // Register and start a mini filter driver
    auto status = FltRegisterFilter(DriverObject, &filterRegistration,
        &g_FilterHandle);

    if (!NT_SUCCESS(status)) 
    {
        DPRINT("flt register: 0x%x\n", status);
        return status;
    }

    status = FltStartFiltering(g_FilterHandle);
    if (!NT_SUCCESS(status)) 
    {
        FltUnregisterFilter(g_FilterHandle);
        DPRINT("flt start: 0x%x\n", status);
        return status;
    }

    DPRINT("flt start installed.\n");

    IoRegisterDriverReinitialization(DriverObject, PostDriverEntry, NULL);

    return status;
}

Minifilter是Windows操作系统中的一个内核模块,它可以对文件系统I/O操作进行监控和过滤,提供一定程度的文件系统访问控制和文件操作的修改能力。minifilter可以在文件系统级别实现对文件的读写访问控制、文件内容加密、文件过滤等功能。 minifilter的下载通常分为两个步骤:首先需要下载Windows Driver Kit(WDK)或Windows SDK,以获取minifilter开发所需的工具和库文件;其次,可以根据自己的具体需求编写或下载现有的minifilter源代码。 WDK或Windows SDK是微软提供的一套开发工具,它包含了开发Windows驱动程序所需的一系列工具、示例代码、库文件和文档等,可以用于minifilter开发及其他相关驱动程序的开发。 一般来说,在微软官网上可以找到WDK或Windows SDK的下载链接,用户可以根据自己的操作系统版本和开发环境选择合适的版本进行下载安装。安装完成后,用户可以在Windows开发环境中配置相应的环境变量,然后就可以使用WDK或Windows SDK提供的工具和库文件进行minifilter开发。 另外,也可以通过搜索引擎或开源社区等途径,找到已经编写好的minifilter源代码,并根据需要进行下载和修改。这种方式适用于一些常见的minifilter功能,如文件加密、病毒扫描等,可以节省开发时间和工作量。 总之,minifilter的下载需要获取Windows Driver Kit或Windows SDK,然后可以通过官方渠道或开源社区获取minifilter的源代码,以进行开发和定制。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值