windows – Minifilter驱动程序,内存映射和记事本

我将从我的最终目标开始.

我希望我系统上的每个文档(doc,docx,pdf,txt等)都有一个固定的(和用户的transperent)标题.

例如,字符串“abcde”将被添加到每个文档中.

为了做到这一点,我写了一个minifilter驱动程序,它执行以下操作:

IRP_MJ_WRITE – 如果存在标题,则将偏移更改为文件的开头.

IRP_MJ_READ – 如果存在标题,则将偏移更改为文件的开头.

IRP_MJ_QUERY_INFORMATION – 如果存在标题,则更改文件的返回大小.

IRP_MJ_DIRECTORY_CONTROL – 如果存在标题,则更改文件的返回大小.

IRP_MJ_CREATE – 如果标头不存在prepened标头到文件.

这种方法很有效,除了MS Word 2003文档(doc,xls,ppt)和记事本.
我似乎没有抓住一些读写操作,记事本显示标题和文件.

我在http://www.osronline.com/读了很多,每个在那里问过的人都被告知阅读一些Nagar书或看看他们的档案(这是搜索的灾难).我想我已经在那里读到与我的问题有关的一切.

似乎记事本使用内存映射文件,快速IO,Pagged IO和上帝知道还有什么.
我试图用mHook挂钩NtMapViewOfSection,MapViewOfFile和MapViewOfFileEx,但是当我在记事本中打开一些文件并试图找到映射数据时我没有运气(但我发现每个其他字节都映射到内存).

然后我读到我想要完成的东西是不可能用钩子,只有minifilter驱动程序和我想象的我错过了一些标志设置.

如果有人可以告诉我该怎么做才能抓住记事本的操作,我真的很喜欢它.

这是一些读取的代码示例:

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检查文件名和请求进程. (有些应用程序可以看到标题)

如果有人可以告诉我该怎么做才能抓住记事本的操作,我真的很喜欢它.

谢谢.

最佳答案 正如@Harry jonhston所指出的,只检查MdlAddress == NULL的拦截IRP是不正确的.

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

很可能记事本和MS Office应用程序因此而失败.

几点:

>您必须适当地处理分页IO.
> FltReadFile应该只被称为IRQL PASSIVE_LEVEL.
>更重要的是,更改文件大小并使其对Windows文件系统和用户保持透明非常复杂.建议不要这样做.
>要为文件添加特殊数据,您最好使用alternate data stream.

点赞