Slide 1

Slide 1 text

Unityでのチート対策を簡単かつ 高品質に行う為の取り組み 大竹悠人 ゲーム事業本部開発事業部開発二部テクノロジー推進グループ 株式会社ディー・エヌ・エー © DeNA Co.,Ltd.

Slide 2

Slide 2 text

自己紹介 2 ● 大竹 悠人(Haruto Otake) ○ ゲーム事業本部開発事業部開発二部テクノロジー推進グループ ○ Twitter: @Trapezoid ● 2013年よりDeNAにジョイン ○ Unityに関連した技術サポートと様々な内製ライブラリの実装・保守に従事 ○ クライアントチート対策のサポート /実装も複数のタイトルで担当

Slide 3

Slide 3 text

3 クライアントチート対策の性質と それに向けたDeNAの体制 透過性のあるクライアントチート対策が必要な理由について

Slide 4

Slide 4 text

モバイルゲームのチート対策の大分類 4 ● クライアントチート対策 ○ クライアントアプリへの不正な操作を 困難にし、検出する ○ 完璧に防ぐことは不可能 ■ 対策の強度が高ければ、 攻撃者にとっての合理性 を低くすることは出来る ○ 突破されては対策してを繰り返す、一定のイタチごっこが必要 ● サーバチート対策 ○ サーバ側への入力を検証して不正な操作や状態遷移を阻止する ○ 入力として有効な範囲で行われたクライアントチート の検出は困難 ゲームに適合するバランスで両立することが必要

Slide 5

Slide 5 text

モバイルゲームのチート対策の大分類 5 ● クライアントチート対策 ○ クライアントアプリへの不正な操作を 困難にし、検出する ○ 完璧に防ぐことは不可能 ■ 対策の強度が高ければ、 攻撃者にとっての合理性 を低くすることは出来る ○ 突破されては対策してを繰り返す、一定のイタチごっこが必要 ● サーバチート対策 ○ サーバ側への入力を検証して不正な操作や状態遷移を阻止する ○ 入力として有効な範囲で行われたクライアントチートの検出は困難 今回はクライアントチート対策に関しての話

Slide 6

Slide 6 text

6 モバイルゲームのクライアントチート対策のコストの性質 ● 運用中は継続的にチート対策コストがかかり続ける ○ 攻撃にさらされ続けるので、対策範囲と強度の見直しを継続的に行う必要がある ○ 運用での機能追加がされた際にもチート対策を行う必要がある ● 重要である一方で、積極的に(多く)払いたいコストではない ○ チート対策は実行性能/実装工数の両面へのトレードオフを伴う ○ チート対策がUXに寄与するのは、チート行為を減らせるかという成果面のみ

Slide 7

Slide 7 text

7 結果、クライアントチート対策は既存の実装に対して適用される ● 最初からクライアントチート対策された状態の実装を書くのは非常に困難 ○ 特に試行錯誤を伴う段階で行うのは工数の無駄が非常に大きい ○ チート対策はパブリックに公開される段階で適用されていれば良い ● 運用中の機能への適用範囲/強度の拡大(チータとのいたちごっこ) ○ 当然、常に既存の実装に対して適用することになる

Slide 8

Slide 8 text

8 既存実装に対して後からチート対策を適用するリスク ● クライアントチート対策でゲーム自体が変化することはあってはならない ○ チート対策の適用による実装変更の量が多ければ不具合混入の危険も大きい クライアントチート対策には 既存実装の動作を極力変えない、高い透過性が求められる

Slide 9

Slide 9 text

9 今回の主題 透過性に着目した DeNAのクライアントチート対策

Slide 10

Slide 10 text

透過性の高いクライアントチート対策を行うための体制 10 ● 透過性の高いチート対策ライブラリ を横断部門から各タイトルに提供 ○ 横断部門の専門性の高いメンバーが、専門性が必要な領域を担える ○ チート対策ライブラリのアップデートによる簡単な強度強化も可能に ● 各タイトルの担当者は、チート対策を必要なだけ導入する ○ 透過性が高いので好きな時に、限りなく少ない影響で安全に 導入できる 高品質なクライアントチート対策を できるだけ少コストで利用可能な環境を実現する

Slide 11

Slide 11 text

11 主なクライアントチート対策 動作中のアプリの メモリを改ざんする (読み込まれたマスタ/プレイヤー データやステータスを、有利な状態 に強制的に変更する ) 行為を制限し、検出する。 メモリ改ざんソフトや、チート対策 の回避を行うソフトの 動作環境となる環境 (Root / 脱獄, エミュレータ等)で のアプリの動作を制限する ゲームロジックそのものや他の チート対策を解読して、チート対策 の回避をしたり、ゲームの挙動を 変化させる 行為を制限し、検出する。

Slide 12

Slide 12 text

12 DeNAのクライアントチート対策ソリューションの技術スタック

Slide 13

Slide 13 text

13 DeNAのクライアントチート対策ソリューションの技術スタック

Slide 14

Slide 14 text

14 GuardProperty 透過性の高いメモリ保護ライブラリ

Slide 15

Slide 15 text

15 GuardPropertyによるメモリヒープ上の値の改ざん保護 ● 透過性の高いメモリ保護を可能にする、DeNAの内製ライブラリ ● 直接メモリを書き換える事によるメモリヒープ上の値のデータ改ざんを保護する ○ 改ざんを検知したら登録した関数を呼び出してゲームの終了等を行う ● フィールドに指定する型を置き換えるだけでメモリ保護ができるというコンセプト 型を置換

Slide 16

Slide 16 text

16 型の透過性を高めるための仕組み ● 暗黙的に元の型と相互変換を行う互換型として実装 ○ 暗黙的変換により、代入や演算も行える ○ ほぼ元の記述のまま適用することが可能 ● readonly structで実装 ○ 防御的コピーの回避 & 元の型と同等に扱う為 ○ 保護状態でコピーすることで改竄検知を遅延

Slide 17

Slide 17 text

17 DeNAのクライアントチート対策ソリューションの技術スタック

Slide 18

Slide 18 text

18 DeNAのクライアントチート対策ソリューションの技術スタック

Slide 19

Slide 19 text

19 チート対策用C++コンパイラ DeClangのしくみ

Slide 20

Slide 20 text

20 クライアントチート対策の手動実装を代替するコンパイラ ● 手動実装時のクライアントチート対策の流れはかなり固定的 ○ ある関数を通った時に(When) ○ 様々なチート検知ロジックを実行し (What, To) ■ 改ざん検知 / 不正環境(Root/脱獄/エミュレータ…)の検知 など ○ チート検知時にアプリケーションの終了等の処理を行う関数を呼び出す (Then) ● チート対策用C++コンパイラ ○ clang等のC++コンパイラと差し替えて利用するチート対策ソリューション ○ コンパイル時に透過的にLLVM IRを改変し、ソース変更せずにチート対策を施す ○ コンパイル時に動くので、関数単位での改竄検知も可能 ● When/What/To/Thenを設定として記述することで、チート対策の内容を指定する

Slide 21

Slide 21 text

21 チート対策用C++コンパイラの選択肢 ● Digital.ai App Protection (EnsureIT) ○ Digital.ai社開発の有償ソリューション ○ 保護の品質はとても高い(外部ベンダのソリューションの為、詳細は省略 ) ● DeClang ○ DeNA セキュリティ部により提供されている DeNA内製のプロダクト ○ OSSとして公開していて、無料で利用可能。 Unity(IL2CPP)に対応 ○ DeNA専用の拡張版が存在(OSS版にはないチート対策機能を多数搭載 )

Slide 22

Slide 22 text

22 DeClangの詳細については開発者による過去の講演を参照 ● DeClang 誕生!Clang ベースのハッキング対策コンパイラ ● DeClang : Anti-hacking Compiler

Slide 23

Slide 23 text

23 チート対策用C++コンパイラの使用例 シーン管理処理と、 ダメージ計算関数、 そして改竄された際のログ関数を まず仮定する。 シーン開始時にScene1Startが シーン終了時にScene1Endが それぞれ呼ばれるとする。

Slide 24

Slide 24 text

24 チート対策用C++コンパイラの使用例 シーン開始時と終了時にそれぞれ ダメージ計算関数の改竄を検出 改竄されていたら 改竄検知ログ送信関数を呼び出す。 このような改竄検知処理を コンパイル時に既存コードに挿入できる

Slide 25

Slide 25 text

25 多層的な改竄検知によるチート対策の強化 ● 改竄検知処理自体を改竄検知する ○ 改竄検知処理自体の改竄によって突破 されても、その改竄を検出できる ○ これを何重にも積み重ねる ○ すべてを改竄しないと突破できない ● クライアントチート対策全般を巻き込んで保護 ですると非常に効果が大きい ○ 下層で不正環境検知を行ったり、メモリ 保護のコードを改竄検知する

Slide 26

Slide 26 text

26 チート対策用コンパイラ(のUnityでの)共通のメリット/デメリット ● メリット ○ コードを変更せずチート対策を差し込める事による、 透過性の高さ ■ 開発用に検知を外すコードパスを用意する必要がなくなる (ビルドフローで対応可 ) ■ パフォーマンス問題があったときに強度を弱めるなどの調整が容易 ○ 手動実装では困難な多層的な改竄検知による、強力なチート対策性能 ● デメリット ○ コードに強く依存する設定としてチート対策の構成を生成する必要がある ■ いつ/どの対象の/どんな事象を検知し違反時にどうするか ■ シンボル名ベースで指定する必要があり、 IL2CPPの命名規則を知る必要も ○ 多層的な改竄検知を構築するにはチート対策への深い理解と多大な工数が必要 ○ 設定の形式は実際のチート対策用コンパイラ毎に異なり、ロックインされる

Slide 27

Slide 27 text

27 そのまま使うコストは高い ● 性能/透過性は高いが、扱うためのコストが高い ● 設定(と導入)のコストを大幅に下げるような仕組み が必要

Slide 28

Slide 28 text

28 DeNAのクライアントチート対策ソリューションの技術スタック

Slide 29

Slide 29 text

29 CodeGuardConfigurator Unity向けのDeClang/EnsureITの共通フロントエンド

Slide 30

Slide 30 text

30 CodeGuardConfigurator ● チート対策用C++コンパイラをUnityで簡単に利用する為のフロントエンド ○ C#コードの保護を、C#コードによるDSLとして記述できる ○ 保護の対象/起点/内容を独立して記述すると保護設定を 自動的に構築する ○ 複数のチート対策用C++コンパイラに対して、同一の手法で設定を記述できる ● 最近のDeNAのゲームの多くで利用中

Slide 31

Slide 31 text

31 多層的な検知構造の自動生成 自動的に階層的な改 竄検知を生成 各々を独立に記述

Slide 32

Slide 32 text

32 多層的な検知構造の自動生成 Seedに応じて 構成を変更 Seed以外は同じ入力

Slide 33

Slide 33 text

33 C#コード(対象/起点)の指定 ● 単体指定と範囲指定で宣言的に区別 ○ 保護の起点は単体指定 ○ 保護の対象は範囲指定 ● リファクタリングでも追跡される記述 ○ Generics / nameof / typeof ○ コードと設定の乖離を防止 ● 合成をサポート ○ 単体 + 単体 = 範囲 ○ 範囲 + 範囲 = 範囲 FunctionExpression.OfMethod( nameof(Chara.DealDamage) ); 対象はメソッド単体 対象のクラス 対象のメソッド RangeExpression.OfClass(); 対象はクラス全体の 範囲 対象のクラス RangeExpression rangeExpression = functionExpression1 + functionExpression2; 単体指定同士を 範囲指定に合成

Slide 34

Slide 34 text

34 保護内容の指定(の擬似コード) ● 保護内容の種類毎のプロパティに指定 ○ 対象がある場合引数にコードを指定 ○ 保護対象毎にオプションも指定 ■ 強度や起点の選択条件など ● いくつかの設定は演算子で合成可能 ○ 設定の責任範囲の分解が可能になる ○ ライブラリ側で難読化や改竄検知を行うべき 範囲を定義できる ○ 内製サーバSDK等で実施 new GuardNetworkBuilder( //利用ミドルウェアとプラットフォームを指定 MiddlewareTypes.DeClang, MiddlewareTargetPlatforms.Android ) { Seed = seed, FirePointSets = new () { //保護起点をFunctionExpressionで指定 scene1Start, scene2Start }, CheckSumPoints = new (){ //改竄保護対象を指定 charaClass, enemyClass, scene1Start, scene2Start }, Obfuscates = new (){ //難読化対象を指定 (強度も指定できる ) {charaClass, 2f}, enemyClass, scene1Start, scene2Start }, //Root検知を実施 DetectJailbreakAndRooted = DetectJailbreakAndRootedSource .OfDefaultPhase() /* 省略 */ );

Slide 35

Slide 35 text

35 Unityのメタデータ(global-metadata.dat)暗号化機能 ● メタデータファイルが平文だと、容易にシンボル名などが解析されてしまう ○ IL2CPPで変換されるコードの動作にはメタデータファイルは必須 ○ 暗号化が望ましいが、ナイーブな組み込みが必要になる ● CodeGuardConfigurator側で機能を提供 ○ Unityのポストプロセス処理として暗号化プロセスを実装 ○ 有効化するだけで、自動的に暗号化 /復号化実装が組み込まれる

Slide 36

Slide 36 text

36 CodeGuardConfiguratorを介したUnityプレイヤービルド

Slide 37

Slide 37 text

37 従来の問題点の解決 ● コードに強く依存する設定としてチート対策の構成を生成する必要がある ○ C#で使った記述を可能にし、実際のコードへの追従性を担保 ● 多層的な改竄検知を構築するにはチート対策への理解と多大な工数が必要 ○ 定義するべきことを絞り、本当に知るべきことだけを知るだけで設定可能 ○ 実際の検知の構築を自動化して、多層的な改竄検知の品質を安定させる ● 設定の形式は実際のチート対策用コンパイラ毎に異なり、ロックインされる ○ 設定手法は共通なので、どちらを使ってもノウハウを共有することが可能 ○ 導入後の切り替えや、どちらにするかの意思決定の遅延が可能

Slide 38

Slide 38 text

38 DeNAのクライアントチート対策ソリューションの技術スタック

Slide 39

Slide 39 text

39 真に透過性のある クライアントチート対策を提供することで 簡単かつ高品質にチート対策を ゲームに取り入れられるようになった

Slide 40

Slide 40 text

40

Slide 41

Slide 41 text

41