Distinguish file creation from file open

148 Views Asked by At

Although not the end goal, the best way of describing what I'm doing is tracking file creations like Sysinternals Sysmon does. I copied the nullfilter sample from here and made adjustments. The following code is truncated to show only changes to the sample:

nullfilter.c

// ...
FLT_POSTOP_CALLBACK_STATUS
FLTAPI CheckPathLengthPost(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags
);
// ...

CONST FLT_OPERATION_REGISTRATION callback[] =
{
    {
        IRP_MJ_CREATE,
        0,
        CheckPathLengthPre,
        CheckPathLengthPost
    },

    {IRP_MJ_OPERATION_END}
};

CONST FLT_REGISTRATION FilterRegistration = {

    sizeof( FLT_REGISTRATION ),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags

    NULL,                               //  Context
    callback,                           //  Operation callbacks

    NullUnload,                         //  FilterUnload

    NULL,                               //  InstanceSetup
    NullQueryTeardown,                  //  InstanceQueryTeardown
    NULL,                               //  InstanceTeardownStart
    NULL,                               //  InstanceTeardownComplete

    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent

};
// ...
FLT_PREOP_CALLBACK_STATUS
FLTAPI CheckPathLengthPre(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)
{

    UNREFERENCED_PARAMETER(FltObjects);
    UNREFERENCED_PARAMETER(CompletionContext);

    if (Data->RequestorMode == KernelMode)
        return FLT_PREOP_SUCCESS_NO_CALLBACK;

    PFLT_FILE_NAME_INFORMATION info = NULL;
    NTSTATUS status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT | FLT_FILE_NAME_DO_NOT_CACHE, &info);
    if (!(NT_SUCCESS(status))) {
        DbgPrint("nullfilter|CheckPathLengthPre: FltGetFileNameInformation failed: %#x", status);
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    ULONG createDisp = (Data->Iopb->Parameters.Create.Options >> 24) & 0x000000FF;

    BOOLEAN isCreation = ((createDisp == FILE_CREATE) ||
        (createDisp == FILE_SUPERSEDE) ||
        (createDisp == FILE_OVERWRITE) ||
        (createDisp == FILE_OVERWRITE_IF) ||
        (createDisp == FILE_OPEN_IF));


    // File or folder is being created
    if ((Data->Iopb->Parameters.Create.Options) & FILE_NON_DIRECTORY_FILE) {
        if (isCreation == 1) {
            DbgPrint("nullfilter: isFile: %d, isDir: %d, createDisp: <%08x>, Path: %wZ", 1, 0, createDisp, info->Name);
        }
    }
    else if ((Data->Iopb->Parameters.Create.Options) & FILE_DIRECTORY_FILE) {
        if (isCreation == 1) {
            DbgPrint("nullfilter: isFile: %d, isDir: %d, createDisp: <%08x>, Path: %wZ", 0, 1, createDisp, info->Name);
        }
    }

    return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

nullfilter.inf

[Version]
Signature   = "$Windows NT$"
Class       = "Bottom"             ;This is determined by the work this filter driver does
ClassGuid   = {21D41938-DAA8-4615-86AE-E37344C18BD8}    ;This value is determined by the Class
Provider    = %ProviderString%
DriverVer   = 06/16/2007,1.0.0.0
CatalogFile = nullfilter.cat
; ...
[NullFilter.Service]
DisplayName      = %ServiceName%
Description      = %ServiceDescription%
ServiceBinary    = %12%\%DriverName%.sys    ;%windir%\system32\drivers\
Dependencies     = "FltMgr"
ServiceType      = 2                        ;SERVICE_FILE_SYSTEM_DRIVER
StartType        = 3                        ;SERVICE_DEMAND_START
ErrorControl     = 1                        ;SERVICE_ERROR_NORMAL
LoadOrderGroup   = "FSFilter Bottom"
AddReg           = NullFilter.AddRegistry
; ...
[Strings]
; ...
DefaultInstance         = "Null Instance"
Instance1.Name          = "Null Instance"
Instance1.Altitude      = "47777"
Instance1.Flags         = 0

This was probably the best question I found in terms of providing source: Minifilter Check new file create on harddisk?

Issue is that it tracks opens and creations. I can't find anything additional to narrow it down. This is the issue with any other discussion I've found on this:

Most of these are discussion with limited code. They all appear to suggest what I've already tried above. Perhaps I'm in the wrong spot, perhaps at this-low level there is no distinction?

1

There are 1 best solutions below

0
Tyler Montney On

Looked at https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/irp-mj-create (again?) and I think I'm onto something.

nullfilter.c

// ...
FLT_POSTOP_CALLBACK_STATUS
FLTAPI CheckPathLengthPost(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags
);
// ...
FLT_PREOP_CALLBACK_STATUS
FLTAPI CheckPathLengthPre(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)
{

    UNREFERENCED_PARAMETER(FltObjects);
    UNREFERENCED_PARAMETER(CompletionContext);

    if (Data->RequestorMode == KernelMode)
        return FLT_PREOP_SUCCESS_NO_CALLBACK;

    NTSTATUS status;
    PFLT_FILE_NAME_INFORMATION info = NULL;
    if (NULL != FltObjects->FileObject) {
        status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT | FLT_FILE_NAME_DO_NOT_CACHE, &info);
    }
    else {
        status = STATUS_UNSUCCESSFUL;
    }

    if (!(NT_SUCCESS(status))) {
        DbgPrint("nullfilter|CheckPathLengthPre: FltGetFileNameInformation failed: %#x", status);
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

FLT_POSTOP_CALLBACK_STATUS
FLTAPI CheckPathLengthPost(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags
)
{
    PFLT_FILE_NAME_INFORMATION info;

    UNREFERENCED_PARAMETER(FltObjects);
    UNREFERENCED_PARAMETER(CompletionContext);
    UNREFERENCED_PARAMETER(Flags);

    UINT16 isCreation = ((Data->IoStatus.Information == FILE_CREATED));

    info = (PFLT_FILE_NAME_INFORMATION)CompletionContext;
    
    if (isCreation == 1) {
        DbgPrint("nullfilter|CheckPathLengthPost: Path: %wZ\r\n", info->Name);
    }

    return FLT_POSTOP_FINISHED_PROCESSING;
}

After thinking about my question, I wondered why again do I believe this "isn't working". DbgView was showing far too much activity, certainly thousands of files aren't being created a second. I determined my create disposition was too wide. For this test, I only care about new files. Additionally, I added a post-create callback as, I believe, IOStatus will not be correct in pre-create.

Since the change, DbgView has significantly less output. The files listed are cache or journal files, both of which are definitely new files. Opening files is not treated "incorrectly".