カーネルの深淵を覗く:EPROCESSとETHREADによる「隠蔽された真実」の抽出
インシデントレスポンスの現場において、OSが提供するAPI――例えば EnumProcesses や tasklist コマンド――を信じきっている人間は、すでに攻撃者の掌の上で踊らされていると言っても過言ではない。
高度なマルウェアやルートキットは、カーネルレベルで自身のプロセス情報をリストからアンリンク(Unlink)することで、正規のAPIからその存在を消し去る。しかし、物理メモリという「逃げ場のない真実」まで改ざんすることは極めて困難だ。今回は、メモリフォレンジックの核心、すなわち EPROCESS と ETHREAD 構造体を直接解析することで、OSの虚飾を剥ぎ取る手法を解説する。
—
1. なぜAPIを信用してはいけないのか
Windowsカーネルにおいて、すべてのプロセスは EPROCESS 構造体として管理されている。プロセスが生成される際、この構造体は非ページプール(Non-paged pool)に割り当てられ、双方向リンクドリスト ActiveProcessLinks によって繋がれる。
攻撃者が行う「DKOM (Direct Kernel Object Manipulation)」は、このリストから自身のノードを外す手法だ。だが、物理メモリ上には依然として EPROCESS の実体が存在し、さらに ETHREAD がスケジューラに登録されている限り、CPUはそれを実行し続ける。ここに、我々がフォレンジックで突くべき「死角」がある。
—
2. メモリ構造解析の実践:Volatilityを用いたアプローチ
現場で最も頼りになるのは、やはり Volatility Framework だ。しかし、ツールを叩くだけでは「オペレーター」止まりだ。我々アーキテクトは、その裏で何が起きているかを理解せねばならない。
以下は、EPROCESS 構造体を直接走査し、隠蔽されたプロセスを炙り出すためのロジックを簡略化したものだ。
# Volatility 3のプラグイン開発を想定したカーネルオブジェクト探索の概念コード
import volatility.framework.interfaces as interfaces
def find_hidden_processes(context, layer_name, symbol_table):
# カーネルのシンボルテーブルからActiveProcessLinksのオフセットを取得
# これをハードコーディングせず、オフセットから動的に計算するのが肝
proc_type = context.symbol_space[symbol_table].get_type("nt!_EPROCESS")
# メモリ層の探索 (物理メモリ空間を直接スキャン)
# 実際にはPoolタグ(ProC)を検索し、構造体の整合性を検証する
for offset in scanner.scan(layer_name, b"ProC"):
try:
eprocess = context.object(symbol_table, "nt!_EPROCESS", offset=offset)
# ActiveProcessLinksを無視し、構造体メンバーの整合性でプロセスを特定
print(f"発見されたプロセス: {eprocess.ImageFileName} (PID: {eprocess.UniqueProcessId})")
except:
continue
構造解析のポイント
- ActiveProcessLinksの罠:
ActiveProcessLinksはOSのリスト管理用であり、ここを外せばpslistコマンドには出なくなる。しかし、psscanのようにカーネルメモリ上の_EPROCESSプールを直接スキャンする手法であれば、リストから外されたプロセスも確実に捕捉できる。 - ETHREADの追跡: プロセスが隠蔽されていても、スレッド(
ETHREAD)がスケジューラに登録されている限り、カーネルのThreadListHeadを辿れば、親プロセスを特定し、その不正なメモリ空間を特定することが可能だ。
—
3. 次世代の脅威:AIとカーネルの融合を見据えて
近年の攻撃トレンドは、巧妙なプロンプトインジェクションによってサンドボックスを脱出し、メモリ上にのみ存在する「ファイルレスマルウェア」を生成する流れにある。これに対し、我々が取るべき防御アーキテクチャの要諦は以下の通りだ。
1. EDRの盲点を突くメモリインテグリティ監視:
カーネルモードコード署名 (KMC) をバイパスする脆弱性が絶えない以上、EPROCESS の構造体自体に対する「改ざん検知」を常時行う軽量なカーネルドライバーの展開を検討すべきだ。
2. ガードレイルとしてのメモリ分離:
生成AIが生成したコードを実行するプロセスに対し、専用のカーネルオブジェクトコンテナを割り当て、ETHREAD が許可されていないカーネル領域にアクセスしようとした瞬間にハードウェア例外を発生させる仕組み(VBS: Virtualization-Based Security の活用)が必須となる。
—
4. 最後に:技術者の矜持として
カーネルの構造解析は、泥臭い作業の連続だ。しかし、攻撃者がどれほど巧妙にカーネルの挙動を模倣しようとも、物理法則(メモリ内のデータ配置)を覆すことはできない。
あなたが今日解析しているそのダンプファイルの中に、次の大規模侵害の「痕跡」が眠っているかもしれない。OSが語る嘘を疑い、メモリが語る真実を追求する。それが、我々DFIRの人間が守るべき最後の砦である。
次回のブログでは、KPCR (Kernel Processor Control Region) の解析を通じて、CPUコアレベルでの実行フローハイジャックを検知する手法について深く掘り下げる予定だ。準備を怠るな。技術の進化と共に、我々の武器も研ぎ澄まされねばならないのだから。
コメント