He estado usando Unity para crear un juego en 2D que estará completamente fuera de línea (que es el problema), el juego necesita que ingreses ciertas cadenas en ciertos niveles y Unity compila en DLL, que pueden ser fácilmente revertidas, así que ¿Hay alguna manera de proteger esas cadenas (el juego está fuera de línea, así que no puedo recuperarlo de otra fuente)?
El juego depende en gran medida de esas cadenas, y sí, estoy al tanto de la ofuscación, pero quiero algo más robusto. Y sé que la salida fácil sería hacer todo en línea desde una fuente de datos, pero me preguntaba si es posible.
unity
c#
anti-cheat
TheBinaryGuy
fuente
fuente
strings
programa.Respuestas:
No almacene esas cadenas, almacene el hash (criptográfico) de ellas.
Una función de hash (criptográfica), como el cifrado, es una forma de convertir una cadena en "galimatías" (llamada hash), pero a diferencia del cifrado, no puede obtener la cadena original de este hash (a menos que pueda forzarla por fuerza bruta o el hash la función está rota). La mayoría de las funciones hash (si no todas) toman una cadena de longitud arbitraria y devuelve una cadena de longitud constante (depende de la función).
¿Cómo verifica que una cadena que el usuario ha ingresado es la correcta? Como no puede obtener la cadena válida del hash, lo único que puede hacer es descifrar las conjeturas del usuario y compararlas con el hash correcto.
Advertencia (por Eric Lippert): NO UTILICE la función integrada
GetHashCode
como tal función; su resultado puede diferir entre diferentes versiones y plataformas .NET, haciendo que su código funcione solo en versiones y plataformas específicas de .NET framework.fuente
Lo que estás tratando de hacer es inútil y sin sentido.
Es inútil porque no hay forma de ocultar adecuadamente la información que está en la máquina del usuario. Cualquiera lo suficientemente dedicado lo encontrará. Puedes hacerlo más difícil, pero nunca puedes evitarlo. Si lo encripta, debe almacenar la clave de encriptación y el algoritmo en algún lugar. No importa cuántas capas de cifrado agregue, la capa más externa siempre tendrá que estar sin cifrar para que su juego se ejecute.
Tampoco tiene sentido, porque estamos viviendo en la era de Internet. Cuando tu juego se vuelve remotamente popular, esas contraseñas se publicarán en toda la web.
Todo lo que puede hacer es confiar en que el jugador no arruinará su propia experiencia de juego buscando información que el juego aún no debe decirles. La gran mayoría de los jugadores no comenzarán a realizar ingeniería inversa en tu juego de todos modos. Y si los pocos que tienen las habilidades necesarias hacen esto, entonces es su culpa.
fuente
Si realmente se desea tal cosa, entonces, en lugar de hash, podría considerar construir las cadenas a partir de un valor de entrada numérico en tiempo de ejecución.
La ventaja es que, como señaló @Philipp, no tiene sentido intentar ocultar los códigos en el ejecutable si puede esperar que se publiquen en Internet de todos modos. Hashed o no, la misma palabra encontrada en Internet e ingresada en el juego dará el mismo hash y funcionará de cualquier manera.
Excepto ... excepto si el código de otra persona no funciona para ti. Lo que puede hacer trivialmente: no es 100% a prueba de manipulaciones pero es razonablemente difícil de solucionar para el usuario promedio. Algo tan simple como lo hará el "generador de nombres en línea Elven" (puede ser arbitrariamente simple, realmente no necesita mucho de un motor de generación de texto markov, extraer 4-5 sílabas de una lista aleatoria es lo suficientemente bueno).
Simplemente genere un número específico del usuario o específico de la máquina, ni siquiera tiene que ser perfectamente único o muy resistente a la manipulación. Algo que probablemente sea diferente para la mayoría de las personas y que sea poco probable que cambie regularmente, por ejemplo, el nombre de red de la computadora, la dirección MAC o el GUID de la unidad de disco del sistema, lo que sea (el número de serie de la GPU puede ser un muy malo)idea ya que es probable que los usuarios actualicen las GPU). Agregue a eso el código numérico al que se refiere el código de desbloqueo e ingrese eso en su generador de palabras. Pero prepárese para responder consultas de soporte cuando los jugadores usen dos computadoras o cambien su tarjeta de red (lo cual es inusual, pero no imposible). Puede ser un buen plan generar solo la ID aleatoria una vez y almacenarla con la configuración del juego. De esa manera, al menos no interrumpe las instalaciones existentes en la misma máquina si algo cambia.
O bien, puede usar el número de serie del juego, que es único y funcionará si el usuario cambia el hardware (irónicamente, sin embargo, esto podría promover la piratería ya que los códigos de desbloqueo compartidos funcionan para series pirateadas pero no para clientes legítimos).
Tenga en cuenta que evitar que los usuarios hagan trampa no es necesariamente algo bueno. En un juego fuera de línea (es decir, no competitivo), generalmente no hay problema si el usuario hace trampa y obtiene los códigos de algún lugar en lugar de jugar. Él solo se está engañando a sí mismo. A quien le importa.
Por otro lado, ponerse demasiado en su camino si realmente desean hacer trampa es una gran oportunidad para cabrear por completo a los clientes que pagan.
Entonces ... antes de hacer algo de esa manera, piense muy bien si realmente quiere eso y qué quiere. Muy posiblemente, tener cadenas legibles por humanos (o trivialmente hechas "ilegibles" con xor) es lo suficientemente bueno y de hecho preferible.
fuente
hash(serial + 1)
para obtener un número correspondiente al primer código. Luego alimente eso en su generador de palabras, que extrae, por ejemplo, una sílaba de una lista de 16 por cada 4 bits de entrada. Ahí tienes, "palabras" individuales para cada usuario.hash(serial+1)
después de descargarlo, ¿qué impide que el usuario realice el cálculohash(serial+1)
? Una vez que se descarga el programa, el usuario tiene acceso a todo lo que hace el programa.hash(serial + 1)
. ¿Y qué? Esto no es un problema. Mire, si alguien invierte una o dos horas (probablemente 6-8 horas para un "usuario" típico sin experiencia en desarrollo de software) solo para engañarse a sí mismo, bueno ... déjelo. La cuestión es que esto funciona para una persona, pero no para todos, y no es competitivo ... así que no hay problema.Si no necesita mostrar las cadenas, entonces la idea de hash es probablemente el camino a seguir. Si, por otro lado, necesita mostrárselos al usuario, hay otras maneras de evitar que aparezcan directamente en su DLL.
Una forma de lidiar con esto además de cifrar u ofuscar las cadenas es dividirlas. Tal vez solo tenga un diccionario ordenado alfabéticamente de todas las palabras posibles de todas las cadenas del juego. Luego, tenga una matriz en algún lugar que le permita juntar las palabras en la cadena que necesita indexando en la matriz de palabras. De esta manera, no tienes las cadenas completas en ninguna parte del juego. No se necesita una clave maestra para descifrar las cadenas. Y los datos que indican su orden podrían estar en toda su fuente, si, por ejemplo, cada función que utiliza una cadena solo tiene una matriz de índices locales para la función. No estoy seguro de lo práctico que es en su caso específico, pero es una forma de hacerlo.
Incluso puede tener una cadena compuesta de algunas palabras, pero terminan en diferentes órdenes. Por ejemplo, puede necesitar las siguientes 2 cadenas:
Su lista de frases contendría tanto "un oso" como "mi casa", pero tendría una gran lista de otras frases que podrían colocarse entre ellas, por lo que descubrir cuál sería tan difícil como descubrirlo realmente El rompecabezas en el juego (o lo que sea). Por ejemplo, las frases de acción podrían ser "caminadas", "quemadas", "empujadas", "protegidas de", "separadas de mí", "producidas mágicamente", etc.
Podrías incorporar esto a tu juego haciendo que los índices se basen en algo que el jugador ha recopilado o hecho. Por lo tanto, no habría una lista maestra de índices en ninguna parte del juego. Serían generados por el jugador que juega el juego.
fuente
strings
contra el ejecutable.