Process Monitor(procmon.exe)
ファイルI/O・レジストリ・プロセス/スレッド活動をリアルタイムに監視できるSysinternalsのツール。Advanced Outputを有効にすると、IRPやファストI/Oのカーネル側の語彙で操作を表示する。
環境依存の不具合調査
特定の環境や端末でだけ起きる不具合の原因を、コードを読むより先に、実際に何が起きたかの記録(ファイル・レジストリアクセスなど)から特定していく調査の進め方。
再現条件の絞り込み
「設定が反映されない」調査
ProcMonのフィルタ(2段階絞り込み)
まずProcess Nameで対象プロセスにIncludeを掛け、次にResultで異常系に絞るというProcMon利用の定石。フィルタは表示上の絞り込みで、裏では既定で全イベントが記録される非破壊フィルタである。
Process Name → Resultの絞り込み
PMLファイル(Process Monitor Log形式)
ProcMonがイベントを保存できるネイティブ形式のログファイル。全カラム・全詳細(スタックを含む)を保持し、別のマシンのProcMonでそのまま開ける。
ブートタイムロギング(Enable Boot Logging)
次回起動時のブート初期からのイベントを記録するProcMonの機能。サービスがログオン前に失敗する等、ProcMonを手で起動するより前に問題が起きるケースの調査に使う。
NAME NOT FOUND(Result値)
ProcMonのResult列に出る、指定パスに名前が存在しないことを示す値。探索順の途中経過であることが多く、最後にSUCCESSがあるかどうかまで見て初めて異常かどうかを判断できる。
ACCESS DENIED(Result値)
ProcMonのResult列に出る、アクセス拒否を示す値。権限・ACL・ウイルス対策・保護領域への書き込みなど、原因の可能性が高いResult値とされる。
SHARING VIOLATION(Result値)
ProcMonのResult列に出る、他のプロセスが排他的にファイルを開いているために生じる共有違反を示す値。ファイルロックの競合原因の特定に使う。
共有違反
BUFFER OVERFLOW(Result値)
ProcMonのResult列に出る、呼び出し側が用意したバッファより必要なデータが大きかったために必要サイズを返した、という正常なAPIの往復を示す値。セキュリティ用語のバッファオーバーフロー攻撃とは無関係。
DLLの検索順序
Windowsが実行ファイルの起動時に限らず、LoadLibrary系APIによる動的な読み込み時も含めて、DLL redirectionやKnown DLLsなどの前段ルールを経てDLLを探す、決まった順序でフォルダーを辿る仕組み。
DLL探索順
VirtualStoreへの仮想化
Program Files配下など管理者権限が必要な場所への書き込みが、実際にはユーザーごとのVirtualStoreフォルダーへリダイレクトされ、読み書きが別の場所に化けるWindowsの互換機能。
ファイル・レジストリの仮想化
WOW64リダイレクト
32bitプロセスからのシステムフォルダーやレジストリへのアクセスが、WOW64によって別のビューへ自動的に振り替えられる仕組み。見ているつもりの場所と実際にアクセスする場所がずれる原因になる。
WOW64ファイルシステムリダイレクター
Process Explorer
プロセスに読み込まれているDLLだけでなく、ハンドル・スレッドスタック・GDI/USERオブジェクト数なども確認できるSysinternalsのプロセス監視ツール。管理者として実行すると他ユーザーやサービスのプロセスも参照できる。
管理者権限
コンピューター全体の設定を変更できる権限。
昇格
ハンドルリーク
参照カウントやハンドルカウントの数え違いなどにより、不要になったハンドル(ファイル・イベント・スレッド・GDIオブジェクト・アクセストークンなどカーネルオブジェクトへの参照)が解放されずに積み上がっていく状態。
パケットキャプチャによる通信調査
通信プロトコルレベルの調査のために、WiresharkやWindows標準のPacket Monitor(pktmon)でパケットの中身を採取・解析すること。
PerfView / dotnet-trace
CPUサンプル・GC・アロケーションなど、.NETアプリケーションの「遅い」の原因を定量的に調査するためのプロファイリングツール群。
WinDbg
クラッシュダンプやハングしたプロセスの状態をカーネル/ユーザーモードで解析するためのMicrosoft製デバッガー。SOS拡張によるマネージドヒープ解析や、Application Verifierの検出結果の解析にも使われる。
Application Verifier
Windowsのuser-modeアプリに対するランタイム検証ツールで、OS API利用や資源の扱い方を監視し誤用の検出や意図的な失敗の注入を行う。
環境依存の不具合調査で最初にやるべきことは、コードを読むことではなく、ProcMonで実際に何が起きたかの記録を取ることである
ProcMonは絞り込んでから読むツールで、まずProcess Nameで対象プロセスに絞り、次にResultで異常系に絞る2段階フィルタが定石になる
ProcMonのログはPMLファイルとして保存すれば、別のマシンでも全カラム・全詳細を確認できるため、顧客環境で採取して自社で解析する分業が成立する
サービスがログオン前に失敗するなど、ProcMonを手動起動するより前に起きる問題にはEnable Boot Loggingでブート初期からのイベントを記録する
ProcMonのResult列にはNAME NOT FOUNDのような値が表示され、探索順の途中経過か本当に見つからないのかを連なりで判断する
ProcMonのResult列にはACCESS DENIEDが表示され、原因の可能性が高い結果として調査の起点になる
ProcMonのResult列にはSHARING VIOLATIONが表示され、時系列で前後の行を見ることでファイルを掴んでいる相手を特定できる
ProcMonのResult列にはBUFFER OVERFLOWのような一見異常に見えるが実際は正常なAPIの往復を示す値も表示される
DLLが見つからない、または意図しないDLLを掴んでいる問題は、Pathに対するNAME NOT FOUNDの連なりが探索順どおりに並び、最後にSUCCESSがあるかどうかで確認できる
Program Files配下への書き込みがVirtualStoreへ仮想化されているかどうかは、ProcMonのPath列に出る実際の読み書き先を見れば分かる
32bitプロセスがWOW64のリダイレクトを受けて意図と違う場所を見ている場合も、ProcMonのPathに実際のアクセス先が出るため確認できる
「今この瞬間、誰が同じファイルを掴んでいるか」を知りたいだけなら、ProcMonよりProcess Explorerのハンドル検索の方が速く確認できる
ProcMonはカーネルドライバーを読み込むため、起動には管理者権限(UACの昇格)が必要になる
長期稼働でハンドルやメモリが増え続ける原因は、Process Explorerでハンドル数やDLLの状態を観察することで確認できる
ProcMonはTCP/UDPの接続イベントは記録するがパケットの中身までは見えないため、プロトコルレベルの調査に用いるのは推奨されない
CPUをどこで使っているかの本格的なプロファイリングにProcMonを用いるのは推奨されず、PerfViewやdotnet-traceの領分になる
クラッシュ・ハングの瞬間のメモリとスタックの解析にProcMonを用いるのは推奨されず、WinDbg+ダンプの領分になる
ヒープ破壊やハンドルの二重解放などAPIの誤用の検出にProcMonを用いるのは推奨されず、Application Verifierの領分になる