a tale of volatile memories.
だからWindowsは神様だ。
はじめに
インシデント対応で証拠保全をするとき、メモリ(RAM)も一緒に取得することが多いと思います。
ただ、取得したはいいものの「で、ここから何を見るの?」となりがち。
メモリには、ディスク上のファイルやログだけでは追えない情報が含まれています。
実行中のプロセスやネットワーク接続、ファイルキャッシュ、レジストリ、アプリケーションが扱っていたデータの断片など、調査対象はさまざま。
ログを読むようにはいかないので、ツールを使ってバイナリの中から必要な情報をDigっていく 感じ。なかなか難しめ。
メモリとは
メモリとひとくちにいってもいろいろある。
RAM上の 物理メモリ を指す場合もあれば、プロセスから見える 仮想メモリ を指す場合もあるのだが、OSやアプリケーションが動作中のコードやデータを置く場所、としてざっくり読んで貰えれば。
メモリは、情報を長期間保存しておくための媒体ではなく、OSやアプリケーションの動作に合わせて内容が書き換わり、プロセスの終了やメモリ領域の再利用によって、それまでの情報は失われていく。 また、電源供給が絶たれればデータはすべて吹き飛ぶ(揮発性)ので、侵害されたコンピュータの電源を落としてしまうと情報は永遠に失われてしまう。可能ならシャットダウンや再起動の前に保全しておきたい。
動作中のコンピュータからメモリの内容を取得することをライブ取得といい、それをファイルに保存したものをメモリイメージあるいはメモリダンプと呼ぶ。一般的にこのメモリイメージを一生懸命解析していくことになる。
メモリ効率のため、一部のデータをOSがディスクに書き出す場合がある(pagefile.sysなど)。それも補助的な調査対象になる。
メモリに残る情報
メモリには、プログラムのコード、スタックやヒープ、ロードされたDLL、プロセスやソケットの管理構造などが置かれる。これらを解析すると、取得時点でどのようなプロセスが動き、どのコマンドラインで起動され、どこへの接続があったのかを調べられる。
また、プロセスが掴んでいたファイルやレジストリのキャッシュが残っていることもある。例えば、攻撃者やローテートによって消去される前のレコードやEVTXの一部がメモリに残っていれば、ディスク側から追えなくなったイベントログを復元できる場合がある。
不要になったメモリ領域も、解放された瞬間に必ずゼロクリアされるわけではない。上書きされるまでの間、終了済みプロセスのデータ(URLやパスなど)が一部残存することもある。
物理メモリと仮想メモリ
プロセスから見える仮想メモリと、RAM上の物理的な配置は異なる。Windowsはページと呼ばれる単位でメモリを管理し、ページテーブルを使って仮想アドレスと物理アドレスを対応付けている。そのため、プロセスから連続して見える領域でも、物理メモリでは離れた場所に配置されていることがある。
この違いは、検索や復元の結果にも影響する。例えば、文字列が物理的に離れたページに分かれていると、物理メモリを先頭から検索するだけでは見つからないことがある。
そんなときは、ツールでページの対応付けを行い、プロセスの仮想メモリとして再構成してから検索すれば見つかる場合もある。
逆に、すでにプロセスから参照されなくなった断片は、物理メモリを直接走査した方が見つかることもあるので、どちらか一方が優れているとかそういう話でもない。
メモリの保全
保全時の注意点
ライブ取得には時間がかかります。取得ツールや保存先の速度にもよるが、体感では1GBあたり1分くらいかな。
バカデカメモリの場合は注意。
メモリ取得中もOSやアプリケーションが動いているため、イメージ内の領域ごとに取得時点がズレ、管理構造やデータの状態が食い違うこともある。この不整合はMemory Smearと呼ばれます。
メモリ外の保全対象
Windowsでは、下記のファイルにもメモリの一部あるいは全部が書き出されることがある。欠損部分を復元したり、過去の状態を調べられる場合があるため、可能なら一緒に保全しておくこと。
| ファイル | 含まれる情報 |
|---|---|
C:\pagefile.sys |
メモリから退避されたページ |
C:\swapfile.sys |
アプリケーションのメモリを退避するファイル。Windows 8/Server 2012以降のみ |
C:\hiberfil.sys |
休止状態やFast Startupで保存された状態 |
C:\Windows\MEMORY.DMP |
クラッシュ時などのメモリダンプ。含まれる範囲はダンプの種類による |
pagefile.sysやswapfile.sysをRAMの欠損部分の補完に使う場合は、できるだけ近いタイミングで取得すること。取得タイミングがズレると、再利用されたページを誤って結び付けてしまうことがある。
取得ツール
メモリを取得するツールは様々あるが、インシデント対応であれば Magnet RESPONSE のような収集ツールを使うとよい。メモリだけでなく、pagefile.sysや揮発性の高いデータ、主要なアーティファクトもまとめて保全してくれる。
以前は FTK Imager も有用な選択肢だったのだが、一時期うまくメモリが取得できないなどの不具合があり(現在は解消?)評判が落ちてしまった。悲しいね。
業界的にもMagnetのほうが最近は人気がある気がする。
日本国内においては、CDIR-Collector もよく使われている。メモリと主要なアーティファクトをまとめて保全できる。pagefile.sysは収集対象外だが、あまり気にしないというならばこっちで。
取得項目はcdir.iniで設定する。メモリを取得する場合はMemoryDump = trueを有効にしておき、cdir-collector.exeをカチカチすると保全できる。
どのツールを使う場合でも当てはまることだが、対象のWindowsのビルドやCPUアーキテクチャ、ドライバ読み込みの制約を含めて事前に試しておくこと。 調査対象が複数あるとか、後で解析しますという場合、取得後にファイルサイズがおかしくないか、プロセス一覧が読めるか程度は確認しておきたい。あとから取り直します、というのは難しい。
保全時の記録
後から取得時の内容を確認できるよう、次の情報は残しておきたい。
- 対象ホスト名
- 取得開始・終了時刻
- ツール名とバージョン、実行コマンドや収集設定
- 出力先、出力形式、取得ファイルのハッシュ
- エラーや読み取り失敗を含む取得ログ
Magnet RESPONSEの場合、これらの情報はログとして出力してくれるので安心。
休止ファイルの展開
ディスクからhiberfil.sysを保全できた場合は、Hibernation Reconなどで展開して解析する。
休止ファイル内のメモリデータは圧縮されているため、まず解析に使える形へ再構成する。
初回起動時にアクティベーション画面が出てくるが、Cancelで閉じるとFree Modeで起動できる。気に入ったらProfessional版のライセンスを買いましょう。
主な出力は下記。
| 出力 | 内容と使い道 |
|---|---|
ActiveMemory.bin |
保存されていたメモリを展開・再構成したもの。対応するメモリ解析ツールへ渡す |
RawSlackChunks/ |
現在の有効な保存データの外に残る領域(slack)。文字列検索やカービングの対象にしてもよい |
HibRec.log |
処理内容やエラーを確認するためのログ |
Fast Startupによるシャットダウン時に保存されたhiberfil.sysは、ユーザーセッション全体を含まないため、ライブ取得したメモリと同じ範囲を調べられるわけではない。休止状態のタイミングによっては、過去のメモリ状態と現在のメモリ状態の2つを手に入れられるので、点ではなく線の解析ができる。
解析の準備
調査目的
何を調べたいかによって調査項目は異なる。
たとえば、既知のマルウェアの痕跡を探すなら、特徴的な文字列やIOCでメモリイメージを検索しても良い。どのプロセスがどこへ接続していたかを知りたいなら、プロセスやネットワークの管理構造を調べる。
| 調査目的 | 作業内容 | 主なツール |
|---|---|---|
| 既知のドメイン、パス、コマンド、特徴的な文字列を検索したい | 文字列検索 | Strings、bstrings、ripgrep、ripgrep-all、langscan |
| 含まれるURLやメールアドレスを列挙したい | パターン検索 | bulk_extractor |
| 特定のバイト列や複数条件に一致する領域を探したい | ルール検索 | YARA |
| プロセス情報や通信先を調査したい | OSの管理構造に沿った解析 | Volatility、MemProcFS |
| メモリ上のファイルを抽出したい | ファイルオブジェクト、キャッシュの解析 | Volatility、MemProcFS |
| 管理構造が失われたファイルを抽出したい | カービング | foremost、scalpel、PhotoRec、bulk_extractor-rec |
本稿では、まずメモリイメージから文字列やファイルを探す方法を、次にOSの管理構造をたどる方法を紹介する。
環境構築
解析対象とOSは合わせておくと吉。WindowsならWindowsがいい。
文字列周りはLinuxのが触りやすい場合もあるので、SIFT Workstation あたりを使っても良い。
解析手法1: バイナリ解析
バイナリの構造を眺めるというよりは、正体不明のドデカバイナリから可読文字列をダンプして、とりあえずわかることを列挙する、的なアプローチ。
手軽にできるが、文字列が出てきただけでは、どのプロセスが何のために使ったものなのかまでは分からない。前後の文字列などからアタリをつけていく。 マルウェアの名前が見つかった!と思っても、よくよく見るとアンチウイルスソフトの定義ファイルかなにかだったりすることもよくある。多少疑ってかかるくらいの勢いで読もう。
文字列抽出
兎にも角にも、文字列を抽出しなければ話にならん。
ASCIIおよびUnicodeの文字列が既定で抽出される、Sysinternals Strings がおすすめ。
最小連続文字列長 -n は 6 とか 8 ぐらいでよいと言われている。何も出てこなければ適宜調整。
Linuxを使っていて、GNU Stringsなどでやるなら、必ず文字コードを意識して出力すること。
-t x を付けておくと、文字列が見つかったファイルオフセットも残る。あとで元のメモリイメージへ戻って周辺を確認したいときに便利。
-e lは入力をUTF-16LEとして読む指定。
出力の圧縮
メモリ全体から文字列を抽出すると、テキストファイルだけで数GBを超える。x100台とかになると手元の機器に置いとくのは厳しいかも。テキストは圧縮がよく効くので、gzipに流したっていい。
Windowsの標準環境にはgzipコマンドがないので、出力後に 7-Zip などでgzip圧縮するとよい。
進捗表示
メモリ程度のstringsで必要になることはあまりないが、進捗がわからないと落ち着かないという人は Pipe Viewer を使うと良い。
Linuxなら pv から入力ファイルを読み込ませると、処理済みサイズ、転送速度、進捗率、残り時間の目安を確認できる。
Windowsにはそんなものない。諦めよう。
文字列検索
既知の不審なドメインやファイル名などのIOC(侵害の痕跡を探すための指標)がある場合は、その値を検索する。 grepでもいいが、ripgrep のほうが爆速。
よく使うオプションは下記。
| オプション | 説明 |
|---|---|
-i |
大文字・小文字を区別しない |
-F |
正規表現ではなく固定文字列として検索する。 |
-f FILE |
検索パターンをファイルから1行ずつ読み込む。IOCをまとめて検索するなど |
-A NUM |
一致した行の後ろを指定行数表示する |
-B NUM |
一致した行の前を指定行数表示する |
-C NUM |
一致した行の前後をそれぞれ指定行数表示する |
-o |
一致した部分だけを表示する |
例えば、IOCを1行に1件ずつ書いたioc.txtがあるなら、下記のように前後3行と合わせて確認できる。
ただし、物理メモリ上で近くにある文字列が、同じプロセスや同じ時点のデータとは限らないので注意。
gzip圧縮している場合は、zgrepを使えばよい。ripgrep-all なら、圧縮ファイルもripgrepと同じ使い心地で検索できる。
langscanによる異言語検索
langscan を使うと、UTF-8テキストからキリル文字や日本語など、指定した言語で使われる文字を検索できる。必要に応じてUTF-8へ変換してから渡す。
キリル文字だけひっかけたいな~というときには次のように書けばよい。
exeファイル内に多言語対応処理が書かれている関係でノイズが非常に多くなったりもする。
後述のように、プロセス単位でダンプされたメモリなど狭い範囲で使うか、ざっと絞り込みたいときに使えば良い。
bstringsによるパターン検索
bstrings を使えば、よく使われる正規表現パターンで文字列の検索が可能。 パターン一覧は以下のように確認する。
お好みのものを検索すればよい。
バイナリに対しても、テキストに対しても検索できる。
よく使うのは下記辺り。
| パターン名 | 説明 |
|---|---|
| b64 | Base64文字列 |
| bitcoin | Bitcoinウォレットアドレス |
| bitlocker | BitLocker回復キー |
| cc | クレジットカード番号 |
| メールアドレス | |
| guid | GUID |
| ipv4 | IPアドレスバージョン4 |
| ipv6 | IPアドレスバージョン6 |
| mac | MACアドレス |
| reg_path | レジストリハイブに関連するパス |
| sid | セキュリティ識別子(SID) |
| unc | UNCパス |
| url3986 | RFC 3986準拠URL |
| win_path | Windowsファイルパス |
| zip | 米国郵便番号(ZIPコード) |
bulk_extractorによるパターン検索
IOCがまだ分からない段階では、bulk_extractorでURL、メールアドレスなどを一括抽出できる。ファイルシステムを解釈せず入力をバイト列として走査するため、メモリイメージも入力にできる。
主な出力は下記。詳しくは forensics.wiki を見るとよい。 出力されるファイルは、有効にしたスキャナや実際に見つかったデータで変わる。
| 出力ファイル | 説明 |
|---|---|
| ccn.txt | クレジットカード番号 |
| domain.txt | インターネットドメイン |
| email.txt | メールアドレス |
| ip.txt | IPアドレス |
| telephone.txt | 米国および国際電話番号 |
| url.txt | URL |
| url_searches.txt | URLから抽出したインターネット検索語。結構役に立つ率が高い。 |
| wordlist.txt | 単語候補のリスト。パスワードクラックなどに有用。 |
| zip.txt | ZIPファイルに関する情報。Office形式などもzipなので有用。 |
こうやって見つけた情報はまた別のところでも使うのでちゃんと整理しておきましょうネ。うまいこと一般化すれば強力な武器にもなる。
YARA検索
単純な検索では引っかからない場合や、マルウェアファミリはわかってるんだけどどう検索していいかわからない場合はYARA を使えばいい。
{malware-family} yara rule とかでググるとたくさん出てくる。必要に応じてカスタムしながら使うこと。ルール集ならこの辺。yara-rules/rules
Rust実装の YARA-X のほうが最近は開発が盛ん。ただし、一部のモジュールに依存したルールなどは動かないので注意。
ファイルカービング
ファイルヘッダやレコードの特徴を頼りに、ファイルやその断片を探す方法をカービングという。 メモリでは、ファイルの一部しか読み込まれていなかったり、物理的に離れたページに分かれていたりするので、不完全な復元となるケースが多い。画像ファイルの一部でも出てきたら儲けたな、ぐらいの期待度で。
foremost
老舗ツール。foremostは、ヘッダやフッタなどの特徴をもとにファイル抽出する。JPEGとPNGを探すなら次のように実行する。
scalpel
scalpelも有名。foremostをベースに改良されたやつ。
配布されているscalpel.confを作業用にコピーし、探したい形式の定義だけコメントを外して使う。
既定の設定ではすべて無効になっている。
PhotoRec
PhotoRec も定番。
アイコンが怪しいが、Autopsy にも組み込まれている実績のあるツール。対応フォーマットは400種類以上あるとか。
TestDiskに同梱されているので、ダウンロードしてqphotorec_win.exeを起動するとGUI版が使える。
bulk_extractor-rec
Bulk Extractor with Record Carvingは、bulk_extractorにレコード復元用のスキャナを追加したもの。EVTXのファイルやチャンク、MFTレコード、USNジャーナルなどを対象にできる。ファイル全体が残っていなくても、レコード単位なら復元できるかもしれない。
BE Viewerを開いて、Toolsからrun Bulk Extractorをクリックするとファイル選択ができる。
PhotoRecなどで抽出できなかったイベントログなどもかなり引っかかる。
解析手法2: 管理構造の解析
単純に文字列抽出とかではなく、OSの管理構造に沿って解析する方法。
あやしいプロセスの名前などが分かっている場合はその実行有無を調べればいいし、候補がなければプロセス一覧、コマンドライン、通信先などをひととおり出力しておいて後でゆっくり読めばいい。
MemProcFSとVolatilityが有名。
SANSの Memory Forensics Cheat Sheet も手元にあると便利。
MemProcFS
メモリから復元できるファイルやアーティファクトを横断的に見たい場合は、MemProcFSのforensic modeが便利。
マウント
Windowsでは Wiki に従ってDokanyなどを準備し、空いているドライブ(一般的には M:)へマウントする。
起動時に-forensicをつけてフォレンジックモードを有効にすることで、同じ入力イメージ・設定・MemProcFSバージョンでの解析結果を再現しやすくなる。マウント後に有効化すると、キャッシュや処理順序の違いから差異が出る可能性がある。
| モード | 意味 |
|---|---|
| 1 | メモリ上だけにSQLiteデータベースを作成 |
| 2 | 一時ファイルに作成し、MemProcFS終了時に削除 |
| 3 | 一時ファイルに作成し、MemProcFS終了後も保持 |
| 4 | 固定名のファイル(vmm.sqlite3)に作成し、MemProcFS終了後も保持 |
データベースの保存場所はM:\forensic\database.txtに書かれている。私の場合は下記だった。
解析の進捗状況は M:\forensic\progress_percent.txt に記録されるので、100になるまで待ってから、結果を確認する。
同時期に取得したページファイルがあるなら、対応する番号で追加できる。
各ページファイルにはインデックス番号が振られており、Windows 10の標準構成ではpagefile.sysに0、swapfile.sysに1が割り当てられる。
ページファイルを追加・変更した環境では番号が異なる場合があるので、対象環境の構成も確認しておく。
マウントすると、次のようなフォルダが見える。
| フォルダ | 説明 |
|---|---|
| conf | MemProcFSの状態と構成設定 |
| forensic | フォレンジック関連情報、めちゃ重要。 |
| misc | その他プラグインに関連する項目。物理アドレスから仮想アドレスを検索するphys2virtや、BitLockerキーを復元するbitlockerなどが置かれている。 |
| name | プロセス情報(名前ごと) |
| pid | プロセス情報(プロセスIDごと) |
| py | Pythonプラグイン関連。pypykatz regsecretsプラグインとか入れるとここに表示される。 |
| registry | レジストリハイブ。ページングなどによって破損している場合もある。 |
| sys | OS、ユーザー、プロセス、ネットワークなど、システム全体の情報。 |
| vm | 検出されたHyper-V仮想マシン、Windows Sandbox、WSL2など。VMware / VirtualBoxはHyper-V上で動作する構成が対象 |
主要なところだけさらっとみていく。
sys
システムに関する情報がいろいろある。まずはここを見ると良い。
タイムゾーンやバージョン情報、コンピュータ名などなど。
あとはproc/proc.txtあたりを見るとプロセスツリーが見れる。
同様に、users/users.txtでユーザー一覧、tasks/tasks.txtでスケジュールされたタスク一覧、net/netstat.txtでネットワーク接続などが見れる。
一通り見てからアタリをつけて掘り下げるといい感じ。
forensic
フォレンジック用にわかりやすくまとめたデータが置かれている。
とりあえず見るべきは csv, files, ntfs あたりかな。
csvには、プロセスやネットワーク接続などの解析結果がCSVで置かれている。Timeline Explorerなどで開くと見やすい。
findevilやyaraの検出結果もまとまっているので、まずここから眺めると楽。
M:\forensic\files\files.txtには復元されたファイルの一覧がある。気になるものがあれば、files配下からもらってきて分析しましょう。元パスと同様にフォルダが再構成されているので探しやすい。
NTFSでは、サイズの小さいファイルの内容がMFTレコード内に直接記録されることがある。filesに見当たらなければ、ntfs側を見るとよいかもしれない。
name / pid
どちらもプロセスに関する情報で、それがプロセス名別かPID別かというだけ。nameの方は末尾にプロセスIDがついているのでそっちのが見やすいかも。
name-longがプロセス名、pidがプロセスID、ppidが親のプロセスID、time-createが作成時刻、win-cmdlineがコマンドライン、win-environmentが環境変数。名前の通り。
まず見たいのはfiles/handlesあたり。プロセスが開いているファイルハンドルを手掛かりに再構築されたファイルがある。
files/modules はメモリ上のモジュールから再構築されたexeやdllなど。files/vads はVAD(Virtual Address Descriptor)を手掛かりに再構築されたファイル。VADは、プロセスの仮想メモリ領域と、その保護属性や対応するファイルなどを管理する構造である。
どの場所から復元した場合でも、ファイル全体がメモリに残っているとは限らない。そのまま読めれば嬉しい。
.evtxで検索するとイベントログが見つかったりする。ディスク側で削除されていても一部イベントの復元ができるかも。見つけたら調査してみるとよい 。
registry
名前の通りレジストリハイブ。ハイブファイルも置かれてるし、パースされたテキストもある。
個人的にはRegistryExplorerとかで見るほうが見やすい。が、壊れていることもよくある。
レジストリへの変更はメモリ上のハイブに反映され、トランザクションログ(.LOG1、.LOG2)を使いながらディスクへ書き戻される。そのため、メモリのほうがディスク上にあるものよりも新しい場合もある。見る価値はある。
Volatility
メモリ調査といえばこれ!のイメージだが、プラグインによってはマジで血管がブチ切れるぐらい時間がかかる。ざっと眺めるならMemProcFSのが早い。
とはいえ、こちらのほうがプラグインが充実しているので、処理かけてからご飯食べに行くとかそういう気持ちで。
vol-rs という高速なRust実装版もある。CTFとかならこういうの使ってもいいかもね。まだ成熟したプロダクトではないので、実務で使う場合は評価検証が必要だと思う。
Volatility 2と3がよく使われるが、最近のOSなら3でいい。たまに古代の発掘品とかが来たときは2じゃないと動かないときもある?どちらも用意しておくとよい。
また、Volatilityは慣れないと使いづらい。Volatility Workbench やKaniVola などのラッパーを使うとかなり楽。コマンドをカチャカチャ打つほうが気持ちいいのはわかるのだが、実際インシデント対応してるときにそんな暇はないことがほとんど。
3系ならVolatility Workbenchがすごく使いやすい。
2系ならKaniVolaがよい。
以下はVolatility 3をコマンドラインから実行する前提での解説。Volatility Workbenchを使っている場合は、対応するプラグインを選択して、PIDなどのオプションを設定すればよい。
シンボル情報
Volatility 3は、Windowsのメモリ内の構造を解釈するためにシンボル情報を使う。必要なシンボルがローカルにない場合はMicrosoftのサーバから自動取得するので、その際にはインターネット接続が必要になる。
私はオフライン絶対至上主義なので、あらかじめシンボル情報をローカルに準備しておく。 JPCERT/CC - オフラインでVolatility 3を実行する方法 が非常に参考になる。
これを自動化するようなスクリプトを書いておくと実際対応するときに助かる。
一方、Volatility 2では、対象OSに対応する構造体の定義などをまとめたプロファイルを--profileで指定する。違うプロファイルを使うと、一見読めているようでも値を誤って解釈することがあるので注意。
基本情報
まずはwindows.infoでOSやカーネルの情報が読めるかを確認する。ここで失敗する場合は、取得形式、イメージの欠損、シンボルの取得状況などを確認してから先へ進む。
プロセス一覧
実行中のプロセスと親子関係、実行時コマンドラインを保存する。 プロセス名だけ見ても怪しいかどうか判別は難しい。実行パス、親プロセス、起動引数、実行ユーザーなどの観点を組み合わせて確認する。
正規名に似たプロセスや、C:\Users\Publicなどの悪用されがちなフォルダから起動された実行ファイルは掘り下げるべき。
pslistはOSが管理するプロセスのリストをたどり、pstreeは同じ列挙結果を親子関係で表示する。
親プロセスがすでに終了していれば一覧にいないこともあるし、PIDが再利用されていると、同じPIDの別プロセスを親と見誤ることもある。親子関係を読むときは作成時刻も確認する。
psscanは、カーネルがメモリを割り当てるpool領域を走査してプロセスの構造体を探すため、終了済みあるいは隠蔽されたプロセスも検出できる場合があるが、時間がかかる。裏で実行しながらコーヒー飲んでpslistとかを眺めておけば良い。
psxviewを使うと、複数のプロセス列挙方法の結果を突合してくれる。pslistにはないけどpsscanにはあった、とか。
プロセスの詳細
候補をPID 4240などに絞れたら、そのプロセスが何を読み込み、何を参照していたかを調べる。ハンドルはファイル、レジストリキー、他のプロセスなどのオブジェクトを参照するための識別子で、調査対象を広げる手掛かりになる。
dlllistで読み込まれたDLLのパスや配置を確認し、handlesで参照しているファイルやレジストリキーなどを確認する。カーネルのモジュールを列挙するwindows.modulesとは、調べる対象が異なる。
例えばコマンドラインに一時ディレクトリ上のスクリプトがあれば、そのファイル名を検索や復元の対象にする。ハンドルに文書のパスがあれば、関連するファイルやアクセスの痕跡をディスク側でも確認する。ハンドルの存在だけでは、ファイルの全内容を読んだことや外部へ送信したことまでは分からない。
コマンド履歴
プロセスの起動引数はcmdline、コンソールに残っている入力履歴はcmdscanで調べる。たとえばcmd.exeを起動した後に何を入力したか知りたい場合は、こちらも試しておく。
取得できるのは対応するコンソールの履歴構造がメモリに残っている範囲なので、すべてのシェル操作を復元できるわけではない。PowerShellの履歴やスクリプトの実行内容は、PSReadLineの履歴ファイルやPowerShellログなども照合する。
ネットワーク接続
ネットワークの管理構造を調べるならnetscanを使う。
見つかったPIDをプロセス一覧や作成時刻と照合し、そのプロセスを追加で調べる。終了済み・解放済みの構造が残る場合もあるので、StateやCreatedも読む。Createdはネットワークオブジェクトの作成時刻を示す。
また、netscanから通信内容や転送量は得られない。
接続先との実際のやり取りを確認するなら、メモリだけでなくプロキシ、DNS、ファイアウォール、EDRなどの記録へ調査を広げる必要がある。
不審な実行領域
malfindは、VADの属性などから、不審な実行可能領域を探す。ファイルをディスクに残さず、別のプロセスのメモリ上でコードを実行するような痕跡を探すときに使える。
出力されたアドレスや保護属性、先頭部分のバイト列・逆アセンブル結果を見て、追加で解析する領域を選ぶ。JITコンパイルなど正規の処理でも候補が出るため、ヒットした領域の内容や関連するモジュールも確認する。
こちらも --dump で抽出できる。
プロセス内の検索
文字列検索でドメインが見つかったものの、どのプロセスと関係するか分からない場合は、同じ文字列をYARAルールにしてプロセスの仮想メモリを検索できる。
vadyarascanは、VADをたどってプロセスの仮想メモリ領域を検索する。
この結果は「そのプロセスの読み取れた領域にIOCがあった」という根拠になるが、それがどう使われていたかは他のアーティファクトと突合して見ていく必要がある。
PEとメモリの抽出
実行ファイルをPE形式で取り出したいのか、ヒープなども含めて文字列を探したいのかで、抽出方法を変える。
出力先フォルダはあらかじめ作っておくこと。
ダンプしたPEは通常、もとのPEファイルと同一ではないので、VirusTotalなどでハッシュ値からもとの検体を同定することはできない。
実行することも難しい。 やるならIAT再構築などをする必要があるが、ここでは取り扱わない。
それでも、前述の文字列抽出やYARAによるスキャンから解析のヒントが得られることはある。
FLOSS は、実行ファイルのコードを解析し、難読化されていた文字列や、実行時に組み立てられる文字列の抽出を試みるツール。
通常のstringsでは出てこない文字列を探したいときに有用。
入力にはダンプしたPEを指定する。欠損やヘッダの破損があると、FLOSS側で解析できないこともある。
ファイルの復元
メモリには、プロセスが使用したファイルやOSのキャッシュも残る。調査対象のファイル名やパスが分かれば復元を試し、得られた内容をその形式に対応するパーサへ渡せる。
filescanは、Windowsがファイルを管理するFILE_OBJECTを走査する。まずファイル名から候補を探し、そのオブジェクトに対応する内容をdumpfilesで復元する。
次はWindows 10 / 11を対象に、見つかったFILE_OBJECTの仮想アドレスを指定する例である。アドレスは実際の出力に置き換える。
--virtaddrと--physaddrは、それぞれFILE_OBJECTの仮想アドレスと物理アドレスを受け取る。
プロセスとの関連が分かっていれば、PIDを指定して復元候補を絞ることもできる。
filescanで名前が見つかっても、ファイル内容がしっかり残っているとは限らない。
パーサで開けなければ、部分的に復元できたデータとして文字列検索やカービングに回してみる。
調査結果の整理
メモリフォレンジックをしていると、ファイルがグチャグチャになりがち。ホストや取得プロセスごとにフォルダを分け、いい感じに整理しておくとよい。 MemProcFSであれば、タイムラインやCSVも出力してくれるので、アンマウントする前にそのあたりも一通りコピーしておく。
整理は本当に大変なので、面倒ならAIにぶん投げても良いと思う。ただし情報の取り扱いには細心の注意を払うこと。
ツールによって結果の食い違いが発生することもままある。
どちらかが間違っていると決めつける前に、各ツールが何をたどって列挙しているかを確認する。参照する管理構造や、終了済みオブジェクト・欠損ページの扱いが違えば、結果も変わる。
おわりに
メモリフォレンジックでは、ディスクフォレンジックと比較して欠けたり壊れたデータを相手にすることが多い。それをどう活かすかというのは、中身を見てアタリをつける経験とセンスになってくるのでなんとも言えないが、困ったらとりあえず文字列として読んでみるとか、画像の断片っぽければGIMPに突っ込んでみるとか。マジに困ったらAIを頼ってもいいと思います。
メモリフォレンジックなんて人間がやることではないな。