
依存関係ゼロのLinuxメモリフォレンジック。カーネル組み込みのBTFとkallsymsを活用し、外部デバッグ情報なしで型認識メモリ解析を実現。
mquireは、memory(メモリ)とinquire(問い合わせ)を組み合わせた造語で、osqueryにインスパイアされたメモリクエリツールです。
mquireは、外部デバッグシンボルを必要とせずにLinuxカーネルメモリのスナップショットを解析できます。
分析に必要なものはすべてメモリダンプ自体に組み込まれています。つまり、以下を解析できます。
カーネルバージョンの要件:
scripts/kallsyms.cのフォーマット変更による)mquireは、モダンなLinuxカーネルに組み込まれている次の2種類の情報を読み取ることでカーネルメモリを解析します。
/proc/kallsymsで使用されるのと同じデータ)。型情報とシンボル位置を組み合わせることで、mquireは以下のような複雑なカーネルデータ構造を見つけて読み取ることができます。
これにより、ディスクから削除されたファイルであっても、カーネルのファイルキャッシュから直接ファイルを抽出することが可能になります。
Kallsymsスキャナーは、カーネルソースのscripts/kallsyms.cのデータ形式に依存しています。将来のカーネルバージョンでこの形式が変更された場合、スキャナーのヒューリスティックを更新する必要があります。
mquireは、システムのさまざまな側面やツール自体の状態をクエリするためのSQLテーブルを提供します。
mquireはデータベースではありません。 各クエリは、メモリをスキャンしてポインタを辿ることにより、カーネルデータ構造を再構築します。事前計算されたインデックスやキャッシュされた結果はありません。テーブルアクセスはすべてカーネルデータのトラバーサルです。冗長なスキャンを避けるには
AS MATERIALIZEDを使用し(クエリ最適化を参照)、task_open_filesやmemory_mappingsのようなプロセス単位のテーブルをクエリする際は、単一プロセスにスキャンを限定するためにtaskのような制約条件を指定してください。
設計原則:結合キーとしての仮想アドレス。 テーブルは、
pidや他のユーザー可視の識別子ではなく、virtual_address(基盤となるデータ構造のカーネルアドレス)を正規の結合キーとして使用します。これは意図的です。同じPIDが複数の発見ソースやルートタスクにわたって複数回現れる可能性がある一方、仮想アドレスは特定のカーネルオブジェクトを一意に識別するからです。SQLテーブルと基盤となるLinuxOperatingSystemAPIはどちらもこの規則に基づいて構築されています。
/proc/kallsymsと同じデータ)dmesgコマンドと同じデータ)task制約を指定し、すべてのタスクを一度にクエリすることも可能)task制約を指定し、すべてのタスクを一度にクエリすることも可能)task制約が必要なため、tasks/processesと結合してください(例:JOIN task_capabilities c ON c.task = p.virtual_address)。task制約が必要です。memエントリ。kernel_module制約が必要なため、kernel_modulesと結合してください(例:JOIN kernel_module_mem_entries r ON r.kernel_module = m.virtual_address)。ftrace_ops_listシンボルから辿ったstruct ftrace_opsノードのリスト。virtual_addressを制約して単一ノードを読み取るか、start_vaddr(オプションでend_vaddrで範囲指定)を制約して任意のノードから辿ることができます。mquireは3つの主要なコマンドを提供します。
mquire shell - 対話型SQLシェルを起動し、メモリスナップショットをクエリしますmquire query - 単一のSQLクエリを実行し、結果を出力します(JSON形式またはテーブル形式をサポート)mquire command - メモリスナップショットに対してカスタムコマンドを実行します(例:.task_tree, .system_version, .dump)mquireは、SQLクエリと区別するために、ドット(.)で始まる特別なコマンドを提供します。
これらのコマンドは、対話型シェルおよびmquire queryで動作します。
.tables - 利用可能なすべてのテーブルを一覧表示.schema - すべてのテーブルのスキーマを表示.schema <table> - 特定のテーブルのスキーマを表示.commands - 利用可能なすべてのカスタムコマンドを一覧表示.exit - 対話型シェルを終了(シェルのみ)これらのコマンドは、対話型シェルおよびmquire commandで動作します。
各コマンドで--helpを使用すると、利用可能なオプションと使用法の情報を表示できます。例:.task_tree --help
.system_versionオペレーティングシステムのバージョン情報を表示します。
これはSELECT * FROM os_versionと同等の便利なコマンドですが、フォーマットされた出力を提供します。
.task_tree実行中のプロセスとスレッドの階層ツリーを表示します。Linuxのpstreeコマンドと似ています。
オプション:
--show-threads - プロセスに加えてスレッドも含めます。有効にすると、各エントリにTGIDとTIDの両方が表示されます。--use-real-parent - ツリー構造の構築にparentフィールドではなくreal_parentフィールドを使用します。real_parentフィールドは、再親化前の元の親プロセスを示します(親プロセスが終了した後でもプロセス生成チェーンを追跡するのに役立ちます)。注記:
[TGID TID]、スレッドを非表示にする場合は[TGID]です。TGID(スレッドグループID)は一般的にPIDと呼ばれるものです。メインスレッド(TGID == TID)の場合、両方の値は同じになります。.carve仮想メモリの領域をディスクに切り出します。このコマンドは、特定の仮想アドレス範囲から、指定されたページテーブルを使用して生のメモリ内容を抽出します。プロセスメモリ、ヒープ内容、またはその他のメモリ領域の抽出に便利です。
引数:
ROOT_PAGE_TABLE - ルートページテーブルの物理アドレス(オプションで0xプレフィックス付きの16進文字列)。翻訳に使用するアドレス空間を決定します。VIRTUAL_ADDRESS - 切り出しを開始する仮想アドレス(オプションで0xプレフィックス付きの16進文字列)。SIZE - 切り出すバイト数。DESTINATION_PATH - 切り出されたメモリが書き込まれる出力ファイルのパス。注記:
.dumpカーネルのファイルキャッシュからファイルを抽出して、メモリから直接ファイルを復元します。このコマンドは、すべてのタスクとそのオープンファイル記述子を反復処理し、ページキャッシュからファイル内容を抽出します。
引数:
OUTPUT - 抽出されたファイルの出力ディレクトリ。ファイルはTGIDごとに整理されます(例:tgid_1234/path/to/file)。注記:
mquireは以下の目的で設計されています。
ビルド済みパッケージはCI実行のアーティファクトとして利用できます。Actionsタブから、成功したワークフロー実行を選択し、アーティファクトをダウンロードすることで入手できます。以下のパッケージ形式が利用可能です。
.debパッケージ.rpmパッケージ.tar.gzアーカイブmquireはRustで書かれています。ビルドするには:```bash
git clone https://github.com/trailofbits/mquire cd mquire
cargo build --release
## 対応するスナップショット形式
mquireは、ファイル拡張子で検出される以下のメモリスナップショット形式をサポートしています:
| 形式 | 拡張子 | 説明 |
|--------|-----------|-------------|
| Raw | `.raw` | フラットな物理メモリダンプ(物理アドレス空間のバイト単位コピー) |
| LiME | `.lime` | アドレス範囲ヘッダー付きの[Linux Memory Extractor](https://github.com/504ensicsLabs/LiME)形式 |
| ELF core | `.elf` | PT_LOADセグメントを含むELFコアダンプ(`virsh dump` または QEMU `dump-guest-memory` で生成されるもの) |
## メモリスナップショットの取得
### AVMLの使用(推奨)
ライブLinuxシステムからメモリスナップショットを取得するには、[AVML](https://github.com/microsoft/avml)を推奨します。以前は[LiME](https://github.com/504ensicsLabs/LiME)が推奨されていましたが、現在は積極的にメンテナンスされていません。```bash
sudo avml output.lime
重要: mquire用のスナップショットを取得する際には
--compressを使用しないでください。mquire は圧縮された AVML スナップショットをサポートしていません。圧縮されたスナップショットがある場合は、avml-convertを使用して最初に解凍してください:avml-convert compressed.lime uncompressed.lime
追加オプションについては、AVML ドキュメント を参照してください。
libvirt/KVM 仮想マシンの場合は、virsh dump を使用して ELF core dump を生成します:```bash
virsh -c qemu:///system dump output.elf --memory-only --format elf
ダンプ中はVMが一時停止され、ダンプ後に再開されます。`--live` を追加すると、一時停止を回避できますが、スナップショットの整合性が低下します。
## はじめに
メモリスナップショットを取得したら、SQLクエリとカスタムコマンドを使って操作できます。mquire はスナップショットを操作するための3つの方法を提供します:
### インタラクティブシェル