皆さん、こんにちは!日々の開発やインフラの管理、本当にお疲れ様です。
セキュリティの勉強を始めると、ファイアウォールやウイルス対策ソフトといった「表玄関の鍵」については耳にする機会が多いですよね。でも、実は家の中(パソコンの内部)に侵入した泥棒が、「住民票や表札をこっそり書き換えて、家族のフリをして居座る」という、もっと巧妙で恐ろしい手口があるのをご存知でしょうか?
今回は、Windowsの内部深くにある「プロセス環境ブロック(PEB)」という仕組みを悪用した隠蔽工作と、それを見破るためのメモリフォレンジックの技術について、身近な例えを交えながら一歩ずつ優しく紐解いていきたいと思います。難しい用語が出てきても置いてけぼりにしませんので、一緒にリラックスして学んでいきましょう!
—
1. 身近な例えで理解する「PEB偽装」の仕組み
まずは、Windowsという巨大なマンションを想像してみてください。このマンションでは、住民(プログラム)が部屋を借りて生活しています。
表札と住民票のギャップ
私たちが普段見ている「Windowsのタスクマネージャー」や「プロセス一覧」は、いわばマンションの管理人が持っている「住民名簿」です。この名簿には、各住民の「名前(プロセス名)」や「部屋番号(プロセスID)」が記載されています。
プログラムが実行されるとき、Windowsのメモリ上にはそのプログラム専用の「プロフィール帳」が作られます。これが今回主役となるPEB(Process Environment Block:プロセス環境ブロック)です。PEBの中には、そのプログラムの名前や起動引数などが書き込まれています。
通常のプログラムであれば、PEBに書かれている名前と、OSの根幹(カーネル)が管理している本当の身分証明書の内容は一致しています。しかし、悪意ある攻撃者はどうするでしょうか?
泥棒が「表札」だけを書き換える手口
サイバー攻撃者は、ウイルスを実行したときに、メモリ上のPEBを書き換えて、プロセス名を無害なもの(例えば、正規の notepad.exe など)に偽装します。
これは例えるなら、強盗がアパートの表札だけを「山田さん(安全な人)」に書き換え、中身は凶悪犯のままで住民を油断させる手口です。
タスクマネージャーを開いた管理人は、「あ、notepad(メモ帳)が動いているんだな」と安心して見過ごしてしまいます。これが、PEBを使ったプロセス偽装の恐ろしいカラクリです。
—
2. 攻撃者はなぜPEBをいじるのか?
攻撃者がなぜわざわざこのような回りくどいことをするのかというと、「人間の目」と「簡易的なセキュリティ製品」を欺くためです。
セキュリティ運用の現場にいる私たちSOCアナリストも、インシデント調査の初期段階では、動いているプロセスの一覧を目視で確認することがよくあります。その時に「怪しい名前のプロセスがいないか」を探すわけですが、攻撃者はその心理の裏を突き、「いかにも安全そうな名前」に化けて潜伏します。
しかし、どれだけ表札(PEB)を上手に書き換えても、マンションの大家さん(Windowsカーネル)が握っている本当の台帳をごまかすことは、実はとても難しいのです。
—
3. 隠蔽を暴く鍵:EPROCESS構造体との比較
表札の嘘を見破るにはどうすればよいでしょうか?
答えは簡単です。「表札(PEB)」と「大家さんの直轄台帳(EPROCESS)」を見比べるのです。
Windowsのカーネル内には、各プロセスの真の身分証明書として機能する EPROCESS という極めて重要なデータ構造が存在します。この EPROCESS は、管理者権限を持つカーネルメモリの領域に安全に保管されており、ユーザーモードのプログラム(たとえ管理者権限であっても、通常の手段では)簡単には改ざんできません。
つまり、次のような比較を行えば、偽装が一発でバレることになります。
1. PEBを見る(表札の確認): 「私は notepad.exe です」と自己申告しているか?
2. EPROCESSを見る(大家さんの台帳確認): カーネルが把握している実際の実行ファイル名は何か?
もし、PEBには「notepad.exe」と書いてあるのに、EPROCESSのイメージ名(ImageFileName)が「malware.exe」になっていたら……?
「おや、表札と中身が違うぞ!偽装工作だ!」と即座に検知できるわけですね。これがメモリフォレンジックの醍醐味です。
—
4. 【実務向けコード解説】不整合を暴くPythonスクリプトのイメージ
実際のインシデントレスポンスの現場では、メモリダンプファイル(物理メモリのコピー)を解析ツール(Volatilityなど)やPythonスクリプトを用いて解析します。
ここでは、PEBのプロセス名とEPROCESSのプロセス名に乖離がないかを概念的にチェックする、Python(Volatility 3のAPIをイメージした疑似コード)のサンプルをご紹介します。実務でそのままロジックを組む際の参考にしてみてください。
# -*- coding: utf-8 -*-
"""
プロセス名の偽装(PEB vs EPROCESSの不整合)を検知するためのロジック例
セキュリティエンジニアがメモリ解析ツールやスクリプトを自作する際のベースとなります。
"""
def check_process_masquerading(task_process):
"""
引数: task_process - 対象のプロセスオブジェクト(EPROCESSおよびPEBの情報を含む)
"""
try:
# 1. カーネルが管理する本当のプロセス名(EPROCESSのImageFileName)を取得
kernel_image_name = task_process.get_image_filename()
# 2. ユーザーモードが主張するプロセス名(PEB内のCommandLineやImagepath)を取得
peb_image_name = task_process.get_peb_process_path()
# 3. 拡張子やファイル名部分を抽出して正規化(比較しやすくする)
kernel_base = extract_filename(kernel_image_name)
peb_base = extract_filename(peb_image_name)
# 4. 不整合のチェック
if kernel_base.lower() != peb_base.lower():
print(f"[!] 警告: プロセス偽装の可能性を検出しました!")
print(f" - プロセスID (PID): {task_process.get_pid()}")
print(f" - カーネル台帳 (EPROCESS): {kernel_base}")
print(f" - 詐称された表札 (PEB) : {peb_base}")
# ここで自動的にメモリダンプを採取したり、アラートを飛ばす処理を実装します
return True
except Exception as e:
print(f"[-] 解析中にエラーが発生しました (PID未確認): {str(e)}")
return False
def extract_filename(path_str):
"""ファイルパスから実行ファイル名のみを抽出するヘルパー関数"""
if not path_str:
return ""
# バックスラッシュやスラッシュで分割して最後の要素(ファイル名)を返す
return path_str.replace('\\', '/').split('/')[-1]
# 実際のインシデントハンドリングでは、稼働中の全プロセスに対して
# for proc in session.list_processes():
# check_process_masquerading(proc)
このように、表面上の情報だけに惑わされず、「信頼できる根源(Root of Trust)」であるカーネル側のデータと突き合わせる視点を持つことが、優れたセキュリティアナリストへの第一歩となります。
—
5. 一歩ずつ対策を学んでいきましょう!
初めてメモリフォレンジックや内部構造の話を聞くと、「なんだか難しそう……」と身構えてしまうかもしれません。でも、安心してください。セキュリティのプロたちも、最初は「メモリってどこをどう覗けばいいんだ?」という初心者からスタートしています。
日々の開発やインフラ構築の中でも、
- 「タスクマネージャーの表示をうのみにせず、EDR(Endpoint Detection and Response)などの専門ツールがどこを見ているか意識してみる」
- 「プログラムがOSの裏側でどうリクエストを送っているか想像してみる」
そんな小さな疑問や探究心の積み重ねが、いざという時に会社やシステムを守る強力な盾になります。
難解な技術も、身近な例えに置き換えれば本質はとてもシンプルです。ぜひ今回の「表札と大家さんの台帳」の話を頭の片隅に置いて、日々のセキュリティ対策に役立ててみてくださいね。それでは、また次の記事でお会いしましょう!
コメント