Metody zaciemniania Unity i ochrona przed hakerami

W końcu wydałeś grę, nad którą tak ciężko pracowałeś, i może nawet dodałeś tabelę wyników, aby dodać wyzwanie do gry. Ale mijają dni i zauważasz, że niektórzy gracze pojawiają się na szczycie tabeli wyników z nierealistycznie wysokimi wynikami. Pierwszą myślą jest oczywiście to, że hakują, ale jak oni to robią?

Odpowiedź jest taka, że ​​najprawdopodobniej używają programu do wstrzykiwania własnych wartości do pamięci, a najpopularniejszym z nich jest Cheat Engine. W grach dla jednego gracza hakowanie nie ma tak dużego znaczenia, ale staje się problemem, gdy jest to gra multiplayer, w którą zaangażowani są inni gracze.

W tym poście pokażę, jak zabezpieczyć grę przed takimi atakami, co z kolei poprawi komfort gry dla graczy, którzy nie hackują.

UWAGA: W tym artykule jedynie pokrótce omówiono najczęstsze ataki i podstawową ochronę przed nimi. Jeśli potrzebujesz bardziej gotowego rozwiązania, sprawdź ten pakiet Asset Store.

Jeśli chodzi o hackowanie za pomocą Cheat Engine, istnieją 2 najczęstsze ataki: Speed ​​Hacking i Value Scanning.

Szybki hack

Ponieważ jest najłatwiejszy do wykonania (wymaga tylko 2 kliknięć), Speed ​​Hack jest zwykle pierwszym wyborem dla początkujących użytkowników.

Speed ​​hack działa poprzez przyspieszenie szybkości aktualizacji gry, dzięki czemu wszystko staje się szybsze, dając w ten sposób hakerom przewagę nad graczami grającymi z normalną prędkością.

Na szczęście istnieje sposób na wykrycie tego hacka w Unity. Sprawdź poniższy skrypt:

UWAGA: Na dzień dzisiejszy ta metoda już nie działa, dlatego wykrycie speed hacka w grach dla jednego gracza stało się znacznie trudniejsze. Jednak gry wieloosobowe nadal są w stanie to zrobić, polegając na kontrolach po stronie serwera, aby wykryć wszelkie niezgodności w czasie gracz-serwer i podjąć odpowiednie działania (wykopanie/banowanie gracza itp.).

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.");
    }
}

Powyższy skrypt porównuje czas w grze z czasem komputera (systemowym). Zwykle oba czasy są aktualizowane z tą samą szybkością (zakładając, że Time.timeScale jest ustawione na 1), ale gdy aktywowany jest SpeedHack, przyspiesza to częstotliwość aktualizacji w grze, powodując akumulację czasu w grze szybciej.

Gdy różnica między obydwoma czasami stanie się zbyt duża (w tym przypadku 7 sekund, ale możesz wybrać dowolną wartość, tylko upewnij się, że nie jest za mała, aby uniknąć fałszywych alarmów) skrypt wywołuje metodę SpeedhackDetected(), która sygnalizuje obecność SpeedHack.

Aby użyć skryptu, upewnij się, że jest on dołączony do dowolnego obiektu na scenie.

Skanowanie wartości

Skanowanie wartości to proces znajdowania odpowiednich wartości w pamięci przydzielonej grze i nadpisywania ich innymi wartościami. Najczęściej używany do zwiększenia zdrowia gracza, amunicji do broni lub dowolnej wartości, która dałaby hakerowi nieuczciwą przewagę w grze.

Technicznie rzecz biorąc, każdą wartość w grze można nadpisać/zmienić, ale czy to oznacza, że ​​wszystkie muszą być chronione? Niekoniecznie. Ogólnie rzecz biorąc, początkujący hakerzy celują tylko w wartości wyświetlane na ekranie i wiadomo, do czego służą (na przykład zdrowie gracza, amunicja itp.). Dlatego przez większość czasu należy chronić tylko wartości "exposed".

Zrzut ekranu z gry Unity FPS

Przykładowo na powyższym zrzucie ekranu każda wartość na ekranie jest potencjalnym celem włamania.

Pytanie brzmi zatem, jak chronić ważne wartości przed atakiem polegającym na skanowaniu wartości? Odpowiedź brzmi Zaciemnianie.

Zaciemnianie to działanie polegające na uczynieniu czegoś niejasnym, niejasnym lub niezrozumiałym.

Istnieje wiele sposobów zaciemniania zmiennych, ale ja użyję metody, którą nazywam Randomizer. Na początku generowana jest wartość losowa, następnie od niej odejmowana jest wartość rzeczywista (następnie ją ukrywana), następnie w razie potrzeby od wygenerowanej wartości losowej odejmowana jest wartość ukryta, z tą różnicą, że jest to liczba pierwotna. Kluczem jest, aby wartość wyświetlana na ekranie miała zupełnie inną wartość niż zmienna, co podczas skanowania prowadzi hakerów w całkowicie błędny sposób.

  • Utwórz nowy skrypt, nadaj mu nazwę 'SC_Obf' i wklej w nim poniższy kod:

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;
    }
}

Powyższy skrypt zostanie użyty do wygenerowania liczby losowej i 2 prostych metod zaciemniania i usuwania zaciemnień wartości.

  • Przejdźmy teraz do zwykłego przykładu skryptu bez zaciemniania:
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");
    }
}

Powyższy skrypt zawiera 2 proste zmienne: zdrowie (float) i amunicję (int). Obie zmienne są wyświetlane na ekranie:

Ten sposób działania jest prosty i wygodny pod względem konserwacji, ale hakerzy będą mogli z łatwością zeskanować wartości i nadpisać je za pomocą Cheat Engine lub podobnego oprogramowania.

  • Oto ten sam skrypt, ale wykorzystujący metody zaciemniania z '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");
    }
}

Zamiast bezpośrednio inicjować zmienne zdrowia i amunicji, inicjujemy je na początku w void Awake() (Pamiętaj, aby wywołać SC_Obf.Initialize() przed przypisaniem wartości za pomocą SC_Obf.Zaciemnienie(wartość)).

Następnie, wyświetlając wartości, na bieżąco je rozjaśniamy, wywołując SC_Obf.Deobfuscate(value), wyświetlając w ten sposób rzeczywiste wartości.

Haker próbowałby wyszukać 100 i 30, ale nie byłby w stanie ich znaleźć, ponieważ rzeczywiste wartości są zupełnie inne.

Aby manipulować zaciemnionymi wartościami (np. odejmując zdrowie), najpierw usuwamy zaciemnienie wartości, następnie odejmujemy potrzebną wartość, a następnie ponownie zaciemniamy wynik końcowy.

Aby uzyskać bardziej zaawansowane rozwiązanie, możesz sprawdzić ten pakiet Asset Store.

Sugerowane artykuły
Wprowadzenie do języka skryptowego Unity C#
Metody na początku środowiska wykonawczego, które inicjują wartości w jedności
Jak odtwarzać pliki wideo w Unity
Implementowanie niestandardowej szybkości aktualizacji w Unity
Jak zmienić rozdzielczość ekranu w grze Unity
Rotacja w miejscu w jedności
Tworzenie prostego systemu pocisków 2D w Unity