Saltar al contenido

Conceptos básicos de Auto Assembler: cómo entender los scripts de inyección AOB en Cheat Engine

Cheat-Engine.net Por Cheat-Engine.net Lectura de 8 min 34 vistas

Qué es una entrada de script, cómo funcionan [ENABLE] y [DISABLE], y un recorrido línea por línea por la plantilla de inyección AOB de Cheat Engine: aobscanmodule, alloc, labels, símbolos y comodines.

La mayoría de las entradas útiles de las tablas de trucos compartidas no son simples valores, sino scripts: salud infinita, sin recarga, fabricación gratis. Están escritos en el Auto Assembler de Cheat Engine, un pequeño formato de scripting que combina ensamblador x86 con comandos para encontrar y modificar código. Esta guía explica qué hace un script así, repasa la plantilla de inyección AOB que Cheat Engine genera por ti y cubre las reglas que hacen que un script sea fiable.

Le sacarás más provecho si ya sabes cómo encontrar un valor y qué es un puntero; la guía de escaneo de punteros cubre ese contexto. Los scripts cambian el código de un juego en ejecución, así que úsalos solo en juegos de un jugador y sin conexión, guarda la partida antes de probar y conserva copias de seguridad de tus archivos de guardado.

Qué es una entrada de script

Una entrada de script es un elemento de la lista de direcciones cuya columna Valor muestra <script>. En lugar de apuntar a un valor, contiene código de Auto Assembler. Al marcar la casilla Activo de la entrada se ejecuta la sección [ENABLE] del script; al desmarcarla se ejecuta la sección [DISABLE]. La guía sobre cómo usar una tabla de trucos lo explica desde el lado del usuario.

El script típico no cambia un valor una sola vez. Cambia la propia instrucción del juego que escribe el valor, así que el efecto es permanente mientras el script esté activo. Por ejemplo, la instrucción que guarda tu nueva salud después de recibir daño puede redirigirse a código que guarde el máximo.

Los scripts tienen una gran ventaja sobre las direcciones simples: localizan su objetivo buscando un patrón de bytes en el código del juego, así que funcionan después de reiniciar sin ningún puntero. El inconveniente es que dependen de que ese código no cambie, lo que los ata a una versión del juego.

[ENABLE] y [DISABLE]

Todo script que se puede activar y desactivar tiene ambas secciones. [ENABLE] encuentra el código, asigna memoria para el código nuevo y escribe un salto desde la instrucción del juego hasta el código nuevo. [DISABLE] lo deshace todo: vuelve a escribir los bytes originales, elimina los nombres que registró y libera la memoria. Un [DISABLE] bien escrito deja el juego exactamente como estaba. Si falta o está mal, al desmarcar la entrada el juego queda modificado o roto hasta que lo reinicies.

Cómo encontrar la instrucción y generar la plantilla

  1. Encuentra el valor que quieres controlar y agrégalo a la lista de direcciones.
  2. Haz clic derecho sobre él y elige Find out what writes to this address. Haz que el valor cambie en el juego. Aparecerán una o más instrucciones en la lista.
  3. Selecciona la instrucción y ábrela en el desensamblador (Memory Viewer).
  4. Con esa instrucción seleccionada en el Memory Viewer, abre Tools → Auto Assemble.
  5. En la ventana de Auto Assemble, elige Template → AOB Injection. Confirma la dirección y acepta o cambia el nombre del símbolo, que por defecto es INJECT.
  6. Edita el script y luego usa el menú File de la ventana para asignarlo a la tabla de trucos actual. Aparecerá en la lista de direcciones como una nueva entrada de script.

La plantilla de inyección AOB, línea por línea

A continuación hay un ejemplo de la estructura que produce la plantilla. El nombre del proceso, el símbolo y los bytes son inventados para ilustrar; este no es código de ningún juego real.

{ EXAMPLE STRUCTURE ONLY - not code for a real game.
  Process: game.exe   Symbol: INJECT   Bytes: made up }

[ENABLE]
aobscanmodule(INJECT,game.exe,89 83 F0 00 00 00 48 8B 5C 24 ??) // should be unique
alloc(newmem,$1000,INJECT)

label(code)
label(return)

newmem:
  mov eax,#999              // your change: store 999 instead

code:
  mov [rbx+000000F0],eax    // the original instruction
  jmp return

INJECT:
  jmp newmem
  nop
return:
registersymbol(INJECT)

[DISABLE]
INJECT:
  db 89 83 F0 00 00 00      // original bytes: mov [rbx+000000F0],eax

unregistersymbol(INJECT)
dealloc(newmem)

aobscanmodule

aobscanmodule(INJECT,game.exe,...) busca el patrón de bytes en la memoria del módulo game.exe y, si lo encuentra, define el nombre INJECT como la dirección donde empieza. Limitar la búsqueda a un módulo es más rápido y evita falsas coincidencias en otras partes. Existen comandos relacionados: aobscan busca en toda la memoria y aobscanregion busca entre dos direcciones. Si no se encuentra el patrón, el script no se activa y muestra un error, que es el síntoma habitual después de una actualización del juego.

alloc

alloc(newmem,$1000,INJECT) reserva 0x1000 bytes de memoria para tu código y lo llama newmem. El tercer parámetro le pide a Cheat Engine que lo asigne cerca de INJECT. En juegos de 64 bits esto importa: un jmp corto de 5 bytes solo alcanza unos 2 GB en cualquier dirección, y asignar la memoria cerca hace que el salto sea lo bastante pequeño para caber en lugar de la instrucción original.

label

label(code) y label(return) declaran nombres para posiciones que se definen más abajo. code marca dónde se vuelve a ejecutar la instrucción original; return marca la instrucción justo después de la modificada, donde continúa la ejecución.

newmem y code

Todo lo que hay bajo newmem: es tu código, seguido de la instrucción original bajo code:. En el ejemplo, mov eax,#999 pone el registro en 999 (el # indica un número decimal), y luego la instrucción original mov [rbx+000000F0],eax lo guarda, así que el valor siempre se escribe como 999. Por último, jmp return vuelve al código del juego.

INJECT: jmp newmem

En la dirección encontrada, el script sobrescribe la instrucción original con jmp newmem. El salto ocupa 5 bytes, pero la instrucción original aquí tenía 6 bytes, así que un nop rellena el byte sobrante; de lo contrario, el procesador intentaría ejecutar media instrucción. La plantilla hace esta cuenta por ti. return: se coloca justo después, así que marca la siguiente instrucción sin tocar.

registersymbol y unregistersymbol

registersymbol(INJECT) hace que el nombre INJECT sea conocido globalmente en Cheat Engine. Eso es lo que permite que la sección [DISABLE], que se ejecuta después y por separado, encuentre la misma dirección sin volver a escanear. También permite que otras entradas se refieran a él. unregistersymbol(INJECT) en [DISABLE] elimina el nombre.

Restaurar los bytes originales y dealloc

En [DISABLE], INJECT: seguido de db 89 83 F0 00 00 00 vuelve a escribir los bytes originales sobre el salto, lo que restaura exactamente la instrucción del juego. Después, dealloc(newmem) libera la memoria que contenía tu código. El orden importa: restaura primero el salto, para que el juego ya no use newmem cuando se libere.

Comodines y por qué importan las firmas únicas

El patrón de bytes de aobscanmodule se llama firma. Tiene que cumplir dos condiciones:

  • Debe ser único. Si el patrón aparece más de una vez, el script modifica la primera coincidencia, que puede ser una función completamente distinta. Así es como los scripts hacen que los juegos fallen o cambian lo que no deben. La plantilla agrega el comentario "should be unique" como recordatorio.
  • Debe resistir cambios pequeños. Algunos bytes cambian fácilmente entre versiones del juego o incluso entre ejecuciones: desplazamientos dentro de las instrucciones, direcciones relativas de llamadas y saltos, y constantes incrustadas. Reemplazar esos bytes por comodines ?? permite que el patrón siga coincidiendo cuando solo cambian esos detalles.

Estos dos objetivos se contraponen. Con muy pocos bytes el patrón coincide en muchos lugares; con demasiados comodines vuelve a ser genérico. Un enfoque práctico es conservar los bytes de los opcodes, poner comodines en los desplazamientos y direcciones variables, e incluir unos pocos bytes de las instrucciones siguientes como contexto. Luego comprueba que el patrón sea único: en la ventana principal, configura el Tipo de valor como Array of byte, pega el patrón y escanea con las opciones de memoria configuradas para incluir memoria ejecutable. Lo que quieres es exactamente un resultado. El creador de firmas AOB te ayuda a convertir bytes copiados en un patrón con comodines y a detectar qué bytes probablemente cambien.

Cómo probar un script

  • Guarda la partida y conserva una copia de seguridad de tu guardado antes de la primera prueba.
  • Activa el script, comprueba el efecto, luego desactívalo y confirma que el juego vuelve a comportarse con normalidad.
  • Actívalo y desactívalo varias veces. Un script que falla en la segunda activación suele tener una sección [DISABLE] que no deshace por completo [ENABLE].
  • Ten cuidado con las instrucciones compartidas. La instrucción que escribe tu salud también puede escribir la salud de los enemigos; en ese caso tu cambio afecta a todos, y tendrás que distinguir los casos antes de cambiar nada.

Cuando un script funcione, ponle a la entrada una descripción clara y guarda la tabla. Cuando el juego se actualice y el script no se active, la firma es lo primero que debes revisar.

Comentarios

0
Respondiendo a

Nunca se muestra públicamente.

Un moderador revisa los comentarios antes de que aparezcan.

Aún no hay comentarios

Sé el primero en compartir tu opinión.