process_history更新 v1.10
すべてのプロセスの開始時間と終了時間を記録します。2000 SP4/XP SP2/Vista SP1にて動作します。作業時間の把握とかに使えるかもしれませんね。よければどうぞー(process_history.cab)。
アーカイブはドライバとその利用サンプルEXEで構成されています。ドライバをロードする機能は提供されていないので ldsys あたりを利用してください。
更新に伴う技術メモ
カーネルモードのミューテックス
ExInitializeFastMutexで初期化し、ExAcquireFastMutexでシリアライズ(待機)、ExReleaseFastMutexでミューテックスを開放する。カーネルモードでは半ば強制的に並列プログラミング+共有リソース操作になるので、これは勉強になった。
システム起動後の経過時間の算出
システム起動後の割り込み回数を取得し、割り込みが発生する時間間隔で乗算する。コードにすると以下。
LARGE_INTEGER ElapsedTime; KeQueryTickCount(&ElapsedTime); ElapsedTime.QuadPart = ElapsedTime.QuadPart * KeQueryTimeIncrement();
KeQueryTickCount の戻り値は特定の操作でリセットされるらしく、時折、smss.exeなどの開始時間がシステム起動時間より過去になることがある。しかしこれはこれで正しいらしく、Process Explorer などでも同様の現象が確認できた。
余談だが LARGE_INTEGER とカーネルモードで変換可能な TIME_FIELDS 構造体があるが、これは SYSTEMTIME 構造体とは似て非なるものでユーザーモードで受け取っても処理に困るだけだったりする。
フルパスを取得しない理由
当初バージョンアップ時に取得する予定であったが、実現困難により中止した。
プロセスのフルパスは PEB 構造体経由で取得することができ、フルパスを得るまでの構造体定義はドキュメント化されている(PEB::RTL_USER_PROCESS_PARAMETERS::ImagePathName)。これをプロセス生成時の通知ルーチンの中で取得すれば良いものと考えていたが、実際に試してみると、通知ルーチンが呼び出される段階ではPEB構造体が初期化されていないことが判った。
おそらくユーザーモードの情報が初期化されていない段階なのだろうが、なんにせよこれ以外のタイミングでスマートに取得する方法が思いつかなかった。過去に扱ったAPCの利用も考えたが、安全に実装する自信が持てなかったため諦めた。
また2000に限定すれば EPROCESS にある pImageFileName メンバを参照すればおk。でもXP/Vistaにはないっぽい。。。
kd> dt nt!_eprocess nt!_EPROCESS +0x000 Pcb : _KPROCESS ... +0x284 pImageFileName : Ptr32 _UNICODE_STRING
05/11追記
XP/Vistaにも近いものはあった。でもいいや、もう。
OS | フィールド名 | オフセット | 値の例 |
---|---|---|---|
2000 SP4 | pImageFileName | _EPROCESS+0x284 | \WINNT\regedit.exe |
XP SP2 | SeAuditProcessCreationInfo::ImageFileName::Name | _EPROCESS+0x1f4 | \Device\HarddiskVolume1\WINDOWS\system32\regedit.exe |
Vista SP1 | SeAuditProcessCreationInfo::ImageFileName::Name | _EPROCESS+0x1cc | \Device\HarddiskVolume1\WINDOWS\system32\regedit.exe |
EPROCESS構造体のExitTimeを取得しない理由
簡単には実現できなかったためだ。
プロセス通知ルーチンにプロセスの破棄が通知された時点での PsLookupProcessByProcessId 呼び出しは失敗するらしい。そのため、せっかく受け取ったPIDから EPROCESS を得ることができない。カレントの EPROCESS から ActiveProcessLinks を辿れば得られないこともないが、KeQuerySystemTime を使えば現在時刻は取得できるため、リスクに比して得られるものがないと判断した*1。
ちなみにプロセス生成時の通知でも、PIDを利用した操作のいくつかが失敗する。時折 STATUS_ACCESS_VIOLATION を返す(例外発生ではない)こともあるようなので、通知ルーチン内でのプロセス操作APIは疑ってかかるように。