intercept call CreateFile with CREATE_ALWAYS in minifilter

the scenario: i have a file name “123.txt” with data in it, some usermode process call CreateFile with CREATE_ALWAYS flag will erase my file’s data, and i wan intercept that in minifilter.
my code using is:
`FLT_PREOP_CALLBACK_STATUS
FsFilter2PreOperation (
Inout PFLT_CALLBACK_DATA Data,
In PCFLT_RELATED_OBJECTS FltObjects,
Flt_CompletionContext_Outptr PVOID *CompletionContext
)
{
// pre operation
UNREFERENCED_PARAMETER(CompletionContext);
bool block = false;
FLT_PREOP_CALLBACK_STATUS retStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
auto param = &Data->Iopb->Parameters.Create;
ULONG CreateDispotition = ULONG((param->Options >> 24) & 0xff);

if (Data->RequestorMode == UserMode && FltObjects->FileObject)
{
    if (FltObjects->FileObject->FileName.Length > 6 && FltObjects->FileObject->FileName.Buffer)
    {
        if (wcsstr(FltObjects->FileObject->FileName.Buffer, L"Desktop\\123.txt"))
        {
            if (FlagOn(CreateDispotition, FILE_OVERWRITE_IF))
            {
                KdPrint(("123.txt CREATE_ALWAYS detected\n"));
                block = true;
            }
            else if (FlagOn(CreateDispotition, FILE_CREATE))
            {
                KdPrint(("123.txt CREATE_NEW detected\n"));
                block = true;
            }
            else
            {
                KdPrint(("123.txt undetected\n"));
            }
        }
    }
}

if (block)
{
    Data->IoStatus.Status = STATUS_ACCESS_DENIED;
    retStatus = FLT_PREOP_COMPLETE;
}

return retStatus;

}

check CreateDispotition  flags was reference from: http://www.osronline.com/article.cfm%5Eearticle=302.htm
but thats not run correctly:
-STATUS_ACCESS_DENIED don't work, usermode app still can open my file and the file is empty after.
-FILE_OVERWRITE_IF triggered many times, even call CloseHandle.
do you have any idea to check call CreateFile(...CREATE_ALWAYS...) exactly? and can totally block that action? pls share if you got something.
thank you!

P/S my user app code to test:

`HANDLE hFile = CreateFile(file_name, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);`

Run Process Monitor in Advanced mode (Filter->Enable Advanced Output) and set a filter to only see requests from your process. You’ll be able to easily see which requests are arriving and the native create flags.

Also, your name processing is very broken. You can’t assume that the name buffer is null terminated or even a valid string (see open by id). You need to use FltGetFileNameInformation to get the name for the request and use Rtl functions to match the UNICODE_STRING (e.g. FsRtlIsNameInExpression, RtlPrefixUnicodeString, etc.). I recommend spending time analyzing Process Monitor output and playing with the Minispy example to get a better foundation.

thanks @“Scott_Noone_(OSR)” for procmon trick. the output line make me notice is:
_
Console1.exe 2956 IRP_MJ_CREATE C:\Users\asd\Desktop\123.txt SUCCESS Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, AllocationSize: 0, OpenResult: Overwritten
_
that mean i catch the right flag, but then i can’t block that operation, even with STATUS_ACCESS_DENIED.
still dont know why…

if (wcsstr(FltObjects->FileObject->FileName.Buffer, L"Desktop\\123.txt"))
this will never match. Even if you correctly use FltGetFileNameInformation, you would not match that string.
It’s too simple, but too long to explain in details - it would be much better if you checked what the filename is like from your process.

The open by ID is not the only case where the above won’t work. Relative opens will not work either, and you must not rely on the FileName of a related file object to be accessible even, and definitely do not rely on it being correct!
(the not being accessible part may seem strange, but it can happen)

thanks all. i found the solution, 1 line code is bad: “Data->RequestorMode == UserMode”. some operation would run in KernelMode too.
i removed it, and the minifilter blocked it immediately.
thanks @Dejan_Maksimovic and @“Scott_Noone_(OSR)” for advices.

You are very unlucky that this code worked as it is fundamentally incorrect…See the previous comments.

oh, these codes just for fast check, i always use at least FltGetFileNameInformation, FltParseFileNameInformation when work with FILE_OBJECT in real project.