I'll start with my final goal. I want that every document (doc,docx,pdf,txt, etc.) on my system will have a fixed (and transperent to the user) header. For example, the string "abcde" will be prepended in every document.

In order to do so I wrote a minifilter driver that does the following:

IRP_MJ_WRITE - if header exists change offset to start of file.

IRP_MJ_READ - if header exists change offset to start of file.

IRP_MJ_QUERY_INFORMATION - if header exists change returned size of file.

IRP_MJ_DIRECTORY_CONTROL - if header exists change returned size of file.

IRP_MJ_CREATE - if header doesn't exists prepened header to file.

This works well, except on MS Word 2003 documents (doc,xls,ppt) and notepad. I just seem to not catch some of the read and write operations and notepad shows the header as well as the file.

I have read A LOT in http://www.osronline.com/ and every one who asks there is told to read some Nagar book or look at their archives (which are disaster to search in). I think I've read there everything related to my issue.

It seems notepad uses Memory Mapped files, Fast IO, Pagged IO and god knows what else. I've tried to hook NtMapViewOfSection, MapViewOfFile and MapViewOfFileEx with mHook, but when I opened some file in notepad and tried to find the mapped data I had no luck (but I found every other byte that was mapped to the memory).

Then I read that what I'm trying to accomplish isn't possible with a hook, only with minifilter driver and from what I figgured I'm missing some flags to set.

I would really appriciate it if someone could just tell me what to do in order to catch notepad's operations.

here's some code example for read:

CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
    { IRP_MJ_WRITE,
    0,
    PreWrite,
    PostWrite },

    { IRP_MJ_READ,
    0,
    PreRead,
    PostRead },

    { IRP_MJ_QUERY_INFORMATION,
    0,
    NULL,
    PostQueryInfo },

    { IRP_MJ_DIRECTORY_CONTROL,
    0,
    NULL,
    PostQueryDir },

    { IRP_MJ_CREATE,
    0,
    NULL,
    PostCreate },

    { IRP_MJ_OPERATION_END }
};

FLT_PREOP_CALLBACK_STATUS
    PreRead (
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID *CompletionContext
    )
{
    NTSTATUS status = 0;
    ULONG bytesRead;
    PVOID readBuffer;
    LARGE_INTEGER zero;
    zero.QuadPart = 0;

    UNREFERENCED_PARAMETER(FltObjects);
    UNREFERENCED_PARAMETER(Data);
    UNREFERENCED_PARAMETER(CompletionContext);

    if(Data->Iopb->Parameters.Read.MdlAddress != NULL){
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    if(!IsFileNeedProccessing(&FltObjects->FileObject->FileName, Data)){
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }


    readBuffer = ExAllocatePool(
        NonPagedPool,
        prefixSize);
    if(readBuffer == NULL)
    {
        return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }

    status = FltReadFile(
        FltObjects->Instance,
        FltObjects->FileObject,
        &zero,
        (ULONG)prefixSize,
        readBuffer,
        FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
        &bytesRead,
        NULL,
        NULL);

    if(NT_SUCCESS(status))
    {
        if(IsBuffAPrefixOfBuffB(prefix, readBuffer, prefixSize, (SIZE_T)bytesRead))
        {
            Data->Iopb->Parameters.Read.ByteOffset.QuadPart += prefixSize;
            FltSetCallbackDataDirty(Data);
        }
    }
    ExFreePool(readBuffer);

    return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

 FLT_POSTOP_CALLBACK_STATUS
    PostRead (
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_opt_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags
    )
 {
    NTSTATUS status;
    ULONG bytesRead;
    PVOID readBuffer;
    FILE_STANDARD_INFORMATION info;
    LONGLONG* currOffset = &Data->Iopb->TargetFileObject->CurrentByteOffset.QuadPart;
    LARGE_INTEGER zero;
    zero.QuadPart = 0;

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

    if(Data->Iopb->Parameters.Read.MdlAddress != NULL)
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    if(!IsFileNeedProccessing(&FltObjects->FileObject->FileName, Data))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    status = FltQueryInformationFile(
        FltObjects->Instance,
        FltObjects->FileObject,
        &info,
        sizeof(info),
        FileStandardInformation,
        NULL);

    if(NT_SUCCESS(status)
        && info.EndOfFile.QuadPart != *currOffset
        && *currOffset >= (LONGLONG)prefixSize)
    {
        readBuffer = ExAllocatePool(NonPagedPool,
            prefixSize);
        if(readBuffer == NULL)
        {
            return FLT_POSTOP_FINISHED_PROCESSING;
        }

        status = FltReadFile(
            FltObjects->Instance,
            FltObjects->FileObject,
            &zero,
            (ULONG)prefixSize,
            readBuffer,
            FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
            &bytesRead,
            NULL,
            NULL);

        if(NT_SUCCESS(status))
        {
            if(IsBuffAPrefixOfBuffB(prefix, readBuffer, prefixSize, (SIZE_T)bytesRead))
            {
                *currOffset -= prefixSize;
                FltSetCallbackDataDirty(Data);
            }
        }
        ExFreePool(readBuffer);
    }

    return FLT_POSTOP_FINISHED_PROCESSING;
 }

IsFileNeedProccessing checks for file name and requesting process. (Some app's could see the header)

I would really appriciate it if someone could just tell me what to do in order to catch notepad's operations.

Thanks.

有帮助吗?

解决方案

As @Harry jonhston pointed out your check of only intercepting IRPs with MdlAddress == NULL is incorrect.

if(Data->Iopb->Parameters.Read.MdlAddress != NULL)
{
    return FLT_POSTOP_FINISHED_PROCESSING;
}

Most likely notepad and MS Office application are failing due to this.

Few points more:

  • You would have to handle Paging IO appropriately.
  • FltReadFile should only be called IRQL PASSIVE_LEVEL.
  • More importantly changing file size and keeping it transparent to windows filesystem and user is quite complex. Its recommended not to do so.
  • To add special data for a file may be you are better of using alternate data stream.
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top