ShimCache を解析する:Windows 10 と 11 のバイナリフォーマット

読了 2 分

TL;DR. 先頭の u32 = ヘッダサイズ、通常 0x30 から 0x36。そのオフセットで各エントリは 4 バイトのマジック 10ts で始まり、12 バイトのヘッダと可変長ボディが続きます。UTF-16LE のパス(長さプレフィックス、ヌル終端なし)、FILETIME mtime、末尾のデータ Blob。実行フラグは Windows 10 で削除されました。

XP 以降のすべての Windows リリースは異なる AppCompatCache レイアウトを出荷してきました。Windows 10/11 のバリアントは、調査員が日々最も目にするもので、落とし穴の場所を知れば最も寛容なフォーマットです。これは、私が最初に手作りのパーサを試したときに欲しかった解説です。

Windows 10/11 ShimCache バイナリエントリのレイアウト

解析するブロブ

次の場所にあるバイナリ値から始めます。

HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache\AppCompatCache

SYSTEM ハイブから抽出してください(ShimCache の保存場所 を参照)。得られるのは単一のブロブで、典型的には数十から数百キロバイトです。小さなヘッダの後に、既知のマジックで始まる一連のエントリが続きます。

ヘッダ

ブロブの先頭 4 バイトのリトルエンディアンは、最初のエントリのオフセットです。Windows 10/11 ではビルドに応じて 0x30、0x34、0x35、0x36 が一般的です。一部のハイブはここに 0x80 を持ち、これは依然として 10ts / 00ts エントリシグネチャを使用する Windows 8.x レイアウトを示します。

ヘッダサイズをハードコードしないでください。先頭の u32 を読み、そのオフセットのバイトが認識可能なエントリの開始であることを検証してください。宣言されたオフセットに 10ts も 00ts も現れない場合、前方に 10ts をスキャンしてそこから拾います。実際のハイブはわずかに仕様外のデータを出荷することがあり、最初のバイト不一致でバイルするパーサは案件を負けるパーサです。

Windows 10/11 エントリ、バイトごと

各モダンエントリは 4 バイトのシグネチャ 10ts(0x31 0x30 0x74 0x73)で始まります。フルレイアウト:

オフセットサイズフィールド
0x004マジック、"10ts"
0x044シーケンス / 不明、しばしば無視
0x084エントリデータサイズ、このフィールド以降のバイト数
0x0C2パスサイズ(バイト、UTF-16LE)
0x0ENパスバイト、UTF-16LE、終端なし
0x0E + N8最終更新時刻、FILETIME(1601-01-01 UTC からの 100 ナノ秒単位)
0x16 + N4末尾データサイズ
0x1A + NM末尾データ、通常空または小さい

エントリ合計サイズは 0x0C + entry_data_size です。次のエントリはその直後から始まります。

実用的な 2 点:

  1. パスは UTF-16LE で、ヌル終端されていません。 パスサイズフィールドを使ってください。ゼロまで読み続けると、次のエントリのヘッダを食べてしまいます。
  2. FILETIME はファイルの $STANDARD_INFORMATION mtime です。 プログラムが実行された時刻ではありません。エントリが挿入された時刻でもありません。検査時に NTFS から直接コピーされたファイルの mtime です。実行証明の投稿 でこれが重要な理由を扱っています。

Windows 10 で削除されたもの

それ以前の Windows バージョンでは、各エントリ内に Executed フラグが詰め込まれていました。Win7 と 8.x のアナリストはそれを読むことを学びました。Windows 10 はそれを削除しました。Windows 11 でも復活しませんでした。バイナリが実際に実行されたかを示すキャッシュ内の方法はありません。Prefetch、AmCache、または EVTX / Sysmon が必要です。

レガシーフィールドレイアウト(XP から 8.1)については、レガシー ShimCache フォーマット を参照してください。

実践での解析

レビューを通過するパーサ:

  1. ヘッダが通知するオフセットの 4 バイトマジックを検証します。
  2. エントリデータサイズフィールドを読み、進めることで、エントリを反復します。
  3. 長さプレフィックスを使ってパスを UTF-16LE としてデコードします。
  4. FILETIME を下流のツールが好むタイムスタンプ形式に変換します。Unix ミリ秒は便利です。ISO 8601 UTC はレポートが実際に求めるものです。
  5. 検出された OS フォーマットラベル(Windows 10/11 vs 8.x vs 8.0)を下流のフィルタリングのために露出させます。
  6. 値を読み取る前に SYSTEM.LOG1 と SYSTEM.LOG2 を再生します。パーサがこれをしない場合、それは古いハイブを読んでいます。

オープンソースの Shimcache Parser は手順 1〜5 を Rust で実装し、WebAssembly としてブラウザに出荷します。単一のハイブファイルを読み、トランザクションログの再生は行わないため、dirty なハイブは先に rla.exe または Registry Explorer で処理してください。サーバなし、アップロードなし。SYSTEM ハイブが規制環境から来ているとき有用です。

さらに読む

関連記事