[レポート]チート対策コンパイラDeClangの自動テスト #denatechcon #techcon_11
2021年3月3日(水) に DeNA TechCon 2021 がオンラインで開催されました。
DeNA TechCon 2021 - 技術の力で事業の未来をリードする -
本記事は「チート対策コンパイラDeClangの自動テスト」セッションをレポートします。
スピーカー
株式会社ディー・エヌ・エー
システム本部セキュリティ部セキュリティ技術グループ
セキュリティエンジニア 森 槙悟さん
セッション概要
セッションページからの引用です。
DeNAではスマホゲームのチート対策として、チート対策コンパイラDeClangを内製で開発しています。ゲームのチートを防ぐには、DeClangが正常に動作しているか確認するテストが必要です。そのテスト自体も手動で行うとミスが発生しやすい上に手間もかかるため、テストを自動化し一定以上の品質を担保しなければなりません。 一方で自動でテストを行うには、Mac, Linux, Windows, Android, iOSと各OSに対応させた上で自動でチートを行いそれが検知されるか確認する、つまりアプリのコード改ざんなどを自動で行う複雑なシナリオを実行する必要があります。また、OSS版と内部拡張版でリポジトリが分かれている点も対応が必要ですし、DeClang自体のビルドを高速に処理する必要もあります。 この発表では、それらの問題にどのように対応し、クラウド上でDeClangの自動テストをいかに実現したかを解説します。
レポート
DeClangとは?
- そもそもDeClangって何?
- DeNA + Clang
- 主にスマホゲームのチート対策
- コンパイル時に難読化・改ざん検知を埋め込む
- アプリコードは変更不要で、コンパイル時に埋め込む
- IL2CPPでUnity C# → C++にする
- Android・iOS向けのビルドで Clang → DeClangに置き換える
- 過去の発表資料に詳細あり
動作確認
DeClangの動作確認
- 開発時の動作確認
- DeClang自体が正常に動くか確認したい
- 追加した機能が動くか?
- サポートしてる環境で動くか?
- デグレードしてないか?
- 毎回QAチームにコード改ざんしてもらうのは非現実的
手順
- OSS版をClone
- 内部拡張のプラグインをクローン
- DeClangをコンパイルする (CMakeとかMakeとか)
- NDK・XcodeのコンパイラをDeClangに差し替える
- Android・iOSアプリをコンパイルする
- アプリのコードを改ざんする
- 実機をPCにつないでインストールする
動作確認する
- 手順が多く複雑、1環境だけでも数十分かかる
- 手順を少しでも間違えると確認できない
- ビルドキャッシュとか
- 自動でテストしたい
- クラウドに移行をすすめているので、できるだけクラウドで実施したい
- 自動テストの難所
- アプリのコード改ざん
- クラウドの各OSでアプリをインストール・動作確認
- 各OSへの対応
- Mac
- Bitriseを使う
- Linux・Windows
- AWSのEC2 + Jenkins
- Android・iOS
- headspinを使う
- Mac
- Bitrise (Mac対応)
- モバイルアプリに特化したCIプラットフォーム
- Mac・Ubuntuが利用可能
- Xcodeのバージョン指定できる
- テストフロー
- 社内のGitHubへの接続設定
- Provisioning Profileを設定 (署名できるように)
- リポジトリのクローン
- DeClang本体のビルド
- ビルドに1時間ぐらいかかる
- ccacheでビルド時間短縮、2回目は5分ぐらい
- キャッシュはS3とsyncする
- テスト本体
- Bats + HeadSpin
- Jenkins (Linux・Windows対応)
- EC2で環境構築してAMIを作成する
- EC2 PluginでそのAMIのノードを作る
- Windows版はMSYS2を使う
- Mac・Linuxと処理を共通化するため (Bashで)
- 他はBitriseと同様
- HeadSpin (Android・iOS対応)
- Android・iOS実機用のデバイスファーム
- 専用端末が安定して動作する
- WebUI・APIで実機を操作できる
- アプリのテストにAppiumを使える
- AppiumはSeleniumのアプリ版みたいなもの
- HTTPでコマンド送信してアプリを操作する
テスト内容の詳細
コード改ざん検知機能とは?
- チートはフックでアプリの処理を変えることが多い
- コンパイル後のバイナリは機械語を書き換えることで改ざんすることができる
- 関数の先頭をジャンプ命令に書き換える
- DeClangは対策として関数の機械語の列がコンパイル時点と変わっていないか検査する
- コード改ざんを検知した場合は指定された関数を呼び出す
- どうやって自動で改ざんするか?
- 文字列を置き換えるsedコマンドでOK!
- 改ざん対象の関数を用意して目印となる数値を埋め込んでおく
- LLDBなどでディスアセンブルして即値ロードの命令を確認する
- 即値ロードの命令を
sed
コマンドで書き換える - コード例
# movz w3, #0x1f3e -> movz w3, #0xffff xxd -p sample.so | tr -d '\n' | sed s/c3e78352/e3ff9f52/ | xxd -r -p > ${temp_file} cp ${temp_file} sample.so
- 改ざん完了後にリパッケージする
複数のテストシナリオへの対応
- テストしたいシナリオが複数ある
- 改ざんした場合に検出ログが出るか?
- 改ざん後正常に動いてるか?
- 指定した関数を難読化しているか?
- Batsを使って各テストに試したいシナリオを書く
- Bats = Bash Automated Testing System
- シナリオに複雑なものが多く、bashスクリプトとassertで
- Pythonとか他のコマンドでも良いけど、コマンド呼び出しが多く他の言語を使うメリットが薄い
- Batsを使ったテストのシナリオ例
結果
- デグレを抑制できるようになった
- 動作確認のミスがなくなった
- 各OSでDeClangが動作することを保証できる
- 早いと15分ぐらいで終わる
- 自動テストを作る過程でバグを発見・修正
まとめ
- DeClangはチート対策コンパイラ
- 複雑な確認手順を自動化
- Bitrise・EC2 + Jenkins・HeadSpinを利用してクラウドで実行
- コード改ざんを自動で再現するためにsedを利用 (目印を埋め込む)
- Batsを使って複数のシナリオに対応
- デグレを抑制できるようになった
おわりに
メモリスキャンやバイナリ改ざん、通信内容の改ざんなど、ゲーム開発者にとってチート対策は頭が痛くなる問題だと思います。DeClangのように、アプリのコード変更を必要とせず、コンパイル時点で対策してくれるのは非常にありがたいと思います。
OSS版が公開されているので、チート対策に困ったときは試してみると面白そうですね!