Métodos de ofuscación de Unity y protección anti-piratería

Finalmente lanzaste el juego en el que has estado trabajando tan duro y tal vez incluso agregaste una clasificación para agregar desafío al juego. Pero pasan los días y notas que algunos jugadores aparecen en la cima del marcador con puntuaciones irrealmente altas. Lo primero que piensas es, por supuesto, que están pirateando, pero ¿cómo lo hacen?

La respuesta es que lo más probable es que estén usando un programa para inyectar sus propios valores en la memoria, siendo el más popular de estos programas Cheat Engine. Ahora, en los juegos para un solo jugador, la piratería realmente no importa mucho, pero se convierte en un problema cuando se trata de un juego multijugador en el que participan otros jugadores.

En esta publicación, mostraré cómo hacer que tu juego sea más seguro contra este tipo de ataques, lo que a su vez mejorará la experiencia para los jugadores que no piratean.

NOTA: Este artículo sólo cubre brevemente los ataques más comunes y la protección básica contra ellos. Si necesita más soluciones listas para usar, no dude en consultar este paquete Asset Store.

Cuando se trata de hackear con Cheat Engine, existen 2 ataques más comunes: Speed ​​Hacking y Value Scanning.

Truco velocidad

Al ser el más fácil de ejecutar (solo requiere 2 clics), Speed ​​Hack suele ser la primera opción para los usuarios novatos.

El Speed ​​Hack funciona acelerando la velocidad de actualización del juego, haciendo que todo sea más rápido, dando así a los hackers una ventaja sobre los jugadores que juegan a la velocidad normal.

Afortunadamente, existe una manera de detectar este hack en Unity. Consulte el guión a continuación:

NOTA: A partir de hoy, este método ya no funciona, por lo tanto, detectar el hackeo de velocidad se ha vuelto mucho más difícil en los juegos para un solo jugador. Sin embargo, los juegos multijugador aún pueden hacerlo confiando en comprobaciones del lado del servidor para detectar cualquier discrepancia en el tiempo entre el jugador y el servidor y tomar la acción adecuada (expulsar/prohibir al jugador, 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.");
    }
}

El script anterior compara el tiempo del juego con el tiempo de una computadora (sistema). Normalmente, ambos tiempos se actualizan al mismo ritmo (asumiendo que Time.timeScale está configurado en 1), pero cuando se activa SpeedHack, acelera la frecuencia de actualización en el juego, lo que hace que -El tiempo de juego se acumula más rápido.

Una vez que la diferencia entre ambos tiempos se vuelve demasiado grande (en este caso 7 segundos, pero puedes elegir cualquier valor, solo asegúrate de que no sea demasiado pequeño para evitar falsos positivos), el script llama al método SpeedhackDetected() que señala la presencia de SpeedHack.

Para utilizar el script, asegúrese de que esté adjunto a cualquier objeto de la escena.

Escaneo de valores

El escaneo de valores es un proceso de encontrar valores relevantes en la memoria asignada del juego y sobrescribirlos con valores diferentes. Se utiliza más comúnmente para aumentar la salud del jugador, la munición de armas o cualquier valor que le dé a un hacker una ventaja injusta en el juego.

Técnicamente hablando, todos los valores del juego se pueden sobrescribir o cambiar, pero ¿significa eso que es necesario protegerlos todos? No necesariamente. Generalmente, los piratas informáticos novatos solo apuntan a los valores que se muestran en la pantalla y saben para qué se utilizan (por ejemplo, salud del jugador, munición, etc.). Por lo tanto, la mayoría de las veces solo es necesario proteger los valores "exposed".

Captura de pantalla del juego Unity FPS

Por ejemplo, en la captura de pantalla anterior, cada valor en la pantalla es un objetivo potencial para la piratería.

Entonces la pregunta es, ¿cómo proteger los valores importantes contra un ataque de escaneo de valores? La respuesta es Ofuscación.

Ofuscación es la acción de hacer que algo sea oscuro, poco claro o ininteligible.

Hay muchas formas de ofuscar una variable, pero usaré un método al que llamo Randomizer. El valor aleatorio se genera al principio, luego se le resta el valor real (posteriormente lo oculta), luego, cuando es necesario, el valor oculto se resta de un valor aleatorio generado, siendo la diferencia el número original. La clave es que un valor que se muestra en la pantalla tenga un valor completamente diferente de la variable, lo que lleva a los piratas informáticos por un camino completamente equivocado al escanear.

  • Cree un nuevo script, llámelo 'SC_Obf' y pegue el siguiente código dentro de él:

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

El script anterior se utilizará para generar un número aleatorio y 2 métodos simples para ofuscar y desofuscar los valores.

  • Ahora pasemos a un ejemplo normal de un script sin ninguna confusión:
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");
    }
}

El script anterior contiene 2 variables simples: salud (flotante) y munición (int). Ambas variables se muestran en la pantalla:

Esta forma de hacer las cosas es simple y conveniente en términos de mantenimiento, pero los piratas informáticos podrán escanear fácilmente los valores y sobrescribirlos usando Cheat Engine o software similar.

  • Aquí está el mismo script, pero usando métodos de ofuscación de '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");
    }
}

En lugar de inicializar las variables de salud y munición directamente, las inicializamos al principio en void Awake() (Asegúrate de llamar a SC_Obf.Initialize() antes de asignar los valores usando SC_Obf.Obfuscate(valor)).

Luego, al mostrar los valores, los desofuscamos sobre la marcha llamando a SC_Obf.Deobfuscate(value), mostrando así los valores reales.

El hacker intentaría buscar 100 y 30 pero no podría encontrarlos porque los valores reales son completamente diferentes.

Para manipular los valores ofuscados (por ejemplo, restar salud), primero desofuscamos el valor, luego restamos el valor necesario y luego ofuscamos el resultado final.

Para obtener una solución más avanzada, no dudes en consultar este paquete Asset Store.