viernes, 8 de mayo de 2015

Trampeando videojuegos con Cheat Engine

Tramposos somos

En muchas ocasiones nos encontramos ante un juego en el que conseguir un determinado objetivo se nos pone un poco cuesta arriba, y aunque una y otra vez parece que lo tenemos en la punta de los dedos en el último momento acaba escapándose.

En estas situaciones, lo normal es priorizar nuestra salud mental y olvidarnos del logro. Pero si no es el caso, no te queda otra que acudir a la noble y admirable perseverancia asiática, reiniciando una y otra vez hasta que se alinean los planetas.

Superando logros. "Classic Mode"

Puesto que muchos no tenemos ya la paciencia necesaria para acometer este tipo de tareas de la forma clásica, le echamos un poco de la igualmente famosa picaresca española y sacamos algo así:

Superando logros... de "otro modo"

Aunque el vídeo está editado para acortarlo y destacar los datos importantes, no he usado ningún truco de vídeo para simular una bajada del tiempo contabilizado por el cronómetro, ni he pegado dos trozos de dos partidas distintas. Obviamente hay un truco, pero no es de vídeo. Se llama Cheat Engine.

Cheat Engine

Cheat Engine es una curiosa herramienta que une, al igual que lo que nos proponemos desde este blog, el mundo de la ingeniería inversa con el de los videojuegos. Siendo como es una herramienta de código abierto, presenta una gran cantidad de funcionalidades que la hacen muy versátil, no solo para hacer trampas en videojuegos modificando "al vuelo" parámetros del mismo, si no para otras tareas de ingeniería inversa que no tienen por qué tener como objetivo un videojuego.

 Logo de Cheat Engine
El  primer objetivo de la herramienta es ayudarnos a localizar en qué posiciones de memoria el videojuego objetivo almacena datos que nos interesan modificar: monedas, puntos, vida, etc... implementando para ello una gran cantidad de modos de búsqueda.

Una vez localizadas aquellas zonas de memoria que albergan datos que nos interesa controlar, la herramienta ofrece varias posibilidades a la hora de controlar el contenido de dichas zonas de memoria.

Técnicamente hablando, y para los que tienen experiencia en programación, Cheat Engine se engancha a un proceso en ejecución como un depurador, lo que le da acceso a la memoria del proceso y al flujo de ejecución del mismo.

Aunque al principio de esta entrada hemos mostrado un ejemplo con el juego Rush Brospara mostrar el funcionamiento básico de la herramienta vamos a usar otro juego que además ser gratuito y todos podemos descargar, tiene su encanto.

El juego se llama Treasure Adventure Game, y como indica el desarrollador en su página se puede descargar desde varios sitios. En mi caso, puesto que tengo cuenta en GOG me lo he bajado de ahí. Quien lo quiera disfrutar en castellano, también existe una traducción disponible entre otros enlaces, aquí.

Rebuscando en la memoria

El primer paso es descubrir en qué localización de memoria nuestro programa objetivo almacena el dato o datos que queremos alterar. Para ello, la solución propuesta por Cheat Engine consiste en realizar búsquedas de manera iterativa. En cada iteración, se evalúa el criterio seleccionado por el usuario sobre los posibles objetivos localizados en la iteración anterior. Así, poco a poco, vamos descartando localizaciones de memoria quedándonos cada vez con menos localizaciones que cumplen las condiciones que vamos imponiendo.

Tras cada iteración, podemos modificar el criterio de búsqueda que se realizará en la siguiente, pero teniendo en cuenta que Cheat Engine en la siguiente iteración solo va a evaluar el criterio seleccionado en el conjunto de localizaciones que superaron el criterio de la iteración anterior.

Antes de realizar la primera iteración de búsqueda tenemos que definir qué tipo de dato contiene la variable que vamos a buscar. El tipo de dato se mantendrá constante durante el resto de iteraciones de búsqueda. Cheat Engine ofrece la búsqueda de valores enteros de tamaño de 1 byte a 8 bytes, búsqueda de valores flotantes, o  incluso de cadenas de texto.

En nuestro ejemplo, nuestro personaje en el juego Treasure Adventure Game dispone de dos contadores, que se muestran en la esquina superior izquierda de la pantalla. Uno de nivel de vida con un valor inicial de 6, y justo debajo otro de monedas con un valor inicial de cero. Nuestro objetivo será controlar ambos valores usando Cheat Engine.

Captura de Treasure Adventure Game. 6 vidas y 21 monedas
Para llegar a la pantalla que se aprecia en la captura, una vez iniciado el juego, y tras las charlas de turno, nos desplazaremos hacia la derecha hasta llegar ahí. Justo en esa puerta aparecen los primeros enemigos que nos darán monedas al eliminarlos, y nos quitarán vidas al tocarnos... lo que necesitamos para empezar a jugar con
Cheat Engine.

En Cheat Engine, pulsamos el botón 'Open Process' y nos aparecerá una ventana con el listado de procesos en ejecución en nuestra máquina. Seleccionamos el proceso del juego, cuyo nombre vendrá precedido con un número en hexadecimal que es el identificador de proceso (aparece en el administrador de tareas de Windows en la pestaña 'Procesos', columna 'PID'). Aunque el nombre del proceso no cambia, ese identificador de proceso cambia en cada ejecución.

Ya estamos listos para lanzar nuestra primera búsqueda. En el tamaño del tipo de valor dejamos el valor por defecto de 4 bytes, que son más que suficientes para el  tamaño de almacenamiento del valor que vamos a buscar. El tipo de búsqueda que vamos a hacer será por valor exacto, y en el control superior tecleamos el número a buscar, que será en este caso el número de vidas que nos quedan. Pulsamos el botón de nueva búsqueda y enseguida el programa nos habrá localizado unos cuantos millares de posiciones de memoria que guardan dicho valor.

Primera búsqueda para localizar el contador de vida
Como se puede apreciar en la imagen, hemos encontrado algo más de 4700 posiciones de memoria. Si nos desplazamos por el listado, veremos que algunas aparecen en rojo, lo que indica que su valor actual es distinto del que tenía cuando se realizó la búsqueda. Cheat Engine nos muestra en tiempo real el valor almacenado en cada posición de memoria. En este caso, puesto que nuestro nivel de vida en el juego no ha cambiado, podemos repetir la misma búsqueda pulsando el botón 'Next Scan'. Del listado actual, Cheat Engine eliminará todas aquellas posiciones que ya no almacenan el valor 6, lo que acortará el número de posibles objetivos.

En el juego entramos en la cueva y nos dejamos 'acariciar' por el primer bicho que encontremos, lo que disminuirá nuestro valor de vida en una determinada cantidad. Volvemos a Cheat Engine, introducimos el nuevo valor de vida restante en la casilla de valor a buscar, y pulsamos en 'Next Scan'.  La lista disminuirá considerablemente.

Seguimos iterando este proceso de búsqueda las veces necesarias para que, idealmente nos quede una única posición, o al menos un listado de resultados suficientemente corto.

Confirmando hallazgos

Una vez que tenemos un número de posibles objetivos lo más bajo posible, pasamos a modificar manualmente los valores de dichas posiciones de memoria a ver cuál produce el efecto deseado. Sobre la posición de memoria a modificar, sacamos el menú contextual y seleccionamos la opción para cambiar el valor.

Tras buscar, probamos a cambiar los valores
Escribimos el valor que queramos, aunque para evitar errores y puesto que el valor máximo de vidas en el juego es 6, colocamos un valor menor o igual que 6, y pulsamos 'Ok'. Si hemos acertado con la posición de memoria adecuada, el contador de vidas del juego mostrará el nuevo valor introducido.

Si es así, ya hemos localizado la posición en memoria del contador de vida en el juego. En el mismo menú contextual anterior seleccionamos la opción 'Add selected address to the addresslist' para almacenar este valor y que no se nos pierda. La dirección de memoria aparecerá en la lista inferior del interfaz de Cheat Engine, lista que denominaremos Cheat Table. Desde el menú contextual de dicha lista inferior podemos cambiar para esa dirección la columna de descripción por algo más intuitivo como 'Vidas'.

Reiniciamos la búsqueda con el botón 'New Scan' y repetimos el proceso para las monedas. Cada vez que eliminemos un enemigo, esté soltará monedas que al recogerlas incrementará nuestro contador de monedas, lo que nos permitirá reiterar la búsqueda con el nuevo valor para descartar resultados obtenidos en la búsqueda anterior. En caso de que nos quedemos sin enemigos antes de localizar lo que buscamos, podemos salir y volver a entrar la cueva ya que esto repone los enemigos.

En el caso de las monedas, la modificación del valor de la dirección de memoria que encontremos no se mostrará inmediatamente en la interfaz del juego ya que el contador de monedas solo se refresca al recoger nuevas monedas o al entrar o salir por una puerta. Al final, tendremos en nuestra Cheat Table un listado de direcciones similar a éste:

Listado final de direcciones
Antes de dar por finalizada la búsqueda de las direcciones de memoria a controlar, hay que cerciorarse de una cosa. Desde el inicio hemos supuesto que las variables son de un tamaño de 4 bytes, pero ha sido una mera suposición. Posteriormente inyectamos en las posiciones de memoria localizadas valores de 4 bytes, pero si para el programa en realidad son variables de otro tamaño, podemos generar errores en la ejecución del programa.

Por ejemplo, si en realidad la variable que almacena las vidas restantes fuera de dos bytes, y dependiendo del compilador utilizado al generar el juego, es posible que si escribimos cuatro bytes estemos modificando inadvertidamente alguna otra variable adyacente en memoria a la que nos interesa.

La manera más lógica es comprobar como usa el proceso esa posición de memoria, como la lee y como escribe en ella. Con Cheat Engine esa tarea es extremadamente sencilla, sin tener que acudir a otras herramientas externas de ingeniería inversa. El debugger que incorpora Cheat Engine nos permite acceder al código que escribe o lee una determinada posición de memoria. Lo habilitamos desde el menú contextual de la lista inferior de direcciones, y seleccionamos la opción para cazar los accesos de escritura a la dirección de memoria a comprobar.

Monitorizando los accesos de escritura a la variable
Una vez en marcha el debugger de Cheat Engine, en el juego realizamos alguna acción que provoque que dicho contador cambie.

Resultado de monitorización accesos de escritura
En la ventana del debugger, se nos muestran las instrucciones que escriben en la posición de memoria de interés. En la primera columna se muestra un contador con el número de veces que se ha ejecutado dicha instrucción, y en la segunda se muestra la instrucción propiamente dicha. Al seleccionar cada instrucción, en la parte inferior aparecen las instrucciones adyacentes a la de interés (que aparece marcada al final con '<<'), además del contenido de los registros del procesador justo tras ejecutarse la instrucción marcada. En nuestro caso, el registro EAX+08 apunta a nuestra variable, y en dicha posición se escribe el contenido del registro ECX, que contiene un cinco ya que acabamos de perder una vida en el juego. En las instrucciones anteriores podemos ver como en ECX se cargaba el contador de vidas actual, y se le restaba el valor de EDX, que valía uno.

Con la información facilitada por el debugger vemos que el contenido de la posición de memoria apuntada se escribe con el contenido del registro ECX, que ocupa 4 bytes, por lo que nuestra variable es de un tipo que ocupa cuatro bytes, así que todo parece estar correcto. También podía haberse dado el caso de que en la posición de memoria se hubiera volcado un valor de 8 bytes, como hubiera sido por ejemplo el registro RCX, que tiene 64 bits. En estos casos en los que se ha supuesto un tamaño de dato inferior al correcto, también es posible que no estuviéramos apuntando a la posición de memoria en la que se inicia el almacenamiento de la variable, si no a la parte final de la misma, con lo que también tendríamos que corregir ese dato.

Con el botón 'More information' accedemos a información extra, como por ejemplo el contenido de la pila cuando se ejecutó dicha instrucción, información que puede ser muy importante para según cuales sean nuestros objetivos. Si fuera necesario, el menú contextual de la lista inferior de dirección, en su opción de 'Change record', además de cambiar la descripción como vimos anteriormente, también nos permitirá corregir la variable objetivo, tanto su tamaño como la dirección de la misma.

Ya hemos resuelto la primera complicación: localizar en dónde se almacenan los valores que nos interesa alterar. Lo que sigue depende de lo que queramos hacer. Podemos hacer que Cheat Engine cambie el contenido de esa variable a un valor predeterminado cada vez que pulsemos una combinación de teclas que configuremos, o incluso podemos crear un programa independiente que lo haga, lo que en el mundo de los videojuegos se denomina "trainer", que no es mas que un pequeño programa especializado en modificar determinados parámetros para una versión específica de un juego.

Explotando los hallazgos

La variable (o variables) de interés deben añadirse a la Cheat Table, que es la lista inferior del interfaz, y que contendrá la lista de direcciones de memoria sobre las que se quiere actuar (opción en negrita del menú contextual mostrado anteriormente). Una vez en la lista de direcciones, usando el menú contextual de dicha lista (Change record -> Description), podemos modificar la descripción de cada una de ellas para tenerlo todo ordenado y clarito, y que sepamos a qué se refiere cada variable. Se presentan a continuación las maneras que ofrece Cheat Engine para manipular el contenido de las variables de interés.

Desde la interfaz de Cheat Engine

A la hora de manipular estos valores, la opción más sencilla es desde la propia interfaz de Cheat Engine. Ya hemos visto como podemos modificar cualquier valor de una dirección de memoria listada en la lista de objetivos.

En nuestro ejemplo, esta solución es válida para en cualquier momento aumentarnos nuestras monedas o vidas restantes, aunque en el caso de las vidas puede hacerse pesado conmutar una y otra vez del juego a la interfaz de Cheat Engine para recuperarnos del último golpe. Además, es posible que es determinadas situaciones no nos de tiempo a conmutar a Cheat Engine para evitar que nos finiquiten en el juego.

Para ello, Cheat Engine dispone de una funcionalidad para "congelar" el valor de una determinada variable. Mientras una variable esté congelada, Cheat Engine vigilará continuamente el valor de la misma, y en caso de que cambie, la devolverá a su estado anterior. La congelación del contenido de una dirección de memoria se habilita desde la columna 'Active' de la Cheat Table.

Contador de vidas "congelado"
Una vez congeladas las vidas, ya podemos volver al juego y no tener que volver a preocuparnos de los golpes que nuestro personaje reciba. Hay que tener en cuenta que la funcionalidad de congelación no evita que el juego cambie la variable. En realidad el juego llega a modificar la variable, pero inmediatamente Cheat Engine detecta el cambio y devuelve la variable al estado anterior. Esto significa que si congelamos el contador de vidas cuando queda una sola vida, y un enemigo nos quita dos de golpe, la partida finalizará a pesar de que Cheat Engine acuda unas décimas de segundo después a intentar restaurar su valor.

Hotkeys

Aunque desde la interfaz de Cheat Engine podemos manipular a placer cualquier variable que hayamos localizado, a la hora de realizar manipulaciones continuas de los valores, el tener que conmutar de la tarea del juego al proceso Cheat Engine una y otra vez puede hacerse bastante tedioso. Para evitarlo tenemos los hotkeys. Con Cheat Engine corriendo en segundo plano, y cuando en el juego o programa en cuestión queramos modificar alguna de sus variables, podemos pulsar una combinación de teclas o hotkey que hayamos predefinido para alterar el contenido de dicha variable. Además es posible definir todos los hotkeys que queramos, asignando a cada uno una modificación distinta, pudiendo manejar todas las variables que queramos sin tener que salir del juego en ningún momento, pulsando en cada momento la hotkey adecuada.

Haciendo click derecho en la Cheat Table sobre la variable que queramos modificar, en el menú contextual pulsamos la opción 'Set/Change hotkeys'. Se muestra una ventana donde se listan hotkeys previamente definidos para editarlos, o bien podemos crear uno nuevo.

En la ventana de creación y edición, primero se define el hotkey, que nos es más que la combinación de teclas con la que activaremos la funcionalidad definida debajo. Entramos en dicho control y pulsamos la combinación de teclas deseada. En caso de que queramos eliminar su contenido pulsamos el botón 'Clear' de la derecha.

Debajo se define la operación a realizar sobre la variable al activar la funcionalidad mediante el hotkey definido. Las operaciones principales que permite Cheat Engine sobre la variable es congelarla, escribir un valor determinado o bien incrementarla o decrementarla con un valor definido. La opción de congelar la variable viene con varios 'sabores', con lo que se amplían las posibilidades. El listado completo de opciones para asignación de funciones a un hotkey es el siguiente:

  • Altenar la congelación de la variable ('Toggle freeze'). Cada vez que pulsemos el hotkey, el estado de la variable conmutará entre congelada y descongelada.
  • Altenar la congelación de la variable permitiendo incrementos ('Toggle freeze and allow increments'). Lo mismo que la anterior, aunque se dejará a la variable ser incrementada.
  • Altenar la congelación de la variable permitiendo decrementos ('Toggle freeze and allow decrements'). Está claro...
  • Congelar.
  • Descongelar.
  • Escribir valor ('Set value to:'). Se escribe en la variable el valor que pongamos debajo.
  • Decrementar valor ('Decrease value with:'). Se decrementa la variable por el valor que definamos
  • Incrementar valor ('Increase value with:'). Incremento por el valor que definamos.
Finalmente hay un control para agregar una descripción de la funcionalidad que estamos definiendo.

En nuestro ejemplo vamos a crear un hotkey sobre el contador de vidas que hemos localizado para obtener la invulnerabilidad. Definimos la funcionalidad con estos valores:

Vidas infinitas
Con los valores definidos, al pulsar la tecla 'Control' junto con la tecla 'V', congelaremos el contador de vidas. Si volvemos a pulsar la combinación de teclas la descongelaremos. Y todo sin salir del juego.

Punteros, clases, objetos y otras zarandajas

A estas alturas, más de uno se habrá dado cuenta que aunque Cheat Engine permite grabar los hallazgos de la Cheat Table para reusarlos en futuras ocasiones, al volver a arrancar Cheat Engine, el juego en cuestión, cargar el proceso del juego en Cheat Engine y recargar el fichero *.CT que Cheat Engine creó con nuestras variables, el contenido de las direcciones de memoria recargadas ya no es el que esperamos, y tenemos que volver a buscar la nueva localización de nuestras variables.

Esto se debe a que en la metodología de programación actual se utilizan variables dinámicas, en lugar de variables estáticas. Y esto es así sobre todo en lenguajes orientados a clases y objetos. Visto a bajo nivel, una clase viene a ser una definición de una estructura de datos, que se denominan propiedades de la clase. Esta clase no ocupa espacio en memoria, ni es directamente utilizable, es meramente una definición. Los objetos son instancias de clases, que cumplen con la definición de la clase que implementan, y estos ya sí ocupan espacio en memoria. Este espacio de memoria que ocupa el objeto es el necesario para almacenar todas las propiedades que define la clase de dicho objeto.

Por poner un símil en la vida real, podemos tener una idea abstracta de lo que es un coche y como se define. A partir de dicha definición, podemos heredar una idea abstracta de cómo es nuestra marca y modelo favorito de coche, que cumplirá todas las definiciones de un coche genérico y además incluirá otras más específicas. Eso serían las clases, donde 'Coche' sería la clase padre, y 'MarcaX_ModeloY' sería una de las posibles clases hija de la anterior. Ambas son definiciones abstractas, que no ocupan lugar en el mundo físico. El 'objeto' sería el coche con matrícula XXXX y nº de bastidor YYYY que tenemos aparcado en el garaje, que es una implementación de la clase 'MarcaX_ModeloY', y que ocupa un espacio y lugar en el mundo físico.

Volviendo a nuestro juego, podemos tener una clase 'Personaje' que define una estructura de datos que define los parámetros necesarios para el funcionamiento del mismo, como puede ser la localización del personaje, el recurso visual usado para mostrarlo en el juego, etc... y como hemos visto otro de dichos datos puede ser nuestra variable 'Vidas', que ocupa 4 bytes. A partir de la clase anterior, puede definirse otra clase heredera 'Protagonista' que tenga todas las características de la clase padre 'Personaje' y que además añada otros datos adicionales como puede ser una variable 'Monedas' también de 4 bytes.

Al iniciar una partida el programa creará un objeto de la clase 'Protagonista' para controlar el personaje que manejamos. Este objeto contendrá, entre otras cosas, los contadores Vidas y Monedas en los que estamos interesados. Al crearse el objeto, a partir de una dirección de memoria se reserva el espacio necesario para ubicar todas las propiedades de la clase. Todos los objetos de una misma clase almacenan sus propiedades en el espacio de memoria asignado de la misma manera y en el mismo orden. Así, si suponemos dos objetos distintos de la clase 'Protagonista', en ambos la distancia en bytes desde el inicio del objeto en memoria hasta el elemento Vidas coincidirá.

Cada vez que desde Cheat Engine localizamos estas variables, encontramos direcciones de memoria que pertenecen al objeto de la clase 'Protagonista' que el juego tiene creado en ese momento. El problema es que cada vez que se inicia el juego, y se vuelve a crear el objeto de la clase 'Protagonista', éste se almacena en una dirección completamente arbitraria, con lo que la posición en memoria de los contadores que nos interesan habrá cambiado.

De esta manera, si no queremos tener que repetir la búsqueda de las variables cada vez que arranquemos el juego, tendremos que fijarnos en otra cosa que no cambie. Lo que tendremos que buscar es en qué posiciones de memoria el juego guarda la dirección de memoria a partir de la cual se almacenan las propiedades del objeto 'Protagonista', o dicho en otras palabras, localizar lo que se denomina el puntero al objeto 'Protagonista'. Un puntero es una dirección de memoria en la que se almacena a su vez la dirección de memoria en la que hay un determinado dato. A partir de la dirección de inicio del objeto, acceder a sus propiedades se reduce a sumar un desplazamiento fijo.

¿Como hacemos esto en Cheat Engine? La búsqueda de punteros se realiza de manera iterativa, similar a la búsqueda de valores. Si nos hemos fijado tras realizar varias veces las búsquedas de los contadores, ambos cambian de dirección en cada ejecución del juego, pero siempre hay una distancia fija de 16 bytes (0x10 en hexadecimal) entre ambos. Así, localizando un puntero que apunta a uno de ellos, también obtendremos el otro. Y cuando digo 'un puntero' me refiero a que pueden haber decenas de punteros válidos en el programa que apunten al mismo objeto, que puede estar referenciado desde varios sitios. Cualquiera de ellos nos valdría para nuestros propósitos.

Al igual que la búsqueda de valores, Cheat Engine usa un método 'ciego' para buscar posibles punteros a nuestra dirección de interés. Para las localizaciones de memoria que encuentre almacenadas en la memoria del proceso, buscará cuales pueden enlazarse mediante uno o más saltos (offsets) con la dirección de interés cumpliendo los requisitos que indiquemos en la ventana de configuración de la funcionalidad.

Por ejemplo, nos centramos en el contador de monedas, y en su menú contextual seleccionamos 'Pointer scan for this address'. La ventana nos aparecerá inicialmente configurada con la dirección de interés en la parte superior.

Configuración búsqueda de punteros
En la ventana hay muchas opciones, muchas de las cuales pueden parecer bastante crípticas tanto para novatos como para menos novatos...

Inicialmente los más importantes pueden ser los del final, que van a permitir acotar y delimitar el universo, inicialmente casi infinito, sobre el cuál Cheat Engine va a realizar la búsqueda.

El primer parámetro, 'Maximum offset value' va a limitar el máximo tamaño de salto que va a contemplar el algoritmo de búsqueda. Tal y como está configurado, la distancia máxima de salto será de 2048 bytes, 0x800 en hexadecimal. Así, si el algoritmo encuentra una dirección de memoria almacenada, o sea, un puntero, solo estudiará el rango 4096 bytes situados alrededor del destino de dicho puntero. Si en ese rango no encuentra la manera de enlazar con el destino (directa o indirectamente a través de otro puntero), descartará dicho puntero.

El segundo parámetro define el número máximo de saltos para llegar a la dirección destino. Tal y como se dijo anteriormente, un puntero es una posición de memoria que alberga la dirección de memoria de otro dato... la historia es que ese otro dato también puede ser a su vez otro puntero, y así hasta aburrir... El enlace entre un puntero y su anidado es lo que llamo un salto. El parámetro 'Max level' define el número de saltos que va a contemplar el algoritmo de búsqueda para, a partir de localizar un puntero, llegar a la dirección de destino.

Dependiendo de la potencia del PC, y sobre todo de estos dos últimos parámetros, el algoritmo tardará más o menos tiempo en finalizar. Inicialmente definimos unos parámetros muy restrictivos dejando el 'Max level' a dos o tres. Si con esa configuración no encontramos una solución consistente, siempre podemos aumentar esos dos parámetros para aumentar el universo de búsqueda.

Mientras que el resultado no tenga un número manejable de registros, reiteraremos la búsqueda para disminuirlos. En mi caso, con 'Max level' a tres me ha arrojado 642 posibles punteros. Para ello, sin cerrar la ventana de búsqueda de punteros, cerramos el juego, lo volvemos a arrancar, y desde la interfaz principal de Cheat Engine repetimos la búsqueda de nuestro contador de monedas, que ahora estará localizado en una nueva posición de memoria. Una vez localizado, apuntamos el valor y volvemos a la ventana de búsqueda de punteros para filtrar aquellos punteros que ahora apuntan a la nueva dirección de dicho contador. Pulsamos en el menú 'Pointer scanner', opción 'Rescan memory', e introducimos la nueva dirección del contador de monedas. Un posible puntero válido de los localizados en la primera búsqueda debe apuntar a esta nueva dirección para no ser descartado.

Filtrando la búsqueda de punteros tras reiniciar el juego
Tras aplicar este filtrado, los resultados se reducen bastante.


Punteros localizados tras el primer filtrado
Aunque repitamos el proceso, el número de punteros válidos no va a disminuir mucho más. Como era de esperar el mismo objeto puede estar referenciado en distintos lugares. Toca ahora elegir con cual nos quedamos.

Lo primero es explicar esa ventana. La primera columna indica el módulo y dirección relativa dentro de dicho módulo en el que se encuentra el puntero. Cuando lanzamos un ejecutable, el sistema operativo cargará en memoria los módulos que precisa. Como mínimo cargará un módulo, que es el propio ejecutable en sí. Luego, en la mayor parte de las ocasiones, cargará otras librerías que usa el ejecutable, y que constituyen el resto de módulos del proceso.

'THREADSTACK#0' no referencia a un módulo, sino a la pila de uno de los hilos del proceso, en concreto del hilo 0, o sea, del hilo principal. La pila, es un espacio de memoria reservado para cada hilo en ejecución que se usa para pasar parámetros cuando se invoca un procedimiento o función, además de mantener la dirección de retorno para cuando se finalice la llamada al procedimiento.

Las columnas 'Offset' indican la distancia en bytes a la que referencia el puntero localizado. Excepto la última, cada columna representa un salto de un puntero a otro anidado. Puesto que nuestro parámetro 'Max level' lo acotamos a tres, no encontraremos punteros con más de tres columnas 'Offset'. Para explicarlo mejor, hacemos doble click sobre el tercer resultado que en mi caso tiene tres columnas de offset con valores hexadecimales C8, 268 y18. Este puntero se añadirá a la lista Cheat Table del interfaz principal. Pulsamos sobre el con el botón de la derecha y seleccionamos en el submenú 'Change record' la opción 'Address'.

Estructura de un puntero
La referencia para explicar la información de dicha ventana se lee desde abajo hacia arriba, y nos ayudamos con la calculadora de Windows en su vista de programador:
  1. Este puntero se encuentra en la dirección relativa hexadecimal  0x59A0C del módulo principal. Su contenido apunta a la dirección 0x6301A0.
  2. En el offset 0xC8 de dicha dirección, o sea, en la dirección 0x630268 (0x6301A0 + 0xC8) encontramos un nuevo puntero que apunta a la dirección 0x630948.
  3. En el offset 0x268 de dicha dirección, o sea, en la dirección 0x630BB0 (0x630948 + 0x268) encontramos un nuevo puntero que apunta a la dirección 0x2BB5E00.
  4. Y llegamos a la dirección destino (0x2BB5E18) sumando un offset de 0x18 a la dirección 0x2BB5E00 anterior. El contenido de la dirección destino es nuestro ansiado contador de monedas, que en estos momentos refleja un valor de 6.
Siguiendo la lógica de clases y objetos que se comentó anteriormente, 0x2BB5E00 es la dirección a partir de la que se almacena nuestro presunto objeto de la clase 'Protagonista', mientras que el offset 0x18 indica el desplazamiento dentro de dicho objeto para llegar a la propiedad que almacena el contador de monedas.

Finalmente la última columna de la lista de punteros localizados indica la dirección final a la que apunta el puntero y el valor que dicha dirección almacena. En nuestro caso, todos apuntan a nuestro contador actual de Monedas, y en mi caso tengo 6 monedas, como así debe reflejar la interfaz del juego.

Lo lógico parece que es quedarnos con el puntero que aparece en la quinta línea. Es el que tiene menos "saltos" hasta llegar al objetivo, y además es una variable que está dentro del módulo principal. Eliminamos el resto de direcciones que tengamos en la Cheat Table, y hacemos doble click sobre el quinto puntero de la lista de resultados de la búsqueda. Lo etiquetamos como 'Puntero monedas'.

El contador de vidas vimos que se encuentra en el mismo objeto, pero aplicando un offset adicional de 16 bytes (0x10 en hexadecimal) respecto al del contador de monedas. Volvemos a hacer doble click sobre el quinto puntero para volverlo a añadir, pero ahora editamos manualmente el último offset de 0x18 a 0x28,  y colocamos una descripción adecuada.

Ajuste manual del contador de vidas
Al final, donde antes teníamos las direcciones que apuntaban directamente a los contadores de vidas y monedas, ahora tenemos dos direcciones estáticas junto con los offsets a aplicar para llegar la variable que apunta al objeto creado dinámicamente (el primer offset de 0x268) y a las propiedades dentro del mismo que almacenan ambos valores (0x18 para las monedas y 0x28 para las vidas). Estos punteros pueden utilizarse para controlar el valor de la variables de interés de la misma manera que se expuso en las secciones anteriores utilizando las direcciones finales directamente.

Tabla final de punteros
Esta tabla final podemos guardarla, ya que no cambiará en futuras ejecuciones del juego. De hecho el archivo resultante podemos compartirlo con los amigos ya que les servirá igualmente, siempre y cuando usen la misma versión del juego. A partir de esta Cheat Table seguiremos trabajando para lograr otras cosas interesantes...

En la página de Cheat Engine se pueden encontrar también Cheat Tables como la que acabamos de generar subidas por la comunidad para multitud de juegos.

'Nopeando' el código del objetivo

Como se comentó en una sección anterior, congelar desde Cheat Engine el contenido de una de las direcciones de memoria tiene sus problemas ya que lo que hace Cheat Engine es monitorizar el valor de la variable, y en el momento en que detecta que ha habido un cambio, la restaura a su valor inicial, pero el cambio se llega a producir. En el caso de nuestro ejemplo en el que congelamos el contador de vidas restantes, el que el cambio se produzca puede provocar que la partida finalice sin remedio si tras el cambio la variable llega a ser cero.

Otro de los mecanismos que ofrece Cheat Engine se basa en eliminar la instrucción que cambia el valor de una variable que no queremos que se vea modificada. Lo que realiza la herramienta es una modificación en el código del programa, sustituyendo una instrucción por una secuencia de instrucciones de ensamblador 'NOP' (No Operation). Esta instrucción especial hace que el procesador no haga absolutamente nada. El código máquina de esta instrucción ocupa un único byte, por lo que si la instrucción a sustituir ocupa más espacio, cada uno de sus bytes es sustituido por una instrucción 'NOP'.

Tal y como se hizo cuando intentamos determinar el tamaño de las variables, lanzamos desde Cheat Engine la funcionalidad para monitorizar los accesos de escritura hacia la variable que contiene el contador de vidas restantes, que ya la tenemos en forma de puntero dinámico en nuestra lista de objetivos. Al tratarse ahora de un puntero, Cheat Engine nos consulta si queremos buscar las instrucciones que escriben el puntero, o bien las que escriben en la dirección apuntada por el puntero.

Buscar accesos a un puntero o a la dirección a la que apunta
Seleccionamos la opción inferior, y en el juego intentamos que cambie el contador de vidas para ver qué ocurre, y desde dónde ocurre. Una vez que se capturen las instrucciones que modifican nuestra dirección al realizar una determinada acción en el juego (como puede ser perder vidas por contactar con un enemigo), pulsamos sobre las mismas para ver información ampliada.

En el caso de nuestro juego de ejemplo, solo ha aparecido una única instrucción, lo que facilita las cosas. Aunque ya podríamos eliminar dicha instrucción mediante la opción 'Replace with code that does nothing (NOP)' deberíamos comprobar si esa instrucción se usa para modificar otras variables. Para ello activamos la opción para verificar los accesos que realiza dicha instrucción a otras variables, y jugamos un poco en el juego para hacer que el código corra...

Verificando las instrucciones que acceden al contador de vidas
Una de las cosas que podemos realizar en el juego es comprar una gorra azul que venden en la tienda que se muestra en la siguiente captura. Tendremos que incrementar nuestro contador de monedas al menos hasta 100 para poder adquirirla, pero es algo que ya sabemos hacerlo.

Tienda en Treasure Adventure Game
Al comprar la gorra veremos que la misma instrucción utilizada para decrementar el contador de vidas también se usa para decrementar el de monedas. Tras un rato jugando con el juego encontramos estos resultados:
Accesos de escritura al contador de vidas
Cheat Engine ha registrado que el contador de vidas ha sido escrito por tres instrucciones distintas. Además estas instrucciones escriben en otras direcciones. En la primera columna se detalla el número de veces que cada instrucción ha sido ejecutada y entre paréntesis el número de direcciones distintas a las que ha accedido. Si hacemos doble click sobre la primera, que es la que nos decrementa vida cuando contactamos con un enemigo, se nos muestran dos ventanas adicionales:

Información adicional sobre accesos de escritura a variables
Efectivamente, la instrucción que decrementa nuestro contador de vidas (0x2A95E28), también ha decrementado nuestro contador de monedas (0x2A95E18) al comprar la gorra en la tienda del juego. Si eliminamos dicha instrucción nuestro contador de vidas no se decrementaría, y como efecto colateral nuestro contador de monedas tampoco... genial ¿no?. Pues inicialmente sí, pero es posible que se produzcan efectos no deseados si más adelante durante el desarrollo del juego la instrucción vuelve a ser utilizada para decrementar otras variables sobre la que aún no ha actuado, y tampoco nos deberíamos arriesgar a producir errores en el juego.

Más adelante veremos como realizar esta modificación del código de una manera condicional, de manera que la modificación sea efectiva cuando se accede a la variable que queremos, pero que para el resto de direcciones de memoria el programa funcione normalmente.

Para 'nopear' una instrucción la seleccionamos y pulsamos el botón 'Replace', o bien seleccionamos la acción adecuada desde el menú contextual que vimos anteriormente. Le damos un nombre a la modificación que vamos a realizar, por ejemplo 'Inmunidad', y aceptamos los cambios. Desde la ventana principal de la herramienta podemos acceder a listado de modificaciones de código realizadas mediante el botón 'Advanced Options' de la esquina inferior izquierda.

Ventana con listado de instrucciones modificadas
Desde esa ventana podemos hacer y deshacer a voluntad las modificaciones realizadas a las instrucciones listadas con el menú contextual. Si pulsamos sobre la primera opción en negrita se nos mostrará el listado en ensamblador de esa zona del juego. Antes de deshacer o rehacer una modificación del código, es recomendable pausar el juego con el botón superior de dicha ventana. Las instrucciones ya 'nopeadas' aparecerán en rojo mientras que las que se encuentran en su estado original en negro.

En el juego jugamos un poco y vemos que efectivamente nuestra vida no se decrementa, y cuando compramos algún artículo nuestras monedas tampoco. A diferencia de la 'congelación' realizada por la herramienta mediante monitorización, con esta solución la variable nunca es decrementada, por lo que en la interfaz del juego no se aprecian los cambios en el contador de vida restante durante las décimas de segundo que sí eran visibles con la otra opción.

Antes de cerrar Cheat Engine guardamos nuestro trabajo. Las instrucciones de interés listadas en la ventana 'Advanced options' se guardarán junto con nuestro punteros a los contadores a modificar.

Inyección de código

Si todo lo anterior ha parecido interesante, llegamos a la parte más divertida. En la sección anterior se ha modificado el programa objetivo eliminando aquellas instrucciones que no nos interesaba que se ejecutaran. En esta sección vamos a inyectar nuestro código en el programa objetivo, pudiendo hacer lo que queramos, o al menos lo que nuestros conocimientos nos permitan hacer. Para entender completamente esta sección es necesario tener algunos conocimientos básicos de ensamblador.

Volvemos a nuestra ventana 'Advanced Options' y hacemos doble click sobre la instrucción en la que queremos realizar modificaciones, que es la que nos decrementaba los contadores, tanto de monedas como de vidas, y puede que otros que aún no hemos descubierto. Se nos abrirá una ventana 'Memory Viewer' con el listado en ensamblador del programa objetivo centrado en la instrucción de interés, y con un volcado de memoria en la parte inferior.

El meollo del asunto
A poco que naveguemos por las opciones de los distintos menús tanto contextuales como de los menús superiores vemos que estamos ante algo serio. No se van a tratar todas y cada una de las posibilidades que permite este debugger, ya que podríamos llenar otro tutorial más. Usaremos lo que necesitemos y el resto se deja a la curiosidad de cada uno...

Vamos al menú 'Tools' y pulsamos la opción 'Auto Assemble'. Se nos abrirá una ventana inicialmente vacía, pero que enseguida vamos a llenar usando las plantillas que trae por defecto Cheat Engine. En el menú 'Template' seleccionamos la plantilla 'Cheat Table framework code'. Tendremos algo tal que así:

Framework para la Cheat Table
La idea es exportar el código que inyectemos a la Cheat Table donde aparecen ahora mismo listados los punteros a nuestros contadores de vidas y monedas. Para ello, Cheat Engine nos provee un marco en el que insertar un script para hacer cualquier cosa. El script se dividirá en dos secciones, una que se ejecutara al habilitar el 'cheat' o truco, y otra que se ejecutará al deshabilitarlo.

Lo siguiente es importar la plantilla para inyección de código. Menú 'Template', opción 'Code injection'. Se nos mostrará una ventana preguntando en qué dirección del programa objetivo queremos colocar nuestro punto de inyección de código, que por defecto mostrará la dirección en la que se encuentra la instrucción que decrementa nuestros contadores. Tras aceptar nuestro script se va poblando:

Plantilla de inyección de código añadida
Revisemos lo que tenemos. Al habilitarse el cheat, el script ejecutará la parte de la sección '[ENABLE]'. Las acciones que se realizan al habilitarse el script son las siguientes:
  1. Se reserva un bloque de memoria de  kilobytes (2048 bytes), que se asigna a la etiqueta 'newmem'.
  2. Se declaran tres etiquetas adicionales: 'returnhere', 'originalcode' y 'exit'.
  3. A partir de la dirección de memoria reservada dinámicamente con la etiqueta 'newmem' es donde se encontrará nuestro código nuevo.
  4. En el bloque de memoria reservado, tras nuestro código y etiquetado como 'originalcode', se copiará el código original que el script sobreescribirá en el punto de inyección del programa objetivo.
  5. En el bloque de memoria reservado, y tras el código original se coloca con la etiqueta 'exit' el salto que devuelve la ejecución al programa objetivo justo tras el punto de inyección, hacia la etiqueta 'returnhere'.
  6. El redireccionamiento hacia nuestro código se mete en la dirección donde estaba la instrucción original que queremos sustituir, que en este caso será la dirección '"treasure_adventure_game_1.0.exe"+C3D0'. El redireccionamiento se realiza sustituyendo la instrucción a modificar (y en la mayor parte de las ocasiones, algunas de las adyacentes posteriormente) por un salto al bloque de memoria reservado dinámicamente. El punto justo tras este salto se etiqueta con 'returnhere', y es donde volverá el flujo de ejecución tras ejecutarse lo que se inyecta en el bloque de memoria reservado, o sea, nuestro código y el código original sustituido.
Al deshabilitar el cheat, las instrucciones de la sección '[DISABLE]' devolverán todo a su estado original:
  1. Se libera el espacio reservado anteriormente a partir de la etiqueta 'newmem'.
  2. En el punto de inyección se vuelven a escribir las instrucciones originales.
Es importante entender como funciona el esquema de inyección de código ya que es posible que en ocasiones necesitemos corregir manualmente los que la plantilla ha insertado automáticamente.

Para simular lo que hicimos antes 'nopeando' la instrucción que actualiza el contador con el nuevo valor tras decrementarlo, tan solo tendríamos que borrar la instrucción 'MOV' que hay justo debajo de la etiqueta 'originalcode'. Como vimos antes, con esta solución no solo impedimos que se decremente el contador de vidas, si no también el de monedas, que tampoco estaría mal. El problema es que en algún momento del juego al que aún no hemos llegado, puede que también impida el decremento de otra variable distinta, y el que no se decremento podría provocar efectos indeseados en el juego.

Vamos a evitarlo a costa de complicar un poquito más el script, pero poco más. La idea sería verificar si cuando se va a ejecutar la instrucción 'MOV' que actualiza el contador tras el decremento, el registro EAX está apuntando al contador de vidas o no. Si está apuntando al contador de vidas nos saltamos la instrucción 'MOV' para evitar el decremento, y en caso contrario dejamos que se actualice.

La dirección donde se encuentra el contador de vidas la obtenimos anteriormente, y la tenemos en nuestra Cheat Table etiquetada como 'Puntero vidas'. Si desde el menú contextual de esa variable vamos a 'Change record', 'Address' se nos mostrará la secuencia de saltos de dicho puntero.

Dirección del puntero al contador de vidas
El puntero estático lo encontramos en:
"treasure_adventure_game_1.0.exe"+00059A7C
Al contenido de la dirección anterior sumamos el hexadecimal 0x268 y nos lleva al siguiente puntero, cuya dirección apunta por fin al objeto que gestiona al protagonista del juego.

A partir de la dirección de inicio del objeto, sumando el hexadecimal 0x28 llegamos al contador de vidas. Esta dirección es la que tendremos que comparar con el sujeto de la instrucción 'MOV' para ver si es el contador de vidas el que se va a decrementar.

El puntero anterior se podría expresar gráficamente tal que así:

Esquema punteros al objeto 'Protagonista'
Tanto la dirección del bloque de variables como el del propio objeto pueden cambiar de ejecución en ejecución. Lo que se mantiene es la localización del puntero inicial así como los desplazamientos relativos.

En una primera aproximación, el código podría quedar así:

Primera versión del script de inmunidad
Mediante cargas del contenido de direcciones de memoria, y adiciones a dichos contenidos, en un par de instrucciones se reconstruye la dirección final del contador de vida. Hay que destacar que puesto que al iniciarse el código original el registro EAX contiene la dirección del contador a decrementar menos ocho bytes, a la hora de generar dirección del contador de vidas, también restamos ocho. Por ello, la última operación de adición, en lugar de sumar 0x28 suma 0x20. Tras calcular en EAX la dirección del contador de vida, se mueve al registro EBX, se restaura el contenido original de EAX a la dirección de la variable que se iba a decrementar, se compara con EBX y salvo que sean iguales, se actualiza dicha variable.

El código se puede probar y funciona perfectamente. Desde el propio desensamblador de Cheat Engine podemos ver como queda el código en memoria del proceso tras habilitar el script, momento en el que Cheat Engine ejecuta el código de la sección '[ENABLE]', y también podemos comprobar como se restaura correctamente el código original al deshabilitarlo.

Pero Cheat Engine permite aún más. A la hora de referenciar un puntero, la herramienta admite una nomenclatura que simplifica mucho el tema ya que nos libra de tener que meter una repetitiva serie de parejas de instrucciones 'MOV' y 'ADD'. De la manera simplificada quedaría así:

Versión simplificada del script de inmunidad
La directiva 'define' permite sustituir un valor por una cadena. Al generar el código ensamblador, cada aparición de la cadena es sustituida por el valor definido. Al definir el valor, se usa la nomenclatura '[X+Offset]', que se traduce por el contenido de la dirección 'X+Offset'. El anidamiento de dicha nomenclatura permite en una sola línea, alcanzar el final de un puntero.

Desgraciadamente un bug, ya corregido en el repositorio de Cheat Engine pero aún no en el ejecutable ya compilado y disponible para descarga, impide usar esa nomenclatura directamente.

Además de instrucciones en ensamblador, Cheat Engine soporta también la inclusión de secciones en LUA, siendo esa la solución actual mientras no se genere una nueva versión con el bug corregido. El script final nos queda así:

Script final para inmunidad
La sección en LUA se encarga de calcular la dirección final y la mete en una sentencia 'define'. Lanzamos el juego, enganchamos la herramienta al proceso del juego con la opción 'Open Process', cargamos nuestro fichero .CT y hacemos doble click en la instrucción que guardamos en la ventana 'Advanced Options'. Se nos abrirá la ventana 'Memory Viewer' de la herramienta tal y como vimos anteriormente:

Código original previo a la inyección
Sin cerrar esa ventana, en el interfaz principal de la herramienta activamos la línea que corresponde a ese script en nuestra Cheat Table. Delante de nuestros ojos, se inyecta el código y lo que veíamos se transforma en:

Punto de inyección insertado
La instrucción 'MOV' se ha convertido en un 'JMP' a una dirección de memoria. Si vamos a esa dirección de memoria (click derecho, opción 'Go to address'), nos encontraremos nuestro código inyectado.

Código inyectado
El segundo operador de la instrucción 'CMP' es el valor que ha calculado la sección en LUA de nuestro script, y que podemos verificar que es el correcto. La instrucción 'JMP' del final nos devuelve al código original del programa, justo por debajo del punto de inyección. Solo nos queda desactivar el script en la Cheat Table y comprobar que todo se restaura correctamente.

Para ser completamente rigurosos nos ha faltado colocar un 'pushf' al inicio del código inyectado y su correspondiente 'popf' al final para conservar el estado de los flags al volver al código original, aunque en este caso no es necesario.

Generación de trainers

A esta alturas del tutorial, el ingeniero inverso que no conociera Cheat Engine estará completamente asombrado con las funcionalidades que ofrece esta herramienta gratuita y además de código abierto, o al menos eso le pasó a un servidor. Pues aunque ni mucho menos se han expuesto todas las posibilidades que ofrece, ni se van a exponer porque daría para medio libro, voy a tratar una más.
Hasta ahora, todo el trabajo lo está realizando Cheat Engine en segundo plano. Para poder utilizar una Cheat Table generada previamente (o descargada por internet) además de tener el juego o programa objetivo, necesitamos instalar la herramienta y ejecutarla.

Otra funcionalidad de la herramienta es generar lo que se conoce como 'trainer'. Una vez generados todos los trucos que queramos o podamos en Cheat Engine, y comprobado su funcionamiento, la herramienta nos permite generar un ejecutable con un sencillo interfaz que permite a un usuario que no tenga muchos conocimientos utilizar los trucos que incluyamos en el mismo, y sin necesidad de instalar la herramienta.

En el menú 'File' de Cheat Engine pulsamos la opción 'Generate generic trainer lua script from table'. Aparecerá una nueva ventana denominada 'Trainer generator'. En el listado de la izquierda iremos colocando los trucos que seleccionemos de la Cheat Table que hemos generado, asignando a cada funcionalidad un hotkey. Desde el asistente podemos cambiar algunos parámetros visuales de la interfaz que mostrará el trainer, o incluso añadir música de fondo y sonidos de notificación cada vez que se activa o desactiva uno de los trucos. Además del asistente para generar el trainer, se mostrará una simulación en tiempo real del interfaz que se generará reflejando cualquier cambio que introduzcamos en el asistente.

La información mínima que debe completarse es, además de los trucos que se deseen asignados a un hotkey, el nombre del proceso sobre el que debe operar el trainer. Dejamos el asistente como se muestra en la imagen:

Asistente de generación de trainers
El hotkey 'Ctrl+M'se ha configurado usando el puntero al contador de monedas de tal manera que se incremente en 100 unidades cada vez que se pulse. El segundo usa el segundo script que se mostró anteriormente, permitiendo habilitarlo y deshabilitarlo cada vez que se pulse la combinación 'Crtl+V'. Se ha asignado además una imagen con el botón 'Set Side Image' y se ha desactivado el checkbox que permite al usuario del trainer redimensionar la ventana del mismo. Pulsamos el botón 'Generate trainer' y tras definir dónde y con que nombre queremos generarlo, nos aparece una ventana adicional:

Opciones de generación del trainer
En esta ventana seleccionamos el tamaño del trainer a generar. 'Gigantic' generará un ejecutable de mayor tamaño, pero será un ejecutable independiente que incluirá todas las librerías necesarias. 'Tiny' generará un ejecutable mucho menor, pero precisa que Cheat Engine esté instalado. Debajo seleccionamos si el proceso objetivo es de 32 bits o de 64. En nuestro caso el juego Treasure Adventure Game es de 32 bits.  También seleccionamos que características especiales usa el trainer, que en nuestro caso no usamos ninguna. A la derecha se incluyen archivos extras que precisa el trainer, como archivos de imagen, música o sonidos. Solo hemos incluido una imagen para ser mostrada en el lateral de la interfaz del trainer.

Tras pulsar el botón inferior 'Generate' la herramienta ha generado en el directorio destino un ejecutable de casi 4Mb de tamaño y que muestra esta interfaz:

Interfaz del trainer generado
Tras unas cuantas pruebas comprobamos que todo funciona como debería. El trainer se engancha automáticamente al proceso definido y realiza las acciones configuradas al pulsar los hotkeys definidos.

Para los más creativos y experimentados, Cheat Engine ofrece una libertad absoluta a la hora de definir la interfaz del trainer al incorporar un diseñador de ventanas al estilo de Visual Basic. Al diseñador de ventanas se accede con el botón 'Design userinterface manually' de la ventana principal del asistente de generación de trainers.

Diseño avanzado interfaz del trainer

Conclusiones

Quedan muchas cosas en el tintero, en gran parte porque el que suscribe se considera un novato en el uso de la herramienta, y aún tiene muchas cosas que aprender. Lo que sí está claro es que es una herramienta que puede facilitar mucho las cosas al abordar otro tipo de tareas relacionadas con la ingeniería inversa, aunque el programa objetivo no tenga nada que ver con videojuegos. Localizar en qué parte del código se realizan cálculos de determinados valores, que usando herramientas más tradicionales como un debugger normal y un desemsamblador puede llevar su tiempo, con Cheat Engine es prácticamente inmediato. Una vez hecho el tedioso trabajo de localizar nuestra zona de código 'objetivo' ya podemos acudir a otras herramientas, aunque las funcionalidades adicionales que aporta Cheat Engine en gran parte de los casos puede hacer que no necesitemos nada más.

La Cheat Table generada durante este tutorial está disponible en este enlace.

12 comentarios:

  1. Muy buen tutorial gracias para gente novata es muy fácil de entender. Si hicieras lo mismo con algún juego de ps3 o seria el mismo proceso? Saludos

    ResponderEliminar
    Respuestas
    1. Cheat Engine es un programa para Windows, por lo que solo puede usarse con juegos que se ejecuten bajo Windows. Podrás usarlo con las versiones de PC de juegos de PS3, o si existiera un emulador para Windows que permitiera ejecutar directamente juegos de PS3 posiblemente también serviría.

      Eliminar
    2. Yo esque tengo una ps3 liberada con jailbreak tengo acceso a todo el sistema juegos online y tengo el proceso del juego en marcha en cheat engenie a través de ccapi o tmapi por eso te digo solo me falta saber buscar balas infinitas i cosas asi si hicieras tutorial en español en youtube creo q recibirás muchas visitas

      Eliminar
    3. Pues por mi respuesta te habrás dado cuenta de que no tenía ni idea de que existían esas herramientas para acceder remotamente a la memoria de la PS3. Ojiplático me he quedado...
      De todas maneras me extraña que "Cheat Engine" pueda acceder a los procesos en ejecución de una PS3 remota. Buscando información sobre el tema he encontrado una herramienta para Windows que se llama "NetCheat PS3", y que permite mediante ccapi o tmapi trastear en la memoria del proceso en ejecución en una PS3. Quizás sea ese el que estés usando, y no "Cheat Engine".
      Viendo este vídeo en inglés de "NetCheat", la base de funcionamiento es la misma que la de "Cheat Engine":
      https://www.youtube.com/watch?v=2dxuoLTA_Lk
      Quizás no tenga muchas funcionalidades de "Cheat Engine" como la inyección de código, pero lo que es la forma de buscar iterativamente las posiciones de memoria donde se almacena lo que queremos modificar sí que es lo mismo.
      Me lo dejo en el tintero por si algún día me quiero meter en el tema y sacar un tutorial, aunque antes soy yo el que tiene que leerse muchos tutoriales antes... ;)

      Eliminar
  2. Si pues es así a la ps3 se le puede hacer de todo. Y si es netcheat que se parece mucho al engenie si sabes hacer eso lo de ps3 será muy fácil. Yo tengo el e3 flasher es sencillo sino alguien en tu ciudad puede hacerlo el chip sirve para muchas. Una vez flashear a puedes dejar la en cex y instalar ccapi o en dex y instalar tmapi o ccapi también con eso ya manejas las ps3 desde el pc. Y volviendo a las direcciones offsets pues hay gente q los vende para juegos de ps3 y tiene ganancias de más de 100.000€... por eso quiero meterme en esto ya que dispongo de todas las herramientas listas para funcionar

    ResponderEliminar
    Respuestas
    1. Justo ese video en inglés tiene mi like lo vi hace 2 semanas cuando descarge el netcheat ps3

      Eliminar
    2. Tengo algún tutorial de ps3 modificada en mi canal de YouTube/jooniDj pasate si quieres

      Eliminar
    3. Había visto gente con un tinglado montado alrededor de suscripciones de pago para servicios de cheats en juegos flash de Facebook y similares. Imagino que existiendo ya la posibilidad en PS3 el que saliera gente con interés en sacarle dinero es una cosa segura.

      Sobre la facilidad para encontrar los cheats funcionales, al menos en Windows normalmente no suele ser sencillo. Si por ejemplo quieres cambiar las vidas y te quedan 5, es muy posible que el número "5" no sea lo que se guarda en memoria, y casi nunca son posiciones de memoria fijas sino que cambian en cada ejecución.... algunos pueden ser sencillos como el ejemplo de este tutorial pero otros son un quebradero de cabeza que al final no hay por donde cogerlo...

      La forma de buscar las posiciones de memoria de interés parece que en el Netcheat de PS3 es igual. Quizás no ofrezca tantas posibilidades de búsqueda como ofrece Cheat Engine pero la base es la misma. Si has pillado lo que he intentado explicar en el tutorial (puedes bajarte tanto el juego como el Cheat Engine para practicar los pasos del tutorial y entenderlo mejor), el que empieces a probar ya en la PS3 con Net Cheat no lo veo descabellado.

      Eliminar
  3. Hola me gusto lo que explicaste , quisiera hacerte unas preguntas nose si me pasas tu correo o numero asi hablando mil gracias

    ResponderEliminar
    Respuestas
    1. Pregunta por aquí. Salvo que sea muy fácil seguramente no lo sabré, pero hay más posibilidades de que alguien lo lea y sepa.

      Eliminar
  4. Hola... y como hago para poner un numero en negativo... por ejemplo coloco en el cambiar valor -1 o -9 o menos cualquier cosa y da algo como esto"4215426663155442"
    Ayudenme con esta cosa porfavor

    ResponderEliminar
    Respuestas
    1. A la hora de modificar las variables en memoria de una aplicación debes conseguir identificar el tipo de variable que la aplicación guarda en dichas posiciones de memoria. Es importante saber el tamaño. Por ejemplo, y siguiendo la nomenclatura de C, -1 en una variable "short" que ocupa 2 bytes contendrá "FFFF", pero en un "integer" de 4 bytes contendrá "FFFFFFFF".

      Pero no vale solo con saber qué tamaño de memoria ocupa. Supongamos que por ejemplo delimitamos que la variable ocupa 4 bytes. En 4 bytes se puede guardar un entero con signo, un entero sin signo o incluso un flotante, y el mismo contenido en esos 4 bytes puede tener un significado númerico distinto según se interpreten esos cuatro bytes como entero, entero sin signo o flotante. Siguiendo la nomenclatura de C, 2 bytes contiguos de memoria con el valor "FFFF" puede ser -1 si la variable es interpretada como "short" o 65535 si la variable es "unsigned short".

      Desconozco tu problema en concreto, pero si por ejemplo estás intentando introducir un entero negativo ("integer" en C) en una variable que la aplicación interpreta como entero sin signo ("unsigned integer"), nunca vas a conseguir que la aplicación lea correctamente el número negativo que intentas poner. Incluso es posible que la propia aplicación corrija inmediatamente el valor de una posición de memoria si ésta contiene un valor que considera incorrecto (esto podrías verlo colocando un.

      De igual manera cuando en Cheat Engine creas una variable que apunta a una posición de memoria, debes indicarle el tipo correcto de dicha variable que la aplicación va a interpretar, de lo contrario lo que Cheat Engine te mostrará como valor de dicha variable no tendrá nada que ver con el valor que la aplicación está tomando, y si desde Cheat Engine escribes en dicha variable lo que quieres escribir no tendrá nada que ver con lo que la aplicación interpretará.

      Hace dos años que no toco Cheat Engine y no recuerdo los tipos de variables que admite. En caso de que no admita el tipo que necesitas, siempre puedes intentar hacer la traducción tú a hexadecimal al escribir a memoria del proceso. Por ejemplo para convertir a valor negativo en hexadecimal puedes usar la calculadora de Windows en modo programador. Más sobre negativos en hexadecimal: https://systeek.blogspot.com.es/2011/10/tema-2-sistemas-numericos-y-stack.html

      Y sobre tipos de variables en C++ o C: http://www.zator.com/Cpp/E2_2_4.htm

      Eliminar