Minispy File System Minifilter Driver サンプルを動かしてみる
今回は、ファイルシステムミニフィルタ ドライバのサンプル Minispy File System Minifilter Driver をご紹介します。
このサンプルは、システム上の任意の I/O を監視しログに記録する方法を示すサンプルです。
Minispy は、ユーザーモード アプリケーションの minispy.exe とカーネルモード ドライバの minispy.sys で構成されています。Minispy.sys が、様々なI/O に対応するコールバックを、フィルタマネージャに登録します。このコールバックが、システム上の任意のI/O を記録します。ユーザーが、この記録された情報を要求した時に、minispy.sys がminispy.exe にその情報を渡し、minispy.exe が画面上に出力、またはファイルにログしていきます。
あるデバイス上のI/O を監視するためには、minispy.exe を使って、明示的に minispy.sys をそのデバイスにアタッチする必要があります。あるデバイス上の I/O の監視をやめる場合もminispy.exe を使います。
今回は、このサンプルをWindows 10 (1709) x86 にインストールして、C ドライブ上で監視した I/O の情報がコマンドプロンプトやファイル上に出力されるところをお見せしたいと思います。サンプルをビルドする、開発側のPC はWindows 10 (1709) x64 にVisual Studio 2017 とWDK for Windows 10 Version 1709 がインストールされています。
1. サンプルの入手
Minispy File System Minifilter Driver サンプルは、以下のサイトの右側の緑色の [Clone or Download] ボタンを押すと表示される [Download ZIP] ボタンでWindows-driver-samples-master.zipをダウンロードすると、Windows-driver-samples-master\filesys\miniFilter\minispy のフォルダにあります。
https://github.com/Microsoft/Windows-driver-samples
2. サンプルのビルド
このフォルダのminispy.sln を、Visual Studio 2017 で開きます。Filter の方がminispy.sys、User の方が minispy.exe のプロジェクトです。
[ ソリューション ‘minispy’] を右クリックして [構成マネージャー] をクリックします。
今回は、[アクティブソリューション構成] を [Debug] 、[アクティブ ソリューション プラットフォーム] を [Win32] とします。
また、minispy.exe 側でVisual C++ Runtime (VCRUNTIME14D.dll) のインストールを省略するために、User フォルダの下のプロジェクトminispy を右クリックして [プロパティ] を開き、[構成プロパティ]-[C/C++]-[コード生成]-[ランタイム ライブラリ] を [マルチスレッド デバッグ(/MTd)] に変更します。
[ソリューション ‘minispy’] を右クリックして[ソリューションのリビルド] をクリックします。
これで、minispy.sys とminispy.exe ができます。
次のステップに必要なファイルと場所は以下です。
ファイル |
場所 |
minispy.sys |
\minispy\filter\Debug\minispy |
minispy.exe |
\minispy\user\Debug |
minispy.inf |
\minispy |
3. サンプルのインストールと動作確認の準備
上記のファイルをWindows 10 (1709) x86 の環境にコピーします。例えば、C:\minispy というフォルダを作って、そこに置きます。minispy.inf を右クリックして、[インストール] をクリックすれば、インストールできます。
インストールしても、以下のようにまだこのサンプルドライバはロードされていません。(fltmc.exe の使い方の詳細は、以前の記事「fltmc.exe の使い方」<https://blogs.msdn.microsoft.com/jpwdkblog/2013/02/27/fltmc-exe/> をご参照ください。)
>fltmc
フィルター名 インスタンス数 階層 フレーム ------------------------------ ------------- ------------ ----- WdFilter 3 328010 0 storqosflt 0 244000 0 wcifs 1 189900 0 CldFlt 0 180451 0 FileCrypt 0 141100 0 luafv 1 135000 0 npsvctrig 1 46000 0 Wof 2 40700 0 FileInfo 3 40500 0 |
そこで、以下のコマンドでこのサンプルドライバをロードします。
> fltmc load minispy |
これにより、以下のようにminispy がロードされています。ただ、まだインスタンス数が 0 であることから、ボリュームへのアタッチはされていません。
>fltmc
フィルター名 インスタンス数 階層 フレーム ------------------------------ ------------- ------------ ----- Minispy 0 385100 0 WdFilter 3 328010 0 storqosflt 0 244000 0 wcifs 1 189900 0 CldFlt 0 180451 0 FileCrypt 0 141100 0 luafv 1 135000 0 npsvctrig 1 46000 0 Wof 2 40700 0 FileInfo 3 40500 0 |
なお、上記まで行わないと、minispy.exe の実行時に以下のエラーが出ます。
C:\minispy>minispy Connecting to filter's port... Could not connect to filter: 0x80070002 |
上記のminispy.sys のロードを行うことで、minispy.exe を以下のように実行できるようになります。
C:\minispy>minispy Connecting to filter's port... Creating logging thread...
Dos Name Volume Name Status -------------- ------------------------------------ -------- \Device\Mup C: \Device\HarddiskVolume2 \Device\HarddiskVolume1 \Device\NamedPipe \Device\Mailslot
Hit [Enter] to begin command mode... |
最後の行の指示通り、Enter を押すと、コマンドが入力できるようになります。
? を入力して、どのようなコマンドがあるか見てみます。
>? Valid switches: [/a <drive>] [/d <drive>] [/l] [/s] [/f [<file name>]] [/a <drive>] starts monitoring <drive> [/d <drive> [<instance id>]] detaches filter <instance id> from <drive> [/l] lists all the drives the monitor is currently attached to [/s] turns on and off showing logging output on the screen [/f [<file name>]] turns on and off logging to the specified file If you are in command mode: [enter] will enter command mode [go|g] will exit command mode [exit] will terminate this program > |
オプションを表にすると以下の通りです。
オプション |
説明 |
/a <ドライブ> |
<ドライブ> の監視を開始します。/a は、minispy.sys をそのドライブに「アタッチ」するということです。 |
/d <ドライブ>[<インスタンスID>] |
<インスタンスID> のminispy.sys を<ドライブ> からデタッチします。これにより監視を停止します。 |
/l |
現在minispy.sys により監視しているすべてのドライブをリストします。 |
/s |
スクリーンへのログ出力をON/OFF します。(デフォルトはON です。) |
/f [<ファイル名>] |
ファイルへのログ出力をON/OFF します。 ON の時は<ファイル名> が必須で、OFF の時は<ファイル名> が不要です。 |
コマンドモードについては以下の操作ができます。
・Enter を押せばコマンドモードに入ります。
・go またはg を入力すれば、コマンドモードから抜けます。
・exit を入力すれば、minispy.exe を終了します。
ここまでを理解したら、コマンドモードのまま、以下を実行して、C ドライブにアタッチしてみましょう。
>/a c: Attaching to c:... Instance name: Minispy - Top Instance |
実際、/l オプションを実行したら、C ドライブにアタッチできている(Status がAttached) と出力されます。
>/l
Dos Name Volume Name Status -------------- ------------------------------------ -------- \Device\Mup C: \Device\HarddiskVolume2 Attached \Device\HarddiskVolume1 \Device\NamedPipe \Device\Mailslot > |
4. サンプルの動作確認
以上で準備ができたので、動作確認として、C ドライブ上で監視した I/O の情報がコマンドプロンプトやファイル上に出力されるところをお見せしたいと思います。
コマンドモードのまま、g を入力して、スクリーン上にログを出力します。
>g Should be logging to screen... Opr SeqNum PreOp Time PostOp Time Process.Thrd Major/MinorOperation IrpFlags DevObj FileObj Transact status:inform Arguments Name --- -------- ------------ ------------ ------------- ----------------------------------- ------------- -------- -------- -------- ----------------- ----------------------------------------------------------------- ----------------------------------- IRP 00000D69 14:43:32:574 14:43:32:634 4.a54 IRP_MJ_WRITE 00060a01 N--- 8DF72388 8DF74398 00000000 00000000:00001000 1:00001000 2:00000000 3:0006F000 4:00000000 5:9F1BC000 6:00000000 \Device\HarddiskVolume2\ProgramData\Microsoft\Windows Defender\Support\MpWppTracing-03172018-123129-00000003-ffffffff.bin IRP_MN_NORMAL |
上記は、出力のヘッダの部分と、最初のログの一行を抜粋しています。実際には、全部一行で表示できるようにコマンドプロンプトの設定を調整するか、ファイルに出力して、ヘッダの行とログの行の各項目の対応関係がわかるようにした方が、わかりやすいと思います。
上記の例を表にすると、以下のようになります。
ヘッダ |
意味 |
ログ出力例 |
Opr |
IRP、Fast I/O、FsFilter のいずれかのオペレーション IRP:FLT_CALLBACK_DATA_IRP_OPERATION FIO:FLT_CALLBACK_DATA_FAST_IO_OPERATION FSF:FLT_CALLBACK_DATA_FS_FILTER_OPERATION |
IRP |
SeqNum |
シーケンス番号 |
00000D69 |
PreOpTime |
Pre-operation コールバックが呼ばれた時刻 |
14:43:32:574 |
PostOpTime |
Post-operation コールバックが呼ばれた時刻 |
14:43:32:634 |
Process.Thrd |
プロセスID とスレッドID |
4.a54 |
Major/MinorOperation |
Major Function とMinor Function |
IRP_MJ_WRITE IRP_MN_NORMAL |
IrpFlags |
IRP のフラグ。 値に以下が含まれるかどうかをアルファベット一文字でも示す。 N:IRP_NOCACHE P:IRP_PAGING_IO S:IRP_SYNCHRONOUS_API Y:IRP_SYNCHRONOUS_PAGING_IO |
00060a01N--- |
DevObj |
デバイスオブジェクトのアドレス |
8DF72388 |
FileObj |
ファイルオブジェクトのアドレス |
8DF74398 |
Transact |
FLT_RELATED_OBJECTS 構造体のTransaction |
00000000 |
status:inform |
FLT_CALLBACK_DATA 構造体のIoStatus.Status とIoStatus.Information |
00000000:00001000 |
Arguments |
引数 Arg1 ~ Arg6 は、それぞれ、Data->Iopb->Parameters.Others.Argument* |
1:000010002:00000000 3:0006F000 4:00000000 5:9F1BC0006:00000000 |
Name |
ファイル名 |
\Device\HarddiskVolume2\ProgramData\Microsoft\Windows Defender\Support\MpWppTracing-03172018-123129-00000003-ffffffff.bin |
続いて、ファイルに出力してみます。/f の後にファイル名を指定して実行後、g を入力します。
>/f c:\minispy\log.txt Log to file c:\minispy\log.txt >g Should be logging to screen... IRP 0000DDD2 15:26:04:616 15:26:04:616 4.a54 IRP_MJ_WRITE 00060a01 N--- 8DF72388 8DF74398 00000000 00000000:00001000 1:00001000 2:00000000 3:001C9000 4:00000000 5:9F15E000 6:00000000 \Device\HarddiskVolume2\ProgramData\Microsoft\Windows Defender\Support\MpWppTracing-03172018-123129-00000003-ffffffff.bin IRP_MN_NORMAL |
ファイル出力をやめるために、Enter を実行してコマンドモードにし、/f を入力します。(ファイル出力を止めない状態でログを開こうとすると、別のプロセスが使用中というエラーになります。)
>/f Stop logging to file |
ログファイルを開いてみます。以下のように上記と同じログがありつつも、コマンドプロンプト(スクリーン) 上に表示されるよりも多く記録されていました。
上記の内容が、ファイルシステムミニフィルタドライバを開発される方のお役に立てば幸いです。
WDK サポートチーム 津田