4

我將從最終目標開始。 我希望我的系統上的每個文檔(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,分頁IO和上帝知道還有什麼。 我試圖掛鉤NtMapViewOfSection,MapViewOfFileMapViewOfFileEx與mHook,但當我打開記事本中的某個文件,並試圖找到映射的數據我沒有運氣(但我發現其他每個字節映射到內存)。

然後我讀到,我試圖完成的是不可能與一個鉤子,只有微過濾器驅動程序,並從我想我想念一些標誌設置。

如果有人能夠告訴我該怎麼做才能抓住記事本的操作,我會真正appriciate它。

這裏的一些代碼示例讀:

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檢查文件名和請求過程。 (某些應用程序可能會看到標題)

如果有人可以告訴我該怎麼做才能捕獲記事本的操作,那麼我真的會認真對待它。

謝謝。

+1

爲什麼你不攔截'Parameters.Read.MdlAddress!= NULL'的調用?這似乎是錯誤的。 –

+0

你是對的!我會檢查出來的。 Thnaks。 – assafmo

回答

2

As @Harry jonhston指出只檢查IRP與MdlAddress == NULL的檢查是不正確的。

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

最有可能的記事本和MS Office應用程序因此而失敗。

幾分看點:

  • 你將不得不適當地處理尋呼IO。
  • FltReadFile應該只能稱爲IRQL PASSIVE_LEVEL
  • 更重要的是改變文件大小並保持它對Windows文件系統和用戶透明是非常複雜的。它建議不要這樣做。
  • 要爲一個文件添加特殊數據,可能您最好使用alternate data stream
+0

感謝您的意見。 'IsFileNeedProccessing'還檢查'IRQL == PASSIVE_LEVEL'。你如何建議妥善處理Paging IO? – assafmo

+1

@gfgqtmakia我認爲你需要跳過分頁IO,因爲在此期間你可能不會得到文件名。雖然我建議做一些研究,弄清楚你到底需要做什麼。 – Rohan

+0

我可以從'FileObject'和'IoQueryFileDosDeviceName'獲取文件名。分頁IO是MDL?你能再解釋一下嗎? – assafmo