こんにちは!日々の開発やインフラの管理、本当にお疲れ様です。セキュリティの世界へようこそ!
「なんだか最近、サーバーの動きが怪しいな……」「タスクマネージャーを見ても怪しいプログラムは見当たらないのに、ネットワークの通信量だけがやけに多いな……」
そんな経験、エンジニアなら一度はヒヤッとしたことがあるのではないでしょうか。
実はそれ、プロの悪い奴ら(攻撃者)が使う「隠れ身の術」にやられているサインかもしれません。
今回は、Windowsのメモリという奥深い世界を舞台にして、攻撃者がどうやって自分の存在を隠しているのか、そして私たちセキュリティアナリストがどうやってその「隠し部屋」を見つけ出すのかを、身近な例えを交えながら優しく紐解いていきたいと思います。一歩ずつ、一緒に学んでいきましょうね!
—
1. 身近な例えで理解する「プロセス隠蔽」の仕組み
まずは、私たちの身の回りにある「防犯」の仕組みに例えて考えてみましょう。
皆さんが住んでいるマンションには、管理人が持っている「全住民の台帳(名簿)」がありますよね。普通の人が引っ越してくれば、管理人はその台帳に名前を書き込みます。警察や大家さんが見に来たときも、この台帳を見れば誰がどの部屋にいるのかが一目瞭然です。
Windowsのメモリの中でも、これと全く同じことが行われています。
Windowsは、今動いているすべてのアプリ(プロセス)を管理するために、「ActiveProcessLinks(アクティブ・プロセス・リンクス)」という、いわば「住民台帳のリスト」を頭の中に持っています。このリストはまるで数珠つなぎの輪っか(二重連結リスト)のようになっていて、次から次へと隣のプロセスを紹介していく仕組みになっています。
攻撃者はどうやって隠れるの?(泥棒の擬装工作)
もし、悪い泥棒(マルウェア)がこっそりマンションに忍び込んだとしましょう。
普通なら、管理人の台帳に名前が載ってしまうのですぐにバレてしまいますよね。そこで、頭のいい(そして性質の悪い)泥棒は、管理人の台帳から自分の名前のページだけをこっそり破り取り、隣の部屋と自分の部屋を直接繋いでしまうのです。
これが、メモリの世界で行われるプロセス隠蔽(Direct Kernel Object Manipulation: DKOMなど)の正体です。
- タスクマネージャーが見る世界: 「管理人さんの台帳」を見にいくだけなので、泥棒の名前は載っていません。「あれ、誰もいないね、安全安全!」となります。
- 実際のメモリの世界: 台帳から名前が消されただけで、泥棒のプログラム自体は、メモリの片隅でひっそりと動き続けています。
タスクマネージャーや一般的な監視ツールだけを信じていると、「誰もいませんよ」という嘘をそのまま信じ込まされてしまうわけです。怖いですよね。
—
2. 攻撃者が狙う「PEB(プロセス環境ブロック)」とは?
ここで、今回の主役であるPEB(Process Environment Block:プロセス環境ブロック)について少しだけ詳しく、でも分かりやすく見ていきましょう。
PEBとは、一言で言うと「各プロセス専用のプロフィール帳」のようなものです。
「私はこういう名前のプログラムで、こういう場所から起動されていて、こんな設定を持っています」という情報が、このPEBの中にぎっしり詰まっています。
攻撃者は、プロセスを隠すためにこのPEB周辺の構造体を書き換えたり、先ほどお話した「住民台帳の輪っか(ActiveProcessLinks)」のつながりをプチッとハサミで切って、別のプロセス同士を無理やり結びつけたりします。
ここに注目!「不整合」というボロが出ます
完璧に隠れたつもりでいる攻撃者ですが、実はここに大きなボロ(=不整合)が生じます。
マンションの例えに戻りましょう。
部屋の住民台帳(ActiveProcessLinks)からは名前を消したものの、郵便受けの名前や、管理人が持っている別の裏台帳(例えば、プロセスがロードしたモジュールのリストなど)には、うっかり名前が残ってしまっているのです。
私たちDFIR(インシデントレスポンスとフォレンジック)の調査官は、この「あちこちに残る情報のズレ(不整合)」を見つけ出すことで、「おや、台帳には名前がないのに、別の場所には痕跡があるぞ。ここに隠れんぼしている奴がいるな!」と特定するわけです。
—
3. 隠れたプロセスを見つけ出す!実践的なアプローチ
「じゃあ、具体的にどうやってその隠れんぼを見破るの?」気になりますよね。
現場のセキュリティエンジニアは、メモリのダンプファイル(メモリ全体の健康診断データのようなもの)を採取し、専用の解析ツールを使って「台帳の不整合」を暴きます。
ここでは、オープンソースのメモリフォレンジックフレームワークである「Volatility(ボラティリティ)」などを想定した、考え方の流れと、実務で使える擬似的なスクリプトのアイデアをご紹介します。
Python風のイメージコードで見るチェックロジック
実際のフォレンジックツールが行っている内部処理を、少し分かりやすくPythonのコード風に表現してみましょう。
# 【実務参考】プロセスリストの不整合を検出するための概念コード
# ※実際のフォレンジックツールはCやPythonでカーネルメモリ構造体を直接走査します。
def detect_hidden_processes(active_link_processes, system_pslist):
"""
active_link_processes: 通常のWindows APIやリンクを辿って取得したプロセスリスト(タスクマネージャーが見る世界)
system_pslist: メモリ構造体を総当たり(カーネルプールスキャン等)して強引に列挙したプロセスリスト
"""
# セット(集合)を使ってIDを比較します
visible_pids = {p['pid'] for p in active_link_processes}
all_pids = {p['pid'] for p in system_pslist}
# 総当たりで見つかったのに、通常のリンクリストには載っていないPIDを抽出
hidden_pids = all_pids - visible_pids
if hidden_pids:
print("[!] 警告: 隠蔽されたプロセスの可能性を検知しました!")
for pid in hidden_pids:
print(f" -> 発見された不整合 PID: {pid}")
# ここで不審なプロセスのメモリ領域をダンプして詳細調査を行う
else:
print("[+] プロセスの隠蔽は検出されませんでした。正常です。")
# 【解説】
# 通常の列挙方法(ActiveProcessLinksを辿る方法)と、
# メモリ上を直接スキャンしてプロセス構造体(EPROCESS)を探す方法の「差分」を取ることで、
# 攻撃者が隠したプロセスをあぶり出すことができます。
このように、「見えているはずの世界」と「本当のメモリの世界」を見比べる(クロスビュー解析)ことが、隠蔽プロセスを見破るための最強の武器になります。
—
4. 一歩ずつ対策を学んでいきましょう!
「なんだかメモリの話は難しそうだな……」と感じた方もいるかもしれません。でも、安心してください。最初からすべての構造体を暗記しているプロなんていません。
私たちが日々の開発やインフィラ運用で意識できる対策は、次のような基本的な積み重ねから始まります。
1. EDR(Endpoint Detection and Response)製品の導入
単なるウイルス対策ソフト(アンチウイルス)は、ファイルの表面的な特徴しか見ないため、今回のようなメモリ上だけで行われる巧妙な隠蔽工作を見逃しがちです。カーネルの動きを監視できるEDRを導入するのが現代の必須防衛ラインです。
2. アップデートの徹底
OSの脆弱性を突かれてカーネル空間への不正なアクセス権(特権)を奪われると、このような高度なPEB操作やDKOMが自由に行われてしまいます。パッチ当てをサボらないことが最大の防御になります。
3. 「見えているもの」を疑う目を養う
「タスクマネージャーにいないから安全」という思い込みを捨て、「ログが出力されていないか」「ネットワークの出入りが不自然ではないか」と多角的にシステムを観察する習慣を持ちましょう。
セキュリティの世界は広大で、時には今回のようなトリッキーな攻撃に出会うこともあります。しかし、仕組みを一つずつ紐解いていけば、攻撃者の足跡は必ずどこかに残るものです。
焦らず、一歩ずつ、一緒にセキュリティの引き出しを増やしていきましょうね!次の記事でも、現場で役立つリアルな知見をお届けしますので、ぜひお楽しみに!
コメント