はじめに
マルウェア解析は専門性が高く、
「どこをどう見ればいいのか分かりづらい」 「学習コストが高い」 分野だと感じていました。
私自身、以前からマルウェア解析という分野に興味があり、
「仕組みをきちんと理解できるようになりたい」 「手法を体系的に学びたい」 と思いながらも、
実際に手を動かすと、その難易度の高さに躓いてきました。
特に、解析結果は断片的には理解できても、
「この情報から何が言えるのか」 「次はどこを見ればよいのか」 を
自分の中で整理しきれないことが多く、学習のハードルを感じていました。
そうした中で近年、LLM(大規模言語モデル)が急速に進化し、
複雑な情報を要約・整理する能力を持つようになっています。
この特性をうまく活用すれば、 マルウェア解析における思考整理や理解の補助に使えるのではないかと考えました。
そこで今回は、LLMを活用してマルウェア解析を支援する AI エージェントを試作し、
実際のマルウェアサンプルを用いて、
- 解析結果の理解はどれくらい楽になるのか
- 人間の解析作業をどこまで支援できるのか
この 2 点を検証してみました。
※本記事では 「解析を AI にすべて任せる」 ことを目的にしていません。
あくまで人間が行う解析作業の理解を助け、思考を整理し学習コストを下げるための
“補助役”として AI を活用できないか という立場で検証しています。
※補足
本記事では「AIエージェント」と表現していますが、
厳密には自律的に計画・実行を行う完全なエージェント構成ではありません。
本来はツールを定義し、AIが解析方針を決定しながら進める構成を想定していましたが、
LLM APIのステートレス性やトークンコストの制約から、
今回は解析結果を整理・解釈するパイプライン型の支援ツールとして実装しています。
マルウェア解析手法について
1. 表層解析
- ファイル形式(PE / ELF など)
- strings の抽出
- ハッシュ値の算出(MD5 / SHA-256 など)の算出
- 怪しい文字列やURLの有無
この段階では、実行せずに危険度をざっくり把握することが目的です。
2. 静的解析
- バイナリを逆アセンブル/逆コンパイル
- 関数構造の把握
- API 呼び出しの確認
- 暗号化・難読化の有無
実行はせず、コードの構造や処理内容を読み解くフェーズです。
3. 動的解析
- サンドボックスやVM上で実行
- ファイル操作・通信・プロセス生成の監視
- 実際の挙動を確認
「このマルウェアは何をするのか」 を挙動ベースで確認するフェーズになります。
今回の方針
今回は静的解析に焦点を当てたAIエージェントを作成しました。
理由としては静的解析は情報量が多く、
人間が把握(脳内コンパイル)するのに時間がかかりますが、
使用するツールの解析結果(strings / import / decompile など)は
LLMと相性が良いと考えたためです。
静的解析においても、安全性担保の観点から隔離環境での解析を推奨します
全体構成
使用したツール
Ghidra
Ghidra は、アメリカ国家安全保障局(NSA)が開発した オープンソースのリバースエンジニアリングツールです。
ソフトウェア解析やバイナリ解析を目的として利用され、
機械語を人間が理解しやすい高級言語風のコードに変換する逆コンパイル機能を備えています。
本記事ではGhidra のすべての機能を使うのではなく、
マルウェアの挙動把握に特に有用な以下の機能に絞って利用しました。
・Strings
プログラム内に含まれる文字列を一覧表示する機能です。
URL・IPアドレス・ファイルパスなどが含まれることがあり、
マルウェアの挙動を推測するための最初の手がかりとして利用できます。
・Import
マルウェアが明示的にImportしている外部関数(主に Windows API)の一覧です。
通信、ファイル操作、レジストリ操作などの有無を確認でき、
大まかな挙動を推測することができます。
・Functions
Ghidraの自動解析によって識別した関数の一覧を確認できます。
処理単位でコードを追えるため、
怪しい挙動を持つ関数を絞り込むための起点として利用します。
・Decompile
アセンブリコードを 高級言語風の疑似コードとして表示する機能です。
完全に元のソースコードが復元されるわけではありませんが、
関数の処理内容やロジックを直感的に理解しやすくなります。
本検証ではこれらの情報を Ghidra から抽出し、
LLM に入力することで解析支援を行いました。
構築ポイント
LLMをマルウェア解析に使う場合、
大きな課題だったのが、入力トークン数の大きさ です。
- strings が数千行
- decompile 結果が数万トークン
- そのまま投げると 遅い・高い・不安定
今回の構築において、
「解析精度を落とさずにトークン量を減らす」 ことを重要な構築方針としました。
① "none"の除外
Ghidra で抽出される strings には "none" が大量に含まれます。
なぜ含まれているかというと攻撃者が"難読化"を行っており、
これらは LLMにとって情報価値がほぼゼロ です。
# =====================================================
# stringsの要約関数
# =====================================================
def summarize_strings(strings):
return [s for s in strings if isinstance(s, dict) and s.get("value") and s["value"].lower() not in ("none", "")][:50]
上記対応でLLMが「意味のある文字列」に集中するようになり、
strings の行数を 20〜60%削減しました(「情報量」 ではなく 「情報密度」 を上げるイメージ)
② decompile 結果の WARNING コメントを除去
Ghidra の decompile 結果には、以下のような WARNING が頻出します。
/* WARNING: Type propagation algorithm not settling */
これらはLLMの挙動解析にはほぼ不要です。
トークンを大量消費してしまうので、
decompile 結果を LLM に渡す前にWARNING コメントを除去しました。
# =====================================================
# 逆コンパイルサポート
# =====================================================
def clean_decompile_code(c_code: str) -> str:
lines = []
for line in c_code.splitlines():
if line.strip().startswith("/* WARNING"):
continue
lines.append(line)
return "\n".join(lines)
上記対応により
関数1つあたり 数十~百トークン削減になりました。
③ 全関数を decompile しない(最重要)
人間の解析者も、最初から全関数を読むことはほぼありません。
LLMにも 「人間と同じ優先順位」 を与える設計にするために 「関数厳選」 を行いました。
(初期実装では、全関数を decompile しLLMにすべて渡しており、これがトークンコストを増大させていました)
以下の評価軸から各関数に簡易スコア を付与します。
評価軸の例:entry / main 系関数(最重要)、関数サイズ
# =====================================================
# スコアリング
# =====================================================
def is_entry_function(name: str) -> bool:
lname = name.lower()
return any(k in lname for k in ENTRY_KEYWORDS)
def score_function(func) -> int:
"""
静的解析ベースの簡易スコア
"""
score = 0
# entry / main 系は最優先
if is_entry_function(func.getName()):
score += 50
# 関数サイズ
try:
score += func.getBody().getNumAddresses()
except Exception:
pass
return score
そして
スコア順に並べて 上位 N 個のみ decompile。
# スコア順で上位のみ
scored_funcs.sort(key=lambda x: x[0], reverse=True)
target_funcs = scored_funcs[:TOP_N_FUNCTIONS]
④ 「怪しい関数だけ」を LLM に渡す設計
③のスコアリング結果をもとに、
LLM に渡す decompile 結果は 上位N個の関数のみに限定しました。
結果として入力されるのは、
-
main / WinMain / entryなどのエントリポイント周辺 - 実際に処理の中心となっている関数
に自然と集約されます。
これら4つの構築ポイントにより、
- トークン量:従来の 1/3〜1/10 に削減
- 解析精度:体感的な低下はほぼなし
という結果が得られました。
抽出した関数は以下のような形式でログ保存することで、人が後で見れるようにしました。
===== FUNCTION START =====
name: FUN_00421d4f
entry_point: 00421d4f
score: 119
void FUN_00421d4f(HWND param_1,int *param_2,int param_3)
{
wchar_t *pwVar1;
ushort uVar2;
uint ****ppppuVar3;
bool bVar4;
char cVar5;
uint uVar6;
int iVar7;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
local_8._0_1_ = 8;
FUN_00401a66(local_2c);
}
cVar5 = FUN_0040f763(local_dc,(ushort *)local_1d4);
} while (cVar5 != '\0');
LAB_0042235a:
FUN_00401a66(local_1d4);
FUN_0040f6f7(local_dc);
FUN_00401a66(local_8c);
pppppuVar18 = (undefined4 *****)local_5c;
goto LAB_0042237e;
}
===== FUNCTION END =====
解析フロー
1.検体をAIエージェントに投入
2. Strings、Imports、Functions、Decompileの解析結果を取得
3.解析結果を要約(無駄な情報を削除)し、LLMに入力
Stringsの要約(一部抜粋)
[Summarized analysis results]
{
"strings": [
{
"address": "0043c674",
"value": "Unknown exception"
},
{
"address": "0043c688",
"value": "bad array new length"
},
{
"address": "0043c6a0",
"value": "string too long"
},
{
"address": "0043c6b0",
"value": "vector too long"
},
4.LLMの応答が画面に出力される
LLMからは、「マルウェアの概要」 「想定される目的」 「怪しい処理や注目すべきポイント」 「攻撃の流れの推測」 といった情報が自然言語で出力されます。

性能検証
今回は2つの検体を解析してみます。
LLMに渡す関数は4つとしました。
1検体目:RemocosRAT(Remote Control & Surveillance)
RemocosRATはWindowsを主な対象とする商用のリモート管理ツール型マルウェアです。
本来は正規ソフトとして販売されていましたが、現在は不正侵入や情報窃取を目的とした攻撃で広く悪用されていいます。
主な機能として、「キーログ取得」 「画面キャプチャ」 「ファイル操作」 「コマンド実行」 「プロセス管理」 「パスワード窃取」 などを備え、侵入後の端末を包括的に遠隔制御できる点が特徴です。
解析時間 :約2分
トークン数:131,281
LLMの分析レポート
## マルウェア解析レポート
### 1. 分類
**ドロッパー (Dropper) / SFX型マルウェア**
この検体は、自身の内部に保持されたペイロードを特定の環境に展開し、実行することを目的としたドロッパー、あるいはRAR自己展開形式(SFX)を悪用したマルウェアと推測されます。
### 2. 挙動の解説
このマルウェアは、実行環境のOS情報をWMI(Windows Management Instrumentation)を通じて収集し、システム特権(SeSecurityPrivilege, SeRestorePrivilege等)を有効化することで、保護された領域へのアクセスを試みます。また、NTFSの代替データストリーム(ADS)や詳細なファイル属性を操作するコードが含まれており、ファイルシステムレベルでの隠蔽や特殊なデータ保存を行います。
### 3. 攻撃フロー
1. **環境探索:** WMIを使用してOSバージョン情報を取得し、ターゲット環境を特定。
2. **権限昇格:** トークン操作を行い、ファイル操作やシステム設定変更に必要な高度な特権を有効化。
3. **ペイロード展開:** `.rartemp` や `.rar` などの一時ファイルを作成し、内蔵された実行ファイルやスクリプトを抽出。
4. **永続化と実行:** `MoveFileExW` やレジストリ操作を用いて、再起動後も実行されるよう設定。必要に応じてメモリ保護API(CryptProtectMemory)でデータを難読化。
### 4. 不審なインジケーター
* **WMIクエリ:** `SELECT * FROM Win32_OperatingSystem`
* **特権要求:** `SeSecurityPrivilege`, `SeRestorePrivilege`, `SeCreateSymbolicLinkPrivilege`
* **NTFS属性操作:** `::$DATA`, `::$INDEX_ROOT`, `::$ATTRIBUTE_LIST`
* **ファイル操作:** `MoveFileExW`, `SHFileOperationW`
* **暗号化API:** `CryptProtectMemory`, `CryptUnprotectMemory` (メモリ上のデータ隠蔽)
* **パス参照:** `Software\Microsoft\Windows\CurrentVersion`, `ProgramFilesDir`
参考(各関数のスコア)
name: FUN_00421d4f
entry_point: 00421d4f
score: 119
name: FUN_0042776c
entry_point: 0042776c
score: 112
name: FUN_0040bf3d
entry_point: 0040bf3d
score: 103
name: FUN_0043480e
entry_point: 0043480e
score: 100
まとめ
今回の検体では、LLM に渡した関数を 4 つに限定したこともあり、
本来は RAT であるにもかかわらず、SFX 型ドロッパーとして誤分類される結果となりました。
LLM のレポート内容自体は、「権限昇格」 「永続化処理」 といった 「部分的な挙動の読み取り」には成功しており、コード断片レベルでの解析能力は十分に高いと感じました。
一方で、「C2 通信」 「遠隔操作(RAT)特有のコマンド処理」 「入力監視や画面キャプチャといった機能」 といった RAT としての本質的な振る舞いを示す情報が入力に含まれていなかったため、マルウェアファミリ全体の正確な分類には至りませんでした。
2検体目:Vidar
VidarはWindows を主な対象とする 情報窃取型マルウェア(インフォスティーラー) で、Arkei 系マルウェアをベースに開発されたと言われています。主にメール添付や不正サイト経由で拡散され、感染端末から 「ブラウザに保存された ID・パスワード」 「Cookie、クレジットカード情報、暗号資産ウォレット情報」 などを窃取します。加えて、 「スクリーンショット取得」 「システム情報収集、追加ペイロードのダウンロード機能」 も備えています。窃取した情報は C2 サーバへ送信され、初期侵入やアカウント侵害の起点として悪用されることが多いようです。
解析時間 :約5分
トークン数:295,058
LLMの分析レポート
### マルウェア分析レポート
#### 1. 分類
**インフォスティーラー (Infostealer)**
#### 2. マルウェアの概要
このマルウェアは、感染端末からWebブラウザ(特にGoogle Chrome)の認証情報、クッキー、およびユーザーの機密ファイルを窃取することを目的としています。解析を妨害するための難読化(不透明な述語やジャンクコード)が施されており、窃取したデータはAES-GCM暗号化やBase64エンコードを用いて隠蔽した状態で外部へ送信されます。
#### 3. 攻撃フロー
1. **アンチ解析・潜伏**: `GetTickCount` や `Sleep` を利用した時間差攻撃により、サンドボックス環境や動的解析を回避します。
2. **ターゲット探索**: `%LOCALAPPDATA%`、`%USERPROFILE%` などの環境変数を展開し、デスクトップ、ドキュメント、ブラウザのデータフォルダ(`\Network\Cookies` 等)を走査します。
3. **情報窃取と暗号化**: 特定したファイル(クッキー、パスワード、ホスト名等)を読み込み、ハードコードされたXORキーやAES-GCMを用いてデータを加工します。
4. **データの送信**: 窃取した情報をC2サーバーへ送信するためのネットワーク接続準備(`%s:%d` 形式のフォーマット)を行います。
#### 4. 不審なインジケーター
- **ファイルパス**: `C:\ProgramData\`, `%APPDATA%`, `\Network\Cookies`
- **重要文字列**: `ChromeBuildTools`, `ChainingModeGCM`, `DEADBEEF`
- **特徴的な動作**:
- 大量のXOR演算による文字列復号ループ
- `GetTickCount` の差分を利用したデバッグ検知
- `ADVAPI32.DLL` を利用した暗号化処理
- **エンコード**: 標準的なBase64カスタムインデックスの使用
---
**分析者コメント**: 典型的なRedLineやRacoon Stealerのような挙動を示しており、ユーザーの資格情報奪取を最優先としています。
参考(各関数のスコア)
name: FUN_140024556
entry_point: 140024556
score: 180
name: FUN_140059f38
entry_point: 140059f38
score: 172
まとめ
2 検体目の Vidar では、LLM が出力した解析結果は 既知の Vidar の挙動とほぼ一致しており、
分類・攻撃フロー・目的のいずれも高い精度で捉えられていました。
特に 「ブラウザ情報(Cookie / 認証情報)の窃取」 「難読化解除を前提とした解析」 「窃取データの暗号化および外部送信」 といった インフォスティーラー特有の処理を一連の流れとして説明できている点が良かったです。
また、本検体では難読化されたコード量が多かったためか、
Ghidraスクリプトの処理だけで約 4 分半を要しました。
性能検証まとめ
LLMを活用することで、
・静的解析結果の要点を素早く把握できる
・初見のマルウェアでも全体像を掴みやすい
・「次にどこを見るべきか」の指針が得られる
といったメリットを感じました。
一方でLLMには推測ベースの説明も含まれるため、
やはり細かい挙動の正確性は人間の確認が必須と感じています。
現時点ではあくまで人間の解析を支援する存在として使うのが現実的だと思います。
今回の取り組みを通じて個人的には、
マルウェア解析をもっと学んでいきたい という思いが強くなりました。
Ghidra を使った静的解析やコードリーディングの力を高めた上で、
その理解を補助・整理する存在として AI を活用していきたいと考えています。
また、本 AI エージェントは
解析結果を自然言語で説明できるという特性から、
リバースエンジニアリングやマルウェア解析の学習用途としても
活用できる可能性を感じました。
初心者が「何を見ればよいのか分からない」状態から抜け出すための
ガイド役として、教育目的での利用もできそうです。
今後は、
- LLM に渡す情報の選定精度向上
- 動的解析との組み合わせ
- 教育用途を意識した出力形式の改善
などにも取り組みながら、 この AI エージェントを継続的に改善していけたらなと思います。


