Unityゲームのハッキング(および保護)の実践ガイド





ソフトウェアに関して言えば、「ハッキング」という用語は著作権侵害や著作権侵害に関連していることがよくあります。 この記事はそれについてではありません。 それどころか、他の開発者に直接的または間接的に損害を与える可能性のある行為を強く不承認にします。 ただし、この記事は依然として実用的なハッキングガイドです。 後で説明するツールと方法を使用して、独自のUnityゲームの保護を確認し、ハッキングやリソースの盗難から保護する方法を学ぶことができます。



はじめに



ハッキング知識に基づいています。Unityプロジェクトをハッキングするには、Unityプロジェクトのコンパイル機能を理解する必要があります。 この記事を読んだ後、Unityがゲームリソースをコンパイルする方法と、そこからソースマテリアル(テクスチャ、シェーダー、3Dモデル、スクリプト)を抽出する方法を学習します。 これらのスキルは、プロジェクトのセキュリティの分析だけでなく、その高度なデバッグにも役立ちます。 閉じられたソースコードのため、Unityは「ブラックボックス」として機能することが多く、その中で何が起こっているのかを正確に理解する唯一の方法は、コンパイルされたバージョンのスクリプトを調べることです。 とりわけ、他の誰かのゲームを逆コンパイルすることは、その秘密と「イースターエッグ」を見つけるのに非常に役立ちます。 たとえば、これがFEZの最終的なパズルの解決策を見つけた方法です。







ゲームリソースを見つける



たとえば、Windowsで構築され、Steamを介してダウンロードされたゲームを考えてみましょう。 必要なリソースがあるディレクトリに移動するには、Steamライブラリでゲームのプロパティウィンドウを開き、[ローカルファイル]タブで[ローカルファイルを参照...]をクリックします。







UnityがWindowsでプロジェクトをコンパイルするとき、リソースは常に同様の方法でパッケージ化されます:実行可能ファイル(たとえばGame.exe



)はゲームのディレクトリのルートにあり、ゲームのすべてのリソースを含むディレクトリGame_Data



は隣にあります。



テクスチャとシェーダーの取得



ほとんどのUnityプロジェクトリソースは、 .resources



.assets



および.resources



独自形式のファイルにパッケージ化されています。 そのようなファイルを表示し、そこからリソースを抽出するためのこれまでで最も人気のあるツールは、 Unity Assets Explorerです。







プログラムのグラフィカルインターフェイスは便利ではなく、いくつかの重大なバグもあります。 それにもかかわらず、このプログラムはゲームからほとんどのテクスチャとシェーダーを抽出することができます。 結果のテクスチャはDDS形式になり、 Windows Texture Viewerを使用して「読み取る」ことができます。



シェーダーの状況はより複雑です。シェーダーは既にコンパイルされた形式で抽出され、私が知る限り、読み取り可能な形式に自動変換する解決策はありません。 それでも、この状況は、別のUnityプロジェクトで結果のシェーダーをインポートして使用することを妨げません。 ただし、このような「盗難」は著作権を侵害し、著作権侵害行為であることを忘れないでください。



3Dモデルの取得



典型的なUnityアセンブリの3次元モデルはさまざまなリソースに「分散」されており、それらの一部はゲーム中に生成されることさえあります。 ファイルを掘り下げる代わりに、グラフィックアクセラレータメモリからジオメトリデータを直接取得するという興味深い代替方法があります。 ゲームの実行中、画面に表示されるテクスチャとモデルに関するすべての情報は、ビデオカードのメモリにあります。 3D Ripper DXユーティリティを使用すると、このすべての情報を抽出し、3Dエディターが理解できる形式(3D Studio Maxなど)で保存できます。 プログラムは最も使いやすいものではないことに注意してください-ドキュメントを参照する必要があるかもしれません。







PlayerPrefsをハックする



PlayerPrefsは、Unity標準ライブラリのクラスであり、デバイスの長期メモリにデータを保存できます。 多くの場合、開発者はさまざまな設定、実績、プレーヤーの進行状況、およびゲームの状態に関するその他の情報を保存するために使用します。 Windowsでは、このデータは次の方法でレジストリに保存されます: HKEY_CURRENT_USER\Software\[company name]\[game name]











標準のregeditユーティリティを使用すると、PlayerPrefsの値を簡単に変更して、ゲームの構成とステータスを変更できます。



PlayerPrefsの保護



ユーザーがレジストリの値を編集できないようにすることはできません。 しかし、これらの値が私たちの知識なしに変更されたかどうかを確認することは非常に現実的です。 ハッシュ関数はこれに役立ちます。保存されたデータのチェックサムを比較することで、このデータがコード以外に変更されていないことを確認できます。



 public class SafePlayerPrefs { private string key; private List<string> properties = new List<string>(); public SafePlayerPrefs (string key, params string [] properties) { this.key = key; foreach (string property in properties) this.properties.Add(property); Save(); } //    private string GenerateChecksum () { string hash = ""; foreach (string property in properties) { hash += property + ":"; if (PlayerPrefs.HasKey(property)) hash += PlayerPrefs.GetString(property); } return Md5Sum(hash + key); } //    public void Save() { string checksum = GenerateChecksum(); PlayerPrefs.SetString("CHECKSUM" + key, checksum); PlayerPrefs.Save(); } // ,    public bool HasBeenEdited () { if (! PlayerPrefs.HasKey("CHECKSUM" + key)) return true; string checksumSaved = PlayerPrefs.GetString("CHECKSUM" + key); string checksumReal = GenerateChecksum(); return checksumSaved.Equals(checksumReal); } // ... }
      
      







上記のクラスは、文字列変数で機能する簡単な実装例です。 初期化するには、秘密キーとPlayerPrefsキーのリストを渡す必要があります。これらの値は保護する必要があります。



 SafePlayerPrefs spp = new SafePlayerPrefs("MyGame", "PlayerName", "Score");
      
      







その後、次のように使用できます。



 //    PlayerPrefs   PlayerPrefs.SetString("PlayerName", name); PlayerPrefs.SetString("Score", score); spp.Save(); // ,    if (spp.HasBeenEdited()) Debug.Log("Error!");
      
      







初期化中にキーがクラスに渡されたすべてのパラメーターの値に基づいて、 Save



メソッドが呼び出されるたびに、チェックサムが計算されて保存されます。 HasBeenEdited



メソッドを使用して、保護されたパラメーターが知らないうちに変更されたかどうかを確認できます。



ソースコードをハックする



Windowsビルドの場合、Unityはすべてのゲームスクリプトのソースコードをコンパイルし、 Managed



ディレクトリに保存します。 次のライブラリに興味があります: Assembly-CSharp.dll



Assembly-CSharp-firstpass.dll



およびAssembly-UnityScript.dll











.NETライブラリのマネージコードを逆コンパイルして表示するには(犠牲者は)便利であると同時に、無料のユーティリティIlSpydotPeekがあります。







与えられたアプローチは、私たちの目的にとって特に効果的です。Unityは、実質的に構造を変更することなく、ゲームスクリプトのソースコードを非常に控えめに最適化し、変数の名前も隠しません。 これにより、逆コンパイルされた素材の読み取りと理解が容易になります。



ソースコードを保護する



Unityはコードの安全性を気にかけないので、自分でやるつもりです。 幸いなことに、知的作業の成果を自動的に暗号化する準備ができているユーティリティ、 Unity 3D Obfuscatorがあります。







また、プログラムはその任務を完全に処理しますが、それでもネイティブライブラリの外部からアドレス指定された多くのクラスは、接続が中断するリスクがなければ暗号化できません-注意してください!



ゲームメモリのハッキング



Cheat Engineは、ゲームをハッキングするための有名なプログラムです。 実行中のゲームのプロセスに属するRAMの領域を見つけ、それを任意に変更できます。







このプログラムは、ゲーム開発者が変数値を保護することはめったにないという事実を利用しています。 次の例を考えてみましょう。ゲームには100ラウンドあります。 Cheat Engineを使用すると、値「100」を保存するメモリのセクションを検索できます。 それからショットを行います-弾薬の在庫は99ユニットです。 メモリを再度スキャンしますが、今度は値「99」を探しています。 何度か繰り返した後、ゲーム内のほとんどの変数の位置を簡単に見つけて、それらを任意に変更できます。



ゲームのメモリを保護する



Cheat Engineは、変数値が保護されずに元の形式で保存されるため、非常に効果的です。 「詐欺師」の生活を真剣に複雑にすることは非常に簡単です。変数を扱う方法を少し変更するだけです。 標準のfloat



安全な代替として役立つSafeFloat



構造体を作成します。



 public struct SafeFloat { private float offset; private float value; public SafeFloat (float value = 0) { offset = Random.Range(-1000, +1000); this.value = value + offset; } public float GetValue () { return value - offset; } public void Dispose () { offset = 0; value = 0; } public override string ToString() { return GetValue().ToString(); } public static SafeFloat operator +(SafeFloat f1, SafeFloat f2) { return new SafeFloat(f1.GetValue() + f2.GetValue()); } // ...     }
      
      







次のように新しい構造を使用できます。



 SafeFloat health = new SafeFloat(100); SafeFloat damage = new SafeFloat(5); health -= damage; SafeFloat nextLevel = health + new SafeFloat(10); Debug.Log(health);
      
      







画面に変数の値を表示する場合、ハッカーはそれらをインターセプトして変更できますが、これはメモリに保存され、ゲームロジックで使用される実際の値には影響しません。



おわりに



残念ながら、ハッキングからゲームを保護する方法は多くありません。 ユーザーデバイスにインストールすると、実際にすべてのテクスチャ、モデル、およびソースコードが表示されます。 誰かがゲームを逆コンパイルしてリソースを盗もうとするなら、それは時間の問題です。



それにもかかわらず、攻撃者の生活を深刻に複雑にする効果的な方法があります。 これは、パニックし、すべてのソースコードを暗号化し、各変数を保護する必要があるという意味ではありませんが、少なくともプロジェクトのリソースが本当に重要であり、それらを保護するために何ができるかを考えてください。



追加情報






All Articles