ゲームファジングの希望「IJON」

こんにちは初めまして！
watnowに所属しています、立命館大学3回生のumiyuriと申します。
僕は開発経験もあまりなく、ほかのメンバーのような技術的な話はあまりできないのです....
最近研究室に配属されたこともあり、研究してみたいなとおぼろげに思っている***ゲームに対するファジングの適用***についてお話ししようかなと思います！
ゲームへのファジングの適用については、世界でも例が少なく、まだまだ発展途上の分野となっています。
ぜひ頭の片隅に残しておいていただけると嬉しいです！

# そもそもファジングって何???
ファジングという単語を聞いたことがない人も多いのではないかのと思います。
（そもそも一般的なものではない）


IPA（情報処理推進機構）の資料では、
>検査対象のソフトウェア製品に「ファズ（英名：fuzz）」と呼ばれる問題を引き起こしそうなデータを大量に送り込み、その応答や挙動を監視することで脆弱性を検出する検査手法です。

と述べられています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/a482ef82-ccd2-4f6e-894c-977e29825b83.png)
つまりもっと簡単かつ適当にいうなれば、「ランダムにいろいろ入力してみて、おかしな出力が出てないか検証する」ってこと
ソフトウェアの***テスト手法の一つ***なんだなあと思ってもらえたらと思います。

# ファジングを用いることの利点
ファジングを用いる利点としては、***開発者が想定していない入力までテストできること***が挙げられます
例えば、ゲームなら壁に向かってダッシュしてジャンプしまくると壁に埋まる、的なバグはよくあるかと思います。
普通のプレイではこんな入力は起こるはずがないですよね（笑）
このようなバグは従来のテスト手法ではテストしきれていない可能性が高いです。


# ゲームにファジングを適用することの難しさ
「ゲームって想定しないバグ結構ありそうだし、ファジングでゲームのテストやればいいじゃん」という発想が出てくるのも自然な流れかと思います。
そんな感じで僕の研究室では先輩たちが頑張っているわけですが、なかなかこれが一筋縄ではいかんのです...

## ゲームごとに作り替えなきゃいけない
これは当たり前ではありますが、ゲームはジャンルによってどんな操作が必要かが異なります。
レースゲームならコースの通りに進み続けますし、オープンワールドなら何をやってもいいんです。
|![スクリーンショット 2024-12-07 14.56.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/c36c8861-16e7-1a0c-3742-393b70cbdc76.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/41bb92ce-a88a-3b11-1d4f-81af42e4acb5.png)|
|---|---|
|https://www.youtube.com/watch?v=HljJvwifETg|https://www.youtube.com/watch?v=OMw-xmBEWuE|

必要な入力のタイミング、継続時間等もゲームによってそれぞれ特殊になっているので、「ゲームのファジングができるツール」として開発できないという難点があります。

## 単純にファジングするだけだと意味を為さない
前述した通り、ファジングはランダムに入力を生成することでソフトウェアの脆弱性を発見します。
特にオープンワールドのゲームにファジングをただ適用しただけだとこうなるのです

<iframe width="560" height="315" src="https://www.youtube.com/embed/QxiIJMdJGjg" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>

そう、***その場で動き続けるだけ***なのです
これは毎フレームごとに入力を生成しているからで、状態の数が膨大になってしまうからだと考えられます。

例えば、簡単のために、上下左右４方向にしか移動できないとしましょう。
![名称未設定ファイル.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/125f4613-bfb4-7b8f-4035-9fb69647a706.png)
1フレームにつき4通りの選択肢があります
つまり、
1秒(=60フレーム)で4^60通り、
1分(=3600フレーム)で4^3600通り
になってしまうわけです
最近のオープンワールドなら斜めにも進めるので、実際のゲームにしてみたらもっと状態数は多くなります....
こんなの、***１秒間まっすぐ進むだけでも奇跡***なわけです😅

これで、ゲームにファジングを適用することの難しさを理解してもらえたんじゃないかなと思います

# ゲームファジングの希望「IJON」
そんな時に現れたのがIJONです！！！！
なんとこいつは初代スーパーマリオをクリアできるファジングツールだと言い出したんです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/16bf6bee-2a73-8aa3-2358-2e9640dc81cc.png)
[IJONの論文内の画像](https://ieeexplore.ieee.org/document/9152719)より引用

従来のファジングツールとして有名なAFL(American Fuzzy Lop)と比較しても歴然で、AFLでは一度もクリアできていません

# なぜIJONが優れているのか
それはIJON固有の機能である***アノテーション***が効いています。
人間がソースコードに`アノテーション`といわれる数行のコードを挿入することができます。

こんな感じで
```diff_c
void ErrorMessege::setmsg(const std::string &msg)
{
    static unsigned int call_count = 0;
    call_count++;
+   IJON_MAX(call_count);

    ...(中略)...
}
```
https://kuznetsov.am/fuzzing-cppcheck-ijon より引用


アノテーションを付けることで、ファジングツールが生成する***入力列を少々ガイドしてやる***ことができます。
これで効率的にいろんな状態を探索することが可能になるわけですね！

IJONで実装されているアノテーションにはたくさん種類があります。
(気になる人は[論文](https://ieeexplore.ieee.org/document/9152719)を読んでみてください)

今回は初代マリオをクリアした例で使用されていた `IJON_MAX()`について紹介します。
`IJON_MAX()`では、引数に設定された変数が最大になるように入力列を生成するようになります。

マリオをクリアさせるなら、右側にゴールがあるので***X座標を最大化する***ようにすればよさそうですよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/70147383-0d5c-1250-6abd-52983dcd7efe.png)
[IJONの論文内の画像](https://ieeexplore.ieee.org/document/9152719)より引用

こんな数行を挿入するだけで探索の効率が爆伸びするんです、革命的ですね...

AFLでは１２時間かけてもクリアできなかったのに対し、IJONは難なくクリアでき、さらにはグリッチまで２つ発見したと報告しています

# IJONの欠点
こんな完璧にも見えるIJONに欠点は存在しているんです。。。
~~一番の問題は、IJONは更新が4年前で止まっていてろくに保守されていないことなんですけどね~~

## 誰でも簡単に使えるというわけではない
アノテーションをソースコードの中に挿入しないといけない関係上、プログラムをよく理解しているエンジニアしか利用できません。
適当にアノテーションを入れ込んだだけでは探索の効率が上がらず、普通にAFLを動かしているのと変わりません。

## アノテーション入れるの普通にめんどい
ゲーム性を理解して、どのようにアノテーションを入れればいいか考え、ソースコードを読み、必要な変数を見つけ、アノテーションを挿入して,,,
***めちゃめちゃしんどいし、時間かかっちゃうんですよね***
~~少なくとも「個人開発で作成したゲームにIJON適用してバグ探すぞ！」とかめんどくさくて僕は絶対やらないですね~~

## アノテーションを入れてガイドした入力で本当に想定しないバグは見つけられるのか？
前述したとおり、ファジングは「ランダムな入力を生成し、開発者が想定していないバグを見つけることができるツール」です。
- アノテーションなんか入れ込んで人間が恣意的に入力列をガイドしてしまったら、それは本当にランダムに生成された入力なのでしょうか？
- 人間が恣意的に誘導した生成列で、想定しないバグを発見できるのでしょうか？


これは議論の余地があるように感じていますが、僕は下の図のようなグラデーションでつながっていると考えています。
![スクリーンショット 2024-12-12 14.32.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820975/3cc230ff-cf25-2b7e-bba4-1c1dcc43f1a2.png)

***完全にランダムでもないが、想定しないバグを完全に発見できないほど人間が誘導しているわけではない***というのが僕の考えです。
というか、ちょっと自由度高くなると前に載せた動画みたいに、テストとして成立しないんですよね...
人間が少しくらいガイドしてやることは、ファジングを適用する上で必須のものだと感じています。



# 終わりに
いかがでしたでしょうか？
ゲームファジングの希望「IJON」についてお話させていただきました。
入力列をもともと用意しておいて、それに基づいて行われる自動テストであれば、現在でも盛んに行われているのですが、ゲームに対するファジングの適用はまだまだ発展途上です。
少しでも覚えておいてもらえると嬉しいです！
もしIJONを動かしてみたいと思った人がいたら[僕の記事](https://qiita.com/umiyuri777/items/8a3bc88e8410b2314b81)を参考にして動かしてみてください！
マニアックすぎて日本語で書かれたIJONの記事は僕の記事のみです！
ここまでお付き合いいただきありがとうございました！


# 参考
[ファジング活用の手引き](https://www.ipa.go.jp/security/vuln/fuzzing/ug65p9000001986g-att/000057652.pdf) - IPA (2024/12/6 参照)
[Ijon: Exploring Deep State Spaces via Fuzzing](https://ieeexplore.ieee.org/document/9152719) - IEEE (2024/12/7 参照)
[Фаззинг cppcheck с помощью IJON+AFL](https://kuznetsov.am/fuzzing-cppcheck-ijon) - Александр Кузнецов (2024/12/8 参照)