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

  • Post author:
  • Post category:其他

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

导致效果很奇怪很奇怪,当时我哭晕在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;
}

 


版权声明:本文为zhuhuibeishadiao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。