Méthodes d’obfuscation Unity et protection anti-piratage

Vous avez enfin sorti le jeu sur lequel vous avez travaillé si dur, et vous avez peut-être même ajouté un classement pour ajouter du défi au jeu. Mais les jours passent et vous remarquez que certains joueurs apparaissent en haut du tableau d'affichage avec des scores irréalistes. Votre première pensée est bien sûr qu’ils piratent, mais comment font-ils ?

La réponse est qu'ils utilisent très probablement un programme pour injecter leurs propres valeurs dans la mémoire, le plus populaire de ces programmes étant Cheat Engine. Désormais, dans les jeux solo, le piratage n'a pas vraiment d'importance, mais cela devient un problème lorsqu'il s'agit d'un jeu multijoueur dans lequel les autres joueurs sont impliqués.

Dans cet article, je vais montrer comment rendre votre jeu plus sécurisé contre de telles attaques, ce qui améliorera l'expérience des joueurs non-pirateurs.

REMARQUE: Cet article ne couvre que brièvement les attaques les plus courantes et la protection de base contre celles-ci. Si vous avez besoin d'une solution plus prête à l'emploi, n'hésitez pas à consulter ce Asset Store Package.

Lorsqu'il s'agit de piratage avec Cheat Engine, il existe 2 attaques les plus courantes: le Speed ​​Hacking et le Value Scanning.

Piratage rapide

Étant le plus simple à exécuter (ne nécessite que 2 clics), le Speed ​​Hack est généralement le premier choix des utilisateurs novices.

Speed ​​Hack fonctionne en accélérant le taux de mise à jour du jeu, rendant tout plus rapide, donnant ainsi aux pirates un avantage sur les joueurs qui jouent à la vitesse normale.

Heureusement, il existe un moyen de détecter ce hack dans Unity. Vérifiez le script ci-dessous:

REMARQUE: à partir d'aujourd'hui, cette méthode ne fonctionne plus. Par conséquent, la détection du speed hack est devenue beaucoup plus difficile dans les jeux solo. Les jeux multijoueurs, cependant, sont toujours capables de le faire en s'appuyant sur des contrôles côté serveur pour détecter toute inadéquation dans le temps joueur-serveur et prendre les mesures appropriées (expulser/bannir le joueur, etc.).

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

Le script ci-dessus compare l'heure du jeu avec l'heure d'un ordinateur (système). Normalement, les deux heures sont mises à jour au même rythme (en supposant que Time.timeScale est défini sur 1), mais lorsque le SpeedHack est activé, il accélère la fréquence de mise à jour dans le jeu, ce qui rend le -le temps de jeu s'accumule plus rapidement.

Une fois que la différence entre les deux temps devient trop importante (dans ce cas 7 secondes, mais vous pouvez choisir n'importe quelle valeur, assurez-vous simplement qu'elle n'est pas trop petite pour éviter les faux positifs) le script appelle la méthode SpeedhackDetected() qui signale la présence de SpeedHack.

Pour utiliser le script, assurez-vous qu'il est attaché à n'importe quel objet de la scène.

Analyse des valeurs

L'analyse des valeurs est un processus consistant à trouver des valeurs pertinentes dans la mémoire allouée au jeu et à les écraser par des valeurs différentes. Le plus souvent utilisé pour augmenter la santé du joueur, les munitions d'armes ou toute valeur qui donnerait à un pirate informatique un avantage injuste dans le jeu.

Techniquement parlant, chaque valeur du jeu peut être écrasée/modifiée, mais cela signifie-t-il qu'elles doivent toutes être protégées ? Pas nécessairement. Généralement, les pirates novices ciblent uniquement les valeurs affichées à l'écran et savent à quoi elles servent (par exemple la santé du joueur, les munitions, etc.). Ainsi, la plupart du temps, seules les valeurs "exposed" doivent être protégées.

Capture d'écran du jeu FPS Unity

Par exemple, sur la capture d'écran ci-dessus, chaque valeur à l'écran est une cible potentielle de piratage.

La question est donc de savoir comment protéger les valeurs importantes contre une attaque Value Scanning ? La réponse est Obfuscation.

L'obscurcissement est l'action de rendre quelque chose d'obscur, peu clair ou inintelligible.

Il existe de nombreuses façons de masquer une variable, mais j'utiliserai une méthode que j'appelle Randomizer. La valeur aléatoire est générée au début, puis la valeur réelle en est soustraite (en la masquant ensuite), puis si nécessaire, la valeur cachée est soustraite d'une valeur aléatoire générée, la différence étant le nombre d'origine. La clé est d'avoir une valeur qui s'affiche à l'écran pour avoir une valeur complètement différente de la variable, ce qui conduit les pirates dans une direction complètement fausse lors de l'analyse.

  • Créez un nouveau script, appelez-le 'SC_Obf' et collez-y le code ci-dessous:

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

Le script ci-dessus sera utilisé pour générer un nombre aléatoire et 2 méthodes simples pour obscurcir et désobscurcir les valeurs.

  • Passons maintenant à un exemple classique de script sans aucune obscurcissement:
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");
    }
}

Le script ci-dessus contient 2 variables simples: la santé (float) et les munitions (int). Les deux variables sont affichées à l'écran:

Cette façon de faire est simple et pratique en termes de maintenance, mais les pirates pourront facilement scanner les valeurs et les écraser à l'aide de Cheat Engine ou d'un logiciel similaire.

  • Voici le même script, mais en utilisant les méthodes d'obscurcissement du '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");
    }
}

Au lieu d'initialiser directement les variables de santé et de munitions, nous les initialisons au début dans void Awake() (Assurez-vous d'appeler SC_Obf.Initialize() avant d'attribuer les valeurs à l'aide de SC_Obf.Obfuscate(value)).

Ensuite, lors de l'affichage des valeurs, nous les désobscurcissons à la volée en appelant SC_Obf.Deobfuscate(value) affichant ainsi les valeurs réelles.

Le pirate essaierait de rechercher 100 et 30 mais ne parviendrait pas à les trouver car les valeurs réelles sont complètement différentes.

Pour manipuler les valeurs obscurcies (par exemple en soustrayant la santé), nous désobscurcissons d'abord la valeur, puis soustrayons la valeur nécessaire, puis obscurcissons le résultat final.

Pour une solution plus avancée, n'hésitez pas à consulter ce Asset Store Package.

Articles suggérés
Introduction au langage de script Unity C#
Méthodes au début du runtime qui initialisent les valeurs dans Unity
Comment lire des fichiers vidéo dans Unity
Comment changer la résolution de l'écran dans le jeu Unity
Rotation sur place dans Unity
Création d'un système de puces 2D simple dans Unity
Un guide sur le chargement de scènes dans Unity