windows - Minifilter 驱动程序、内存映射和记事本

标签 windows driver memory-mapped-files memory-mapping minifilter

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

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

IRP_MJ_WRITE - 如果 header 存在,则更改文件开头的偏移量。

IRP_MJ_READ - 如果 header 存在,则更改文件开头的偏移量。

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

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

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

除 MS Word 2003 文档(doc、xls、ppt)和记事本外,此方法运行良好。 我只是似乎没有捕捉到一些读写操作,记事本显示了标题和文件。

我在http://www.osronline.com/ 中阅读了很多内容|每个问的人都被告知要阅读一些 Nagar 的书或查看他们的文件(搜索这些文件是灾难)。我想我已经在那里阅读了与我的问题相关的所有内容。

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

然后我读到我试图用钩子(Hook)完成的事情是不可能的,只能用 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。 .

关于windows - Minifilter 驱动程序、内存映射和记事本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12735169/

相关文章:

windows - 具有部分对象(CreateFileMapping)的 I/O 是否比基本 api(Read/WriteFile)更快?

java - 将文件从 windows Java 应用程序移动到 linux box

Windows 调度程序不执行批处理脚本,但脚本在命令行中运行良好

c - 制作我自己的/dev/random,缓冲区不工作,c

java - Box 类,getFull() 方法不会显示准确的 boolean 结果

c++ - 为什么 SetupDiEnumDriverInfo 会为我的驱动程序提供两个版本号

c++ - 为什么从内存映射文件读取这么快?

git - 单个 Git 安装,多个环境(msys、cygwin、SourceTree 等)

python - Windll ctypes 从 python 2.7 调用可变参数 c 函数在 win64 中有效,但在 win32 中无效

c++ - 估计内存映射的boost rtree所需的大小