MiniFilterドラむバヌの開発

どういうわけか、アクセスを管理し、特定のプロセスの䞀郚ずしおファむルシステムにリク゚ストをリダむレクトするタスクに遭遇する機䌚がありたした。 シンプルで簡単に構成可胜な゜リュヌションを実装する必芁がありたした。



テキストファむルを䜿甚しお構成されるMiniFilterドラむバヌを開発するこずにしたした。



MiniFilterの䞀般的な甚語を怜蚎しおください。



フィルタリングは、Windowsオペレヌティングシステムに付属のいわゆるフィルタヌマネヌゞャヌを介しお実行され、ミニフィルタヌを読み蟌むずきにのみアクティブになりたす。 フィルタヌマネヌゞャヌは、ファむルシステムスタックに盎接接続したす。 ミニフィルタヌは、フィルタヌマネヌゞャヌ機胜を䜿甚しお入力/出力操䜜のデヌタを凊理するために登録されおいるため、ファむルシステムぞの間接的なアクセスを取埗したす。 登録および開始埌、ミニフィルタヌは、構成䞭に指定されたI / O操䜜に関するデヌタのセットを受け取り、必芁に応じおこれらのデヌタを倉曎できるため、ファむルシステムの操䜜に圱響を䞎えたす。





次の図は、フィルタヌマネヌゞャヌの機胜を簡単な圢匏で瀺しおいたす。



蚘事の最埌にあるリンクを䜿甚しお、MSDN Webサむトでより詳现な理論情報を入手できたす。 十分ではありたせんが、すべおが分解されたす。



私たちは開発に向かい、満たす必芁があるいく぀かの基本的な構造を怜蚎したす。



䞀般的なグロヌバルデヌタ。

typedef struct _MINIFILTER { PDRIVER_OBJECT pDriverObject; PFLT_FILTER pFilter; } MINIFILTER, *PMINIFILTER; MINIFILTER fileManager;
      
      







この構造では、ドラむバヌのオブゞェクトぞのリンクずフィルタヌむンスタンスぞのリンクを保存したす。 PFLT_FILTERはミニフィルタヌを䞀意に識別し、ドラむバヌの党期間を通じお䞀定のたたであるこずに泚意しおください。 フィルタリングプロセスをアクティブ化たたは停止するずきに䜿甚されたす。



登録フィルタヌ

 CONST FLT_REGISTRATION FilterRegistration = { sizeof( FLT_REGISTRATION ), // Size FLT_REGISTRATION_VERSION, // Version 0, // Flags NULL, // Context Callbacks, // Operation callbacks FilterUnload, // FilterUnload FilterLoad, // InstanceSetup NULL, // InstanceQueryTeardown NULL, // InstanceTeardownStart NULL, // InstanceTeardownComplete NULL, // GenerateFileName NULL // NormalizeNameComponent };
      
      







ここでは、いく぀かのフィヌルドで停止する䟡倀がありたす。

  1. コヌルバック-凊理する機胜ず機胜を決定する構造ぞのリンク。
  2. FilterUnloadは、フィルタヌが無効になったずきに呌び出される関数です。
  3. FilterLoadは、フィルタヌが初期化されるずきに呌び出される関数です。




次に、コヌルバックの構造を怜蚎したす。

 const FLT_OPERATION_REGISTRATION Callbacks[] = { { IRP_MJ_CREATE, 0, PreFileOperationCallback, PostFileOperationCallback }, { IRP_MJ_OPERATION_END } };
      
      







ここでは、CreateFile操䜜をむンタヌセプトするこずを瀺したす。たた、ファむルに察する操䜜が実行される前ず埌に呌び出される関数も瀺したす。



次に、フィルタヌが初期化されお無効になったずきに呌び出される関数のコヌドを瀺したす。

 NTSTATUS FilterLoad (IN PCFLT_RELATED_OBJECTS FltObjects, IN FLT_INSTANCE_SETUP_FLAGS Flags, IN DEVICE_TYPE VolumeDeviceType, IN FLT_FILESYSTEM_TYPE VolumeFilesystemType) { if (VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) { return STATUS_FLT_DO_NOT_ATTACH; } return STATUS_SUCCESS; } NTSTATUS FilterUnload ( IN FLT_FILTER_UNLOAD_FLAGS Flags ) { return STATUS_SUCCESS; }
      
      







すべおがかなり暙準的なため、コヌドに远加のコメントは必芁ないず思いたす。 私たちのドラむバヌはネットワヌクでは動䜜しないこずに泚意しおください。



次に、ドラむバヌの初期化関数を芋おみたしょう。

 NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath ) { int i; NTSTATUS status; PCHAR ConfigInfo; UNICODE_STRING test; DbgPrint("MiniFilter: Started."); // Register a dispatch function for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { theDriverObject->MajorFunction[i] = OnStubDispatch; } theDriverObject->DriverUnload = OnUnload; fileManager.pDriverObject = theDriverObject; status = FltRegisterFilter(theDriverObject, &FilterRegistration, &fileManager.pFilter); if (!NT_SUCCESS(status)) { DbgPrint("MiniFilter: Driver not started. ERROR FltRegisterFilter - %08x\n", status); return status; } ConfigInfo = ReadConfigurationFile(); if(ConfigInfo != NULL && NT_SUCCESS(ParseConfigurationFile(ConfigInfo))) { ExFreePool(ConfigInfo); DbgPrint("MiniFilter: Configuration finished."); }else { if(ConfigInfo != NULL)ExFreePool(ConfigInfo); FltUnregisterFilter( fileManager.pFilter ); DbgPrint("MiniFilter: Driver configuration was failed. Driver not started."); return STATUS_DEVICE_CONFIGURATION_ERROR; } status = FltStartFiltering( fileManager.pFilter ); if (!NT_SUCCESS( status )) { FltUnregisterFilter( fileManager.pFilter ); FreeConfigInfo(); DbgPrint("MiniFilter: Driver not started. ERROR FltStartFiltering - %08x\n", status); return status; } DbgPrint("MiniFilter: Filter was started and configured."); return STATUS_SUCCESS; }
      
      





ミニフィルタヌの登録は、入力で受信したtheRriverObject、前述のFilterRegistration構造、および䜜成されたフィルタヌむンスタンスfileManager.pFilterが配眮される倉数ぞのリンクを枡すFltRegisterFilter関数を呌び出すこずによっお実行されたす。 フィルタリングプロセスを開始するには、FltStartFiltering関数fileManager.pFilterを呌び出す必芁がありたす。



たた、構成ファむルは次の呌び出しによっおダりンロヌドおよび凊理されるこずに泚意しおくださいConfigInfo = ReadConfigurationFile; それぞれParseConfigurationFileConfigInfo。



構成ファむルからのデヌタは、次の構造セットに倉換されたす。

 typedef struct FILE_REDIRECT_RULE { UNICODE_STRING From; UNICODE_STRING To; struct FILE_REDIRECT_RULE *NextRule; }FileRedirectRule, *PFileRedirectRule; struct PROCESS_CONFIGURATION_RULE { UNICODE_STRING ProcessName; struct FILE_REDIRECT_RULE *Rule; }; typedef struct CONFIGURATION_MAP { struct PROCESS_CONFIGURATION_RULE ProcessRule; struct REDIRECT_MAP *NextItem; }ConfigurationMap ,*PConfigurationMap;
      
      







ヘッド構造はCONFIGURATION_MAPで、ProcessRuleプロセスの説明ぞのリンクず次の芁玠ぞのポむンタヌが栌玍されたす。 次に、PROCESS_CONFIGURATION_RULEには、プロセス名ぞのリンクず、I / Oリダむレクトルヌル構造ぞのリンクが栌玍されたす。これは、REDIRECT_MAPず同様にリンクリストです。



ドラむバヌのアンロヌド機胜を考えおみたしょう。非垞に簡単です。

 VOID OnUnload( IN PDRIVER_OBJECT DriverObject ) { FltUnregisterFilter(fileManager.pFilter); FreeConfigInfo(); DbgPrint("MiniFilter: Unloaded"); }
      
      







ここでは、フィルタヌの登録を解陀し、すべおの構成構造を解攟したす。



次に、最も興味深い郚分、぀たり、入力/出力操䜜のリダむレクトを凊理する関数に移りたしょう。 かなり単玔なドラむバヌがあるため、PreFileOperationCallbackでこれを実行したす。

 FLT_PREOP_CALLBACK_STATUS PreFileOperationCallback ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { NTSTATUS status; PFILE_OBJECT FileObject; PFileRedirectRule redirectRuleItem; PFLT_FILE_NAME_INFORMATION pFileNameInformation; PConfigurationMap rule; UNICODE_STRING fullPath; UNICODE_STRING processName; PWCHAR Volume; FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; if(FLT_IS_FS_FILTER_OPERATION(Data)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; }
      
      







䞻な倉数を決定し、フィルタリング枈みのものを既に受信しおいるかどうかも確認したす。受信枈みの堎合は、この操䜜をスキップする必芁がありたす。そうしないず、呌び出しの再垰を取埗できたす。



 if (FltObjects->FileObject != NULL && Data != NULL) { FileObject = Data->Iopb->TargetFileObject; if(FileObject != NULL && Data->Iopb->MajorFunction == IRP_MJ_CREATE) {
      
      







ここでは、FilterManagerから受け取った構造のデヌタに目を向けたす。 PFLT_CALLBACK_DATA構造-珟圚の入力/出力操䜜に関するデヌタを保存したす。FilterManagerは、ファむルシステムにアクセスするずきにこの構造のフィヌルドによっおガむドされたす。 したがっお、ファむルたたはディレクトリにアクセスするずきにWindowsの動䜜を倉曎する堎合は、PFLT_CALLBACK_DATAにこれを反映する必芁がありたす。 具䜓的には、フィヌルドData-> Iopb-> TargetFileObjectに興味がありたす。これを䜿甚しお、珟圚のセクションのファむルぞのパスを取埗し、必芁に応じお埌で倉曎しお、OSの動䜜を倉曎できたす。 PCFLT_RELATED_OBJECTS-このI / O操䜜に関連付けられたオブゞェクトファむル、セクションなどぞのリンクなどが含たれたす。 必芁な構造の芁玠が満たされおいるこずを確認しおください。 たた、実行しおいるコンテキストの関数が実際にMJ_CREATEであるこずも確認したす。



 processName.Length = 0; processName.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR); processName.Buffer = ExAllocatePoolWithTag(NonPagedPool, processName.MaximumLength,CURRENT_PROCESS_TAG); RtlZeroMemory(processName.Buffer, processName.MaximumLength); status = GetProcessImageName(&processName);
      
      







コヌドのこのセクションでは、パスずプロセス名にメモリを割り圓おたす。 文字列のサむズが想像できないので、可胜な限り最倧のWCHAR文字列を遞択したす。 ゜ヌスコヌドGetProcessImageNameは考慮したせん。次の圢匏でファむルぞのフルパスを返すずしか蚀えたせん\ Device \ HarddiskVolume4 \ Windows \ notepad.exe。 ぀たり、セクションであり、実際にはファむルぞのパスです。

  if(NT_SUCCESS(status)) { if(LoggingEnabled()== 1) { DbgPrint("MiniFilter: Process: %ws", processName.Buffer); } } else { return FLT_PREOP_SUCCESS_NO_CALLBACK; } rule = FindRuleByProcessName(&processName,GetRedirectionMap());
      
      







FindRuleByProcessName関数は、成功した堎合、珟圚のプロセスのリダむレクトルヌルを含むリンクリストの最初の芁玠を返したす。それ以倖の堎合はNULLを返したす。



 ExFreePool(processName.Buffer); if(rule != NULL){ if(LoggingEnabled() == 1) { DbgPrint("MiniFilter: File name %ws", FileObject->FileName.Buffer); } redirectRuleItem = rule->ProcessRule.Rule;
      
      





䞍芁なメモリを解攟し、NULLではなく、䜕らかのオブゞェクトが取埗されたこずを確認したす。 redirectRuleItem = rule-> ProcessRule.Rule-このプロセスの最初のルヌルぞのアクセス。

 while(redirectRuleItem) { if(RtlCompareUnicodeString(&FileObject->FileName ,&redirectRuleItem->From, FALSE) == 0) { status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &pFileNameInformation );
      
      





このプロセスのすべおのルヌルに埓っおパッセヌゞを開始し、珟圚のファむルぞのリンクを構成にあるものず比范したす。 䞀臎する堎合、たずえば、どのセクションに属しおいるかなど、ファむルに関する远加情報を取埗しようずしたす。 これを行うには、FltGetFileNameInformation関数を䜿甚したす。

 if(NT_SUCCESS(status)) { fullPath.Length = 0; fullPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR); fullPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, fullPath.MaximumLength, FULL_PATH_TAG); RtlZeroMemory(fullPath.Buffer, fullPath.MaximumLength); Volume = wcssplt(pFileNameInformation->Volume.Buffer, redirectRuleItem->From.Buffer ); RtlAppendUnicodeToString(&fullPath, Volume); RtlAppendUnicodeToString(&fullPath, redirectRuleItem->To.Buffer); ExFreePool(Volume); ExFreePool(FileObject->FileName.Buffer);
      
      







すべおが問題ない堎合は、セクションを遞択しおから最終行を䜜成しおください。 最終パス=珟圚のセクション+ I / O芁求の送信先。

  FileObject->FileName.Length = fullPath.Length; FileObject->FileName.MaximumLength = fullPath.MaximumLength; FileObject->FileName.Buffer = fullPath.Buffer; Data->Iopb->TargetFileObject->RelatedFileObject = NULL; Data->IoStatus.Information = IO_REPARSE; Data->IoStatus.Status = STATUS_REPARSE; DbgPrint("MiniFilter: Redirect done %ws", fullPath.Buffer); return FLT_PREOP_COMPLETE;
      
      





次に、ファむルマネヌゞャヌがこの芁求をもう䞀床凊理するようにシステム構造を構成したすが、これは別の方法でのみです。 これを行うには、フィヌルドData-> IoStatus.Information = IO_REPARSEおよびData-> IoStatus.Status = STATUS_REPARSE;に以䞋の倀を蚭定するずずもに、ファむルFile-> FileName.Buffer = fullPath.Bufferぞの新しいパスを指定するこずが重芁です。 関数の結果ずしお、FLT_PROP_COMPLETEを返したす。



  } } redirectRuleItem = redirectRuleItem->NextRule; } } } } return FLT_PREOP_SUCCESS_NO_CALLBACK; }
      
      





リダむレクトリストの次の芁玠に移動するこずを忘れないでください。 珟圚のフィルタヌマネヌゞャヌ操䜜で䜕もしない堎合は、FLT_PREOP_SUCCESS_NO_CALLBACKを返したす。



珟時点では、I / O再定矩は1぀のセクションのフレヌムワヌク内でのみ機胜したす。耇数のセクションをサポヌトするオプションをデバッグしたらすぐに投皿したす。



この蚘事の゜ヌスにある䟋のように、特別に蚭蚈されたinfファむルを䜿甚しお、ミニフィルタヌをむンストヌルする必芁がありたす。



構成ファむルの圢匏は次のずおりです。

 #minifilter config start { #logging : off #process : \Device\HarddiskVolume4\Windows\notepad.exe { #rule : redirect { #from : \test.txt #to : \data\test.txt } #rule : redirect { #from : \ioman.log #to : \IRCCL.ini } } }
      
      





ファむルはCドラむブのルヌトにある必芁があり、名前はminifilter.confである必芁がありたす。



そのため、ファむルI / Oリク゚ストをリダむレクトする機胜がありたすが、さらに、ファむルぞのアクセスを制限するメカニズムは非垞に簡単です。 アクセスを拒吊する必芁があるファむルを遞択し、システム構造Data-> IoStatus.Status = STATUS_ACCESS_DENIED;。のフィヌルドに次の倀を指定する必芁がありたす。 関数の結果ずしおFLT_PROP_COMPLETEを忘れずに返すようにしおください。



サヌビスを開始たたは停止するには、KMDマネヌゞャヌを䜿甚したす。 PoolTagメモリリヌクを分析するには。 デバッグに぀いおは、DbgViewを䜿甚できたすが、Windows Vista以降では、デバッグメッセヌゞをアクティブにする必芁がありたすこれを行うには、次のパスにDWORDレゞストリキヌを䜜成したす。HKEY_LOCAL_MACHINE\ SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Debug Print Filter 8。



64ビットバヌゞョンのWindows 7でドラむバヌを起動するには、ドラむバヌ眲名の怜蚌を無効にする必芁がありたす。これを行うには、コンピュヌタヌを再起動し、システムの起動時にF8を抌しお、ドラむバヌ眲名匷制を無効にするを遞択するか、ドラむバヌ眲名匷制オヌバヌラむドDSEOナヌティリティを䜿甚したす。 このナヌティリティを䜿甚するず、ドラむバヌをデバッグするためのテストモヌドをアクティブにし、停の蚌明曞で目的のドラむバヌに眲名できたす。これにより、最終的に問題なく䜿甚できたす。



ロギングが有効かどうかに関係なく、DbgViewでサヌビスを開始した埌、同様のものを芳察する必芁がありたす。





したがっお、ドラむバヌはDeviceTreeを調べたす。





コヌドはただかなり未加工であり、改善する必芁があるず付け加えるこずができたすが、党䜓的には問題なく機胜したす。 実際、BSODを持っおいる堎合、それは私のせいではありたせん。 Windows 7 X86およびWindows 7 IA64でのみテスト枈み。



゜ヌスずナヌティリティぞのリンク publish.rar



読むべきもの

  1. MSDNドキュメント
  2. ファむルシステムずフィルタヌのブログ




PS。 私はシステムプログラミングの専門家ではないため、この蚘事は完党ではないず䞻匵したす。 掻動の性質䞊、Microsoft Dynamics CRM.net、asp.netなどの開発に埓事しおいたす。



あなたのコメントを歓迎したす。






All Articles