Minifilter driver, memory card and notepad

I will start with my ultimate goal. I want every document (doc, docx, pdf, txt, etc.) on my system to have a fixed header (and transperent for the user). For example, the string "abcde" will be added to each document.

For this, I wrote a minifilter driver that does the following:

IRP_MJ_WRITE - if the header has a change offset for the beginning of the file.

IRP_MJ_READ - if the header has a change offset for the beginning of the file.

IRP_MJ_QUERY_INFORMATION - if the header exists, the returned file size is changed.

IRP_MJ_DIRECTORY_CONTROL - if the header exists, the returned file size is changed.

IRP_MJ_CREATE - if the header does not contain a pre-prepared header in the file.

This works well, except for MS Word 2003 documents (doc, xls, ppt) and notepad. It seems I just won’t catch some of the read and write operations, and notepad shows the title as well as the file.

I read A LOT at http://www.osronline.com/ , and everyone who asks, asked to read some Nagara book or look at their archives (which are a disaster for searching). I think that I read everything related to my problem there.

Notepad seems to be using files with Mapped, Fast IO, Pagged IO memory and God knows what else. I tried to connect NtMapViewOfSection , MapViewOfFile and MapViewOfFileEx using mHook, but when I opened the file in notepad and tried to find the associated data, I was out of luck (but I found every other byte that was mapped to memory).

Then I read that what I'm trying to do is impossible with a hook, only with a mini-driver and from what I understand, I miss some flags for installation.

I would really appreciate it if someone could just tell me what to do to catch notepad operations.

here is a sample code to 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 the file name and the request process. (Some applications may see the title)

I would really appreciate it if someone could just tell me what to do to catch notepad operations.

Thanks.

+4
source share
1 answer

As @Harry jonhston pointed out that your check only for IRP interception with MdlAddress == NULL is incorrect.

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

Most likely, notepad and MS Office application fail because of this.

A few points more:

  • You will have to handle Paging IO accordingly.
  • FltReadFile should be called only IRQL PASSIVE_LEVEL .
  • More importantly, resizing a file and making it transparent to the Windows file system and the user is quite difficult. It is recommended not to do this.
  • To add special data for the file, you can use an alternative data stream .
+2
source

Source: https://habr.com/ru/post/1437881/


All Articles