我将从我的最终目标开始。我希望我系统上的每个文档(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
,但是当我在记事本中打开一些文件并试图找到映射的数据时,我没有运气(但我找到了映射到内存的所有其他字节)。MapViewOfFile
MapViewOfFileEx
然后我读到我想要完成的事情是不可能用钩子完成的,只有使用微过滤器驱动程序,并且从我认为我缺少一些要设置的标志。
如果有人能告诉我该怎么做才能捕捉记事本的操作,我真的会很感激。
这是一些阅读代码示例:
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
检查文件名和请求进程。(某些应用程序可以看到标题)
如果有人能告诉我该怎么做才能捕捉记事本的操作,我真的会很感激。
谢谢。