以下の内容はhttps://migawari-iv.hatenablog.com/entry/2025/12/26/103414より取得しました。


俺の飯のタネだったマルウェア解析の仕事はそろそろAIに奪われるんだろうか

本当はどこかのアドベントカレンダーに寄稿しようと思ったのですが、エントリーしそびれたので一般的な最終日の次の日に投稿させていただきます。

はじめに

皆さんはマルウェア解析やリバースエンジニアリングはお好きでしょうか? 筆者はだいすきです......が、先日管理職になってからマルウェア解析の仕事はほぼお休み中で悲しいです。何はともあれ学生時代からマルウェア解析や CTF (Capture The Flag) の Rev. 分野に触れてきた筆者ですが、ここ1年くらいで解析のやり方そのものが大きく変わってきたなと感じています。それはなぜかというと、皆さんご察しのとおり生成AIの存在です。正直 CTF の Rev. カテゴリは当たりを付けたら後はAIにコード投げて正しい回答を引かせるプロンプトエンジニアリングゲーの領域と化しており、マルウェア解析の局面でもAIと対話する時間が大きく増加しました。AIの力によって解析やコーディングの速度があがるのはとても喜ばしいのですが、その反面「自分のやっていることはそのうち全てがAIに取って代わられるんじゃないだろうか」という考えが頭をチラついたりもします。

現在は多くのアナリストがAIの助力を受けながら解析をしていると思われる昨今、 ObfusC(AI)tion CTF という難読化されたバイナリをAIの力を使って解析するコンテストが今秋 AVTOKYO2025 にて開かれました。

本投稿では ObfusC(AI)tion CTF イベントの様子に触れながら、実際 AI を使うことでマルウェア解析の仕事というのはAIに完全に奪われるのかということを考察していきたいと思います。

ObfusC(AI)tion CTF の様子

まずは AVTOKYO2025 で開催された ObfusC(AI)tion CTF の内容について簡単に紹介したいと思います。

どんなイベントだったのか

ObfusC(AI)tion CTF は AVTOKYO2025 の現地会場のみで行われた CTF チャレンジコンテストです。AVTOKYO は『no drink, no hack.』のキャッチコピーにある通りみんなでお酒を飲みながら楽しくセキュリティについて語る場で、皆さんお酒を片手にセキュリティ関連のイベントを楽しんでいます。
www.avtokyo.org

裏を返すと AVTOKYO に参加しているメンバーはセキュリティ畑に馴染み深い方々がほとんどで、現地で「私セキュリティ全く知りません!」という人に筆者は遭遇したことがありません。そのため本コンテスト参加者は世間一般で見ればある程度コンピュータセキュリティに精通している人たちで構成されていて、公式の発表では合計25名の方が本コンテストに参加していました。競技時間は3時間で、難読化されたマルウェアライクなバイナリを解析する問題4問、検知AIエージェントをバイパスする問題2問の合計6問が用意されていました。

どんなチャレンジが出たのか(Writeup)

すべてのチャレンジを紹介することは分量の都合上難しいので、筆者が現地で解いた難読化バイナリ解読問題 Confuse について簡単に紹介します。Confuse は Windows の実行ファイルで、正解となる入力を与えると FLAG を教えてくれるいわゆる Crackme 問題です。以下、簡単にチャレンジの解法を記述します。

> confuse.exe
usage: confuse.exe <hex-str>

>confuse.exe 12345678
NOPE

Windows の実行ファイルなので Detect it Easy を使って表層解析をしてみると ConfuserEX で難読化された .NET だとわかります。

> diec.exe confuse.exe --heuristicscan
(snip.)
PE32
    Linker: Microsoft Linker
    Library: .NET Framework(v4.8, CLR v4.0.30319)
    Protector: Confuser(1.X)
    (Heur)Protection: Obfuscation
    (Heur)Protection: Anti analysis

なので、まずは難読化を解除するために著名な .NET の deobfuscator である de4dot を使って難読化を解除します。

>de4dot confuse.exe

de4dot v3.1.41592.3405 Copyright (C) 2011-2015 de4dot@gmail.com
Latest version and source code: https://github.com/0xd4d/de4dot

Detected Unknown Obfuscator
Cleaning confuse.exe
Renaming all obfuscated symbols
Saving confuse-cleaned.exe

難読化解除ができたら後は読むだけになるので、dnSpy のような .NET アセンブリエディタ/デコンパイラを使ってソースコードを解析します。

dnSpy のデコンパイル画面

ここまでAIの出番がありませんでしたが、難読化解除の下処理が終わりようやくソースコードがほぼ見えるようになりました。ここまでできればあとは入力文字列の処理部分をAIにぶん投げて解析してもらい、入力すべき文字列を逆変換するコードを書いてもらうだけで終わりですね! ということで GPT-4 に生成してもらい筆者が一部修正したコードがこちらです。

import struct


# ランダムの定数値
uint_0 = [
    0x24DBFF24, 0xAC8CA113, 0x9CB8ACAE, 0x1E04D7B3, 0x41F91C68, 0x1303E0A5,
    0x38CC75B4, 0xBBA8EFD2, 0x9C88C17F, 0x7AF131ED, 0x53A5B255, 0x0D8F6397,
    0xF81AF02F, 0x5FCCA860, 0xE275DD3F, 0x4515512C, 0x9B84B1A4, 0x215BBC53,
    0x7D23AB8D, 0x15864CAB, 0x5D5DD780, 0x14B31E96, 0x53BAD32B, 0x00F94EDF,
    0x64B1C18D, 0x43732A17
]

def rol(val, bits):
    bits &= 31
    return ((val << bits) | (val >> (32 - bits))) & 0xFFFFFFFF

def ror(val, bits):
    bits &= 31
    return ((val >> bits) | (val << (32 - bits))) & 0xFFFFFFFF

def to_uint32(b):
    return b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24)

def from_uint32(n):
    return bytes([n & 0xFF, (n>>8)&0xFF, (n>>16)&0xFF, (n>>24)&0xFF])

def decrypt_block(target):
    assert len(target) % 8 == 0
    out_bytes = bytearray(len(target))
    for i in range(0, len(target), 8):
        num = to_uint32(target[i:i+4])
        num2 = to_uint32(target[i+4:i+8])

        num = (num + uint_0[0]) & 0xFFFFFFFF
        num2 = (num2 + uint_0[1]) & 0xFFFFFFFF

        for j in range(1, 13):
            tmp = num
            num = num ^ num2
            num = rol(num, num2 & 31)
            num = (num + uint_0[2*j]) & 0xFFFFFFFF

            num2 = num2 ^ num
            num2 = rol(num2, num & 31)
            num2 = (num2 + uint_0[2*j+1]) & 0xFFFFFFFF

        out_bytes[i:i+4] = from_uint32(num)
        out_bytes[i+4:i+8] = from_uint32(num2)
    return out_bytes

# 暗号化後のチェック対象バイト列
byte_1 = bytes.fromhex("6f62667573636174696f6e5f636f6e6675736521213f3f21")

# 入力値(逆演算)を生成
input_bytes = decrypt_block(byte_1)

print("Input bytes (hex):", input_bytes.hex())

このsolverの実行結果を Confuse に与えるとOK表示になったため、FLAG 獲得です。CTF とは言いながらも実にマルウェア解析らしい良い問題でした。やはりAI使うと作業を楽できますね。

> python solver.py
Input bytes (hex): e5472d894122c73424c2faee024ba9df9d1998753f085826

> confuse.exe e5472d894122c73424c2faee024ba9df9d1998753f085826
OK
FLAG{e5472d894122c73424c2faee024ba9df9d1998753f085826}

結果、どれくらい解けたのか

さて、チャレンジの内容について簡単に紹介しましたが、皆さんはこれを見て25人中何人くらい解けたと思いますか? 10人でしょうか? それとも solver 自体50行程度で簡単なんで20人くらい解けたと思いますかね? 正解は.......


.........


......


...


1 solve でした! はい、つまり非公式 Writeup を書けるのは筆者だけ状態です。そもそも難読化されたマルウェアライクなバイナリを解析する問題が4問ありましたが、解かれた問題はこのうち半分の2問しかなくもう一方も 1 solve の状態でした。

ObfusC(AI)tion CTF の結果(AVTOKYO 公式 Discord から引用)

筆者はタイムアップギリギリで Confuse を解いてコンテストを終了しましたが、多くの参加者がAIの力を借りながらも1問も難読化されたバイナリを解読できなかったということになります。な、なんだって。。。

AIのパワーだけではなぜ難しいのかという考察

会場には CTFer の方々や筆者の顔見知りのマルウェアアナリスト(いわゆるプロ)もおりが本コンテストに参加している姿を見たので、繰り返しになりますが参加者のレベル自体も特段低いわけではありませんでした。みんなお酒を飲みながらコンテストに参加しているので多少注意力やパフォーマンスが落ちているというのはありますが、なぜAIをフルパワーで使えても時間内に解析が難しかったのでしょうか? 理由を簡単に考察してみようと思います。

最初に何を聞くのか? という問題

この Confuse のチャレンジについては、そもそも「ConfuserEX による難読化処理が行われている => ツールである程度難読化が解除できる」を最初にAIからうまく聞き出せないとほぼ詰みだと思っています。少なくとも、3時間以内に解くのは難しいでしょう。そのため最初の問い合わせが一番重要になるとは思いますが、筆者の見解だとゼロ知識の状態でこの問い合わせをするには Detect it Easy のような表層解析ツールの出力結果をAIに解釈させるか Triage MCP のようなバイナリのトリアージ自体をAIに自動化させておくかのどちらかになるかと考察しています。つまり、この段階からすでにツールや環境を万全に整えておく必要があり、初見でいきなり対応できるかといわれるとかなり厳しめかと思われます。

また、トリアージ自体をAIにおまかせしていても、de4dot 等を使っている場合はシンボルの解決に失敗することもあります。例えば、下図の左側は解決に成功した画面で右側は解決に失敗した場合の画面なのですが、皆さんはここからAIにさらに質問できますかね...? 経験がある人は右側の画面を見て難読化解除失敗の理由を聞けるかもしれませんが、経験がない人だと(あー少し読みにくいけどなんとか読めるか)くらいにしか思わずこのまま茨の道を進むかもしれません。「どのラインまでがツールによる難読化解除の限界なのか」をAIに聞いて評価する匙加減の領域は、解析知識のベースがないと厳しそうに思えます。

左:難読化解除成功 右: 難読化解除失敗

難読化処理の仕組みそのものを詳しく聞かないと完全な solver コードを作れない

Confuse のチャレンジの内部コードには暗号化の処理が含まれており、処理の中にはいくらか定数が使われていました。例えば、下図の uint_0 などがそれに該当します。

定数なんてその値を参照してあげれば終わりでしょ......と思うかもしれませんが、AI に dnSpy でデコンパイルされたコード全てをそのまま与えても該当の uint_0 の値は読み込めず、解析や solver コードの作成に失敗します。これは ConfuserEX の難読化によって定数がリソース領域に埋め込まれていることが起因しており、定数値そのものを取得したければ以下のような PowerShell スクリプトなどを書いて解析者が独自で抽出し、AI が作成した復号コードの適切な箇所に値を埋めてあげなければいけません。

> $bin = [System.Reflection.Assembly]::LoadFrom("confuse-cleaned.exe")
> $type = $bin.GetTypes() | Where-Object { $_.Name -eq "Class5" }
> $field = $type.GetField("uint_0", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static)
> $field.GetValue($null)
618397476 # この値が python の solver コード中にある uint_0 の最初の値 0x24DBFF24 に該当します
2894897427
...
(snip.)

つまり難読化解除とデコンパイルが終わった後でも、難読化手法をAIに伝えたうえで解析時の特殊な処理の部分を聞き取りしなければ解けません。これがかなり難しかったです。筆者は ConfuserEX の難読化の仕組みを知っていたのでここをAIに聞くことはなかったのですが、後日改めてAIから引き出せるか確認してみたところ、ConfuserEX の仕組みや抽出の方法論などについてかなり詳しく調べてプロンプトを作り上げないと、上記のような抽出スクリプトまで提供してくれませんでした*1。「AIくんこのコードから復号スクリプト書いて」ではなく、こちらが難読化の仕組みや抽出方法などを理解したうえで指示をするか、AIとの対話を通して短時間で指示役が成長しないと solver の完成までもっていけないというのが、初心者が解析するうえでの一つの壁になっているかと思われます。

ハルシネーションを補正する知識と能力の重要性

最後の内容も、先ほどの「仕組みそのものを知らないと難しい」というものに近いです。Confuse の暗号化処理部分は既存のアルゴリズムである RC5 をベースに uint_0 に該当するランダム定数が処理中に混入しているいわゆる カスタムRC5 といえるような実装になっています。これは ConfuserEX のソースコードを見ても、 RC5 の処理に近いけれども手が加えられている部分の処理があることが確認できるかと思います。

github.com

つまり、solver としては RC5 をベースにしてカスタム部分を逆変換できるようなコードをうまく書く必要があるのですが、モデルによっては何度も逆変換コードの作成に失敗します。お金を積めば精度がよくなるのかもしれませんが、少なくとも無料で使える範囲での ChatGPT や Gemini などでは RC5 と判別してくれるけれどもカスタム部分が反映されていなかったり、難読化処理として判定してくれたコードが実は数行分必要な処理だったり、暗号化処理から復号処理に戻す逆変換部分の処理順がめちゃくちゃになったりと、求める solver コードが出てくるにはかなり対話の積み重ねが必要でした。最終的に筆者の場合は完璧な solver を作成することは諦めて人の力で solver の微修正を行う方針にしたのですが、これはデコンパイラや難読化ツールのソースコードと照らし合わせながら矛盾する箇所を見極める力がないとできません。結局のところ、無課金勢にとっては最後の最後で己の実力で解析結果とにらめっこする力が試されるかなと思われます。

おわりに

ObfusC(AI)tion CTF のイベント結果をもとに、マルウェア解析の仕事が誰でもできるものになるのかというのを簡単に考察してみました。結論を言ってしまうと、現段階のAIを使っても知識のあるマルウェアアナリストの作業の一部を代行してくれることがメインで、経験が浅い人が使っても見違えるほど強くなれるような存在ではないように思えます。ただし AI の進化速度が速すぎるので、あと2~3年したらこれらの課題もクリアしてほぼ全自動で解析できる日が来そうな気がしています。そしたら多くの企業の CSIRT は AI で Deep なインシデントレスポンスをできるようになっていい世の中になりますね。

このようにマルウェア解析に関わる業務も様々な部分がAIによって代行され業務負荷が減った反面、筆者としては少し物足りなさを感じています。筆者が解析で好きだったことはアセンブリから少しずつRATの命令パターンや通信のフォーマット特定して、そこから復号スクリプトを作ったり解析を自動化することだったのですが、そのあたりの楽しい部分はほぼ全てAIが担うようになってしまいました。かつて好きだった数日かけて復号や解凍処理を解析をするような時間は失われ、その変わりにプロンプトエンジニアリングやAIが生成したコードの手直しといった、筆者にとっては「物足りないなぁ」と感じる作業が増えたのです(こんなことを書いている時点で老害だとは思いますが....)。筆者自身の専門性が失われたわけではなく、マルウェア解析の専門性自体は依然として高度なので仕事としては残ると思いますが、「もう少しだけ AI くんの成長速度落ちて、楽しい部分の仕事が残っていてくれないかなぁ」と思う今日この頃です。

*1:中途半端に聞くと「実行すると値を確認できます」といった動的な解決方法しか返ってこず、中途半端な場所で値を参照しても欲しい値が手に入らない場合があり運に影響されます




以上の内容はhttps://migawari-iv.hatenablog.com/entry/2025/12/26/103414より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14