4

我将从我的最终目标开始。我希望我系统上的每个文档(doc、docx、pdf、txt 等)都有一个固定的(并且对用户来说是透明的)标题。例如,字符串“abcde”将被添加到每个文档中。

为此,我编写了一个微过滤驱动程序,它执行以下操作:

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

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

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

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

IRP_MJ_CREATE- 如果标题不存在,则将标题添加到文件中。

这很好用,除了 MS Word 2003 文档(doc、xls、ppt)和记事本。我似乎没有捕捉到一些读写操作,记事本显示了标题和文件。

我在http://www.osronline.com/上阅读了很多内容,并且每个提出要求的人都被告知要阅读一些 Nagar 书籍或查看他们的档案(搜索起来是灾难)。我想我已经阅读了与我的问题相关的所有内容。

似乎记事本使用了内存映射文件、快速 IO、分页 IO,天知道还有什么。我尝试过使用 mHook和hook NtMapViewOfSection,但是当我在记事本中打开一些文件并试图找到映射的数据时,我没有运气(但我找到了映射到内存的所有其他字节)。MapViewOfFileMapViewOfFileEx

然后我读到我想要完成的事情是不可能用钩子完成的,只有使用微过滤器驱动程序,并且从我认为我缺少一些要设置的标志。

如果有人能告诉我该怎么做才能捕捉记事本的操作,我真的会很感激。

这是一些阅读代码示例:

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

如果有人能告诉我该怎么做才能捕捉记事本的操作,我真的会很感激。

谢谢。

4

1 回答 1

2

正如@Harry jonhston 指出的那样,您对仅拦截 IRP 的检查MdlAddress == NULL是不正确的。

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

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

还有几点:

  • 您必须适当地处理 Paging IO。
  • FltReadFile应该只称为 IRQL PASSIVE_LEVEL
  • 更重要的是更改文件大小并使其对 Windows 文件系统和用户透明是相当复杂的。建议不要这样做。
  • 为文件添加特殊数据可能是您最好使用备用数据流
于 2012-10-05T04:40:31.653 回答