Методы обфускации Unity и защита от взлома

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

Ответ в том, что они, скорее всего, используют программу для ввода собственных значений в память, причем самой популярной из таких программ является Cheat Engine. В однопользовательских играх взлом не имеет большого значения, но он становится проблемой, когда это многопользовательская игра, в которой участвуют другие игроки.

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

ПРИМЕЧАНИЕ. В этой статье лишь кратко описаны наиболее распространенные атаки и базовая защита от них. Если вам нужно более нестандартное решение, ознакомьтесь с этим Asset Store Пакетом.

Когда дело доходит до взлома с помощью Cheat Engine, наиболее распространенными являются две атаки: Speed ​​Hacking и Value Scanning.

Спидхак

Будучи самым простым в исполнении (требуется всего 2 клика), Speed ​​Hack обычно является лучшим выбором для начинающих пользователей.

Speed ​​hack работает за счет увеличения скорости обновления игры, делая все быстрее, что дает хакерам преимущество перед игроками, которые играют на нормальной скорости.

К счастью, есть способ обнаружить этот взлом в Unity. Проверьте скрипт ниже:

ПРИМЕЧАНИЕ. На сегодняшний день этот метод больше не работает, поэтому обнаружить взлом скорости в одиночных играх стало гораздо сложнее. Однако многопользовательские игры по-прежнему могут это делать, полагаясь на проверки на стороне сервера, чтобы обнаружить любое несоответствие во времени игрока и сервера и предпринять соответствующие действия (кинуть/забанить игрока и т. д.).

SC_SpeedhackDetector.cs

using UnityEngine;
using System;

public class SC_SpeedhackDetector : MonoBehaviour
{
    //Speed hack protection
    public int timeDiff = 0; 
    int previousTime = 0;
    int realTime = 0;
    float gameTime = 0;
    bool detected = false;

    // Use this for initialization
    void Start()
    {
        previousTime = DateTime.Now.Second;
        gameTime = 1;
    }

    // Update is called once per frame 
    void FixedUpdate()
    {
        if (previousTime != DateTime.Now.Second)
        {
            realTime++;
            previousTime = DateTime.Now.Second;

            timeDiff = (int)gameTime - realTime;
            if (timeDiff > 7)
            {
                if (!detected)
                {
                    detected = true;
                    SpeedhackDetected();
                }
            }
            else
            {
                detected = false;
            }
        }
        gameTime += Time.deltaTime;
    }

    void SpeedhackDetected()
    {
        //Speedhack was detected, do something here (kick player from the game etc.)
        print("Speedhack detected.");
    }
}

Приведенный выше скрипт сравнивает внутриигровое время с компьютерным (системным) временем. Обычно оба времени обновляются с одинаковой скоростью (при условии, что Time.timeScale установлено в 1), но когда SpeedHack активирован, он ускоряет частоту обновления в игре, заставляя игровое время накапливаться. Быстрее.

Как только разница между обоими значениями времени становится слишком большой (в данном случае 7 секунд, но вы можете выбрать любое значение, только убедитесь, что оно не слишком маленькое, чтобы избежать ложных срабатываний), скрипт вызывает метод SpeedhackDetected(), который сигнализирует о наличии SpeedHack.

Чтобы использовать скрипт, убедитесь, что он прикреплен к любому объекту на сцене.

Сканирование значений

Сканирование значений — это процесс поиска соответствующих значений в выделенной памяти игры и перезаписи их другими значениями. Чаще всего используется для увеличения здоровья игрока, боезапаса оружия или любой другой ценности, которая могла бы дать хакеру несправедливое преимущество в игре.

С технической точки зрения, любое значение в игре можно перезаписать/изменить, но значит ли это, что все их необходимо защищать? Не обязательно. Как правило, начинающие хакеры ориентируются только на значения, которые отображаются на экране и знают, для чего они используются (например, здоровье игрока, боеприпасы и т. д.). Поэтому в большинстве случаев необходимо защищать только значения "exposed".

Скриншот игры Unity FPS

Например, на скриншоте выше каждое значение на экране является потенциальной целью для взлома.

Итак, вопрос в том, как защитить важные ценности от атаки сканирования значений? Ответ: Запутывание.

Запутывание — это действие, делающее что-то неясным, неясным или непонятным.

Есть много способов запутать переменную, но я буду использовать метод, который называю Randomizer. В начале генерируется случайное значение, затем из него вычитается реальное значение (впоследствии оно скрывается), затем, при необходимости, скрытое значение вычитается из сгенерированного случайного значения, при этом разница составляет исходное число. Ключевым моментом является то, чтобы значение, отображаемое на экране, полностью отличалось от значения переменной, что приводит хакеров совершенно неверным путем при сканировании.

  • Создайте новый скрипт, назовите его 'SC_Obf' и вставьте в него приведенный ниже код:

SC_Obf.cs

using UnityEngine;

public class SC_Obf : MonoBehaviour
{
    static float random = -1;

    public static void Initialize()
    {
        if(random == -1)
        {
            random = Random.Range(10000, 99999);
        }
    }

    public static float Obfuscate(float originalValue)
    {
        return random - originalValue;
    }

    public static float Deobfuscate(float obfuscatedValue)
    {
        return random - obfuscatedValue;
    }
}

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

  • Теперь перейдем к обычному примеру скрипта без каких-либо обфускаций:
using UnityEngine;

public class SC_Test : MonoBehaviour
{
    public float health = 100;
    public int ammo = 30;

    public void Damage(float points)
    {
        health -= points;
    }

    void OnGUI()
    {
        GUI.Label(new Rect(5, 5, 150, 25), health + " HP");
        GUI.Label(new Rect(5, 30, 150, 25), ammo + " Ammo");
    }
}

Приведенный выше скрипт содержит две простые переменные: здоровье (float) и боеприпасы (int). Обе переменные отображаются на экране:

Этот способ прост и удобен с точки зрения обслуживания, но хакеры легко смогут сканировать значения и перезаписывать их с помощью Cheat Engine или аналогичного программного обеспечения.

  • Вот тот же скрипт, но с использованием методов обфускации из 'SC_Obf.cs':
using UnityEngine;

public class SC_Test : MonoBehaviour
{
    public float health;
    public int ammo;

    void Awake()
    {
        SC_Obf.Initialize();
        health = SC_Obf.Obfuscate(100);
        ammo = (int)SC_Obf.Obfuscate(30);
    }

    public void Damage(float points)
    {
        health = SC_Obf.Obfuscate(SC_Obf.Deobfuscate(health) - points);
    }

    void OnGUI()
    {
        GUI.Label(new Rect(5, 5, 150, 25), SC_Obf.Deobfuscate(health) + " HP");
        GUI.Label(new Rect(5, 30, 150, 25), SC_Obf.Deobfuscate(ammo) + " Ammo");
    }
}

Вместо прямой инициализации переменных здоровья и боеприпасов мы инициализируем их в самом начале с помощью void Awake() (обязательно вызовите SC_Obf.Initialize() перед присвоением значений с помощью SC_Obf.Obfuscate(значение)).

Затем при отображении значений мы деобфусцируем их на лету, вызывая SC_Obf.Deobfuscate(value), тем самым отображая реальные значения.

Хакер попытается найти 100 и 30, но не сможет их найти, поскольку реальные значения совершенно разные.

Чтобы манипулировать запутанными значениями (например, вычитая здоровье), мы сначала деобфусцируем значение, затем вычитаем необходимое значение, а затем обратно маскируем окончательный результат.

Для более продвинутого решения ознакомьтесь с этим пакетом Asset Store.

Рекомендуемые статьи
Введение в язык сценариев Unity C#
Самые полезные фрагменты кода для разработчиков Unity
Создание простой 2D-системы маркеров в Unity
Методы в начале выполнения, инициализирующие значения в Unity
Реализация ввода с клавиатуры и мыши в Unity
Руководство по MonoBehavior в Unity
Создание GrabPack в Unity, вдохновленное Poppy Playtime