Как правильно использовать обфускатор в среде Unity3D?



Обфускация (от лат. obfuscare, «затенять, затемнять») — это процесс запутывания кода программы, то есть приведение исходного текста или исполняемого кода к виду, сохраняющему функциональность программы, но затрудняющему анализ, понимание алгоритмов работы и модификацию при декомпиляции.


Обфускация включает в себя как правило переименование имен классов, методов, свойств и полей в набор бессмысленных имен, что затрудняет изучение логики работы программы.


 

Но для сохранения функциональности кода - не все имена можно переименовывать, особенно это касается среды Unity, для этого в обфускаторе DevXObfuscator автомотически создаются правила-исключения для некоторых имен:


 

  1. Из процесса переименования исключаются имена классов унаследованных от unity MonoBehaviour и ScriptableObject

    Причина: В Unity классы унаследованные от MonoBehaviour или ScriptableObject используются в сцене для объектов GameObject, а связка осуществляется по имени класса, таким образом изменив имя класса - Unity не сможет связать ссылку в GameObject с реальным классом в сборке (dll).

    Пример:
    // for obfuscator - Dont rename ‘GameObjectScript’
    public class GameObjectScript : MonoBehaviour
    {
    }

  2. Из процесса переименования исключаются имена следующих функций (для классов унаследованных от MonoBehaviour)

    Create, Update, LateUpdate, FixedUpdate, Awake, Start, Reset, OnMouseEnter, OnMouseOver, OnMouseExit, OnMouseDown, OnMouseUp, OnMouseDrag, OnTriggerEnter, OnTriggerExit, OnTriggerStay, OnCollisionEnter, OnCollisionExit, OnCollisionStay, OnControllerColliderHit, OnJointBreak, OnParticleCollision, OnBecameVisible, OnBecameInvisible, OnLevelWasLoaded, OnEnable, OnDisable, OnPreCull, OnPreRender, OnPostRender, OnRenderObject, OnWillRenderObject, OnGUI, OnRenderImage, OnDrawGizmosSelected, OnDrawGizmos, OnApplicationPause, OnApplicationQuit и некоторые другие..

    Причина: Unity в процессе работы вызывает определенные методы класса, имена которых зарезервированы для определенных действий, например Update вызывается при обновлении каждой сцены и если мы его переименуем, то Unity не найдет по имени данный метод и функция не будет вызвана.  

    Пример:
      // for obfuscator - Dont rename ‘GameObjectScript’
    public class GameObjectScript1 : MonoBehaviour
    {
        // for obfuscator - Dont rename
        // Use this for initialization
        void Start ()
        {  
        }

        // for obfuscator - Dont rename
        // Update is called once per frame
        void Update ()
        {
        }
    }


  3. Из процесса переименования исключаются имена публичных “public”  классов, методов, свойств, полей.


    Причина: В сцене игры для объектов GameObject могут использоваться поля и методы классов, но связка осуществляется по имени, поэтому например если переименовать поле в классе то Unity не найдет его, что приведет к ошибке.  

    Пример:
    // for obfuscator - Dont rename ‘GameObjectScript’
    public class GameObjectScript : MonoBehaviour
    {
       // for obfuscator - Dont rename
       public string field_for_scene;

       // for obfuscator - Dont rename
       public bool flag_for_scene;


       // for obfuscator - allow rename
       internal string name_for_only_scripts_access;
       // for obfuscator - allow rename
       private bool flag_for_only_class_access;

       // for obfuscator - allow rename
       protected int count_for_only_class_access;
    }


  4. Из процесса переименования исключаются имена сериализуемых  классов их  свойств и полей.


    Причина: В процессе сериализации используются имена классов их полей и свойств, поэтому если переименовать класс, то может возникнуть ошибка сериализации.  

    Пример:
      // for obfuscator - Dont rename class and contents
       [System.Serializable]
       class TestObject
       {
           string name;
           int count;
       }


Рекомендации:


Для получения максимального эффекта от процесса обфускации рекомендуется следовать следующим правилам:

  1. Используйте модификатор “public” только там где это действительно необходимо, в остальных случаях замените на:

    1. internal” - Доступ к типу или члену возможен из любого кода в той же сборке, но не из другой сборки.

    2. protected” - Доступ к типу или члену возможен только из кода в том же классе или структуре либо в классе, производном от этого класса.

    3. private” - Доступ к типу или члену возможен только из кода в том же классе или структуре.

  2. Игровую логику лучше выводить из классов унаследованных от MonoBehaviour в отдельные internal классы без использования модификатора public и флага сериализации, таким образом будет намного сложнее связать логику работы объектов сцены.

  3. Логику проверки лицензионных ключей и других механизмов проверки безопасности - лучше разделить на множество отдельных частей и разнести эти части по коду. Это усложнит анализ логики. Также рекомендуется добавить в саму логику дополнительный код, который фактически не влияет на результат но усложняет анализ из за избыточного количества инструкций.

  4. Для защиты строковых данных - доступ к которым нежелателен (особенно тех что используются для проверки ключей) рекомендуется использовать соответствующий флаг обфускатора (шифровать строки)

  5. Для защиты от просмотра и модификации данных сохраненных с использованием PlayerPrefs рекомендуется использовать соответствующий флаг обфускатора (Защитить данные используемые с помощью PlayerPrefs), что обеспечит как сокрытие реального имени так и защиту самих данных

  6. Для защиты временных переменных от получения и модификации через память (отладчики) рекомендуется использовать классы защищенного хранения переменных (входят в комплект поставки обфускатора DevXObfuscatorPro)   

    1. ProtectedFloat - для хранения в памяти float переменной в зашифрованном виде

    2. ProtectedInt - для хранения в памяти int переменной в зашифрованном виде

    3. ProtectedString - для хранения в памяти строковой переменной в зашифрованном виде

  7. Если в проекте используются ресурсы (/Resources/) содержимое которых вы хотели бы защитить от экспорта, то рекомендуется использовать механизм шифрования ресурсов обфускатора

    1. Шифрование текстовых данных
      для загрузки зашифрованного текста используется функция
      string DevXUnity.LoadEncryptedResourceText(string resource_name, string key)

    2. Шифрование изображений
      для загрузки зашифрованного изображения используется функция
      Texture2D DevXUnity.LoadEncryptedResourceTexure(string resource_name, string key, int width, int height, TextureFormat format, bool mipmap, bool linear)

    3. Шифрование других типов доступно в бинарном виде
      для загрузки используется функция
      byte[] DevXUnity.LoadEncryptedResourceBinary(string resource_name, string key)




Также можно получить консультацию и ответы на вопросы направив запрос на почту unity3dobfuscator@gmail.com