Prólogo

Casi Hacker

Al momento de hablar de hacking, casi todo el mundo se imagina el clásico hacking ético, intentando vulnerar redes, sus MITM, típico que salta Kali Linux, claves de facebook, etc… Esa es la primera imagen que se le viene a la gente, un hacking, que en verdad, a mi poco y nada me interesaba.

Y esto se puede evidenciar aún más, al momento de hacer ese tipo de búsquedas en algún motor como google, abunda el contenido donde se enseña a usar este tipo de técnicas y herramientas, lo que hizo que me tardase en por fin encontrar lo que siempre estuve buscando.

Bajo nivel, C, y otras drogas

Mi primera experiencia en la programación, fue cuando estaba en 4to medio y la Pontificia Universidad Católica de Valparaíso hizo un curso para estudiantes de programación. Allí enseñaron C, y uff, a pesar de lo mucho que me costó entender los punteros, fue un lenguaje que amé desde el minuto 0. Molestaba frecuentemente a los tutores, llegaba a la casa a seguir aprendiendo, típico, hice la calculadora básica, lo recuerdo con mucho afecto.

¿Por qué importa esto? porque C es un lenguaje de bajo nivel, y es lo que más me llamaba la atención, manejo de memoria, punteros, arreglos pelados, etc.

Desde ese entonces, siempre quise profundizar mis conocimientos en esta área, aprender más cosas sobre como funciona un computador a nivel “puro”, aprender Assembly, aprender sobre procesos, etc. y nunca lo hice, hasta que un día de forma aleatoria, me metí a Cheat Engine, y me di cuenta de lo realmente poderosa que es esta herramienta.

Game Hacking, Alto nivel

Cheat Engine

Cuando chico, obvio que me encantaba jugar, pero rara vez completaba los juegos (mi backlog es un poco… grande). Además de jugar, me gustaba mucho usar claves jaja, pero no siempre todos los juegos tenían de éstas o no había una que hacía lo que yo quisiese, y por esas búsquedas de Google me encontré con el famoso Cheat Engine, que en ese entonces, no tenía ni idea como realmente funcionaba, simplemente ocupaba su feature más básica, escanear valores y modificarlos.

Así fue como conocí Cheat Engine, pero después de harto tiempo dejé de usarlo porque jugaba más que nada cosas online. Fast forward algunos años, decidí instalarlo de nuevo, porque, why not?, y ahí fue cuando me di cuenta de lo que me perdí cuando era chico.

Intro to reverse engineering: Memory & Assembly

Cheat Engine, en resumen, es un manipulador de memoria. Con su scanner, puedes ir descartando resultados que no corresponden al valor que tu buscabas, para finalmente encontrar lo que quieres y modificarlo, dinero, vidas, etc. Pero CE daba mucho más que eso, también sirve como debugger, y más interesante aún, inyectar código en runtime a un proceso externo, y ahí fue cuando todo escaló.

¡Sorpresa! puedes ver el código del proceso cargado en memoria, manipularlo como quieras, también tienes acceso a la parte de datos, al stack, ¡a todo el espacio reservado por el juego! Las posibilidades son infinitas, puedes modificar mecánicas, valores, agregar condiciones nuevas, etc. El límite es el cielo.

Mi primer Cheat para The Witcher 1

Fue ahí entonces cuando decidí inmediatamente, comenzar a aprender Assembly, uno de los lenguajes más temidos por los programadores en general.

Gasté horas y horas, leyendo, investigando, aprendiendo sobre la arquitectura actual de procesadores, los registros, convenciones, y fue todo muy mágico. Re-descubrí el amor por la informática, me volví a enamorar, cual niño chico con juguete nuevo.

Definitivamente, abrí muchas puertas del conocimiento, el área que tanto me interesaba pero nunca le pude dedicar tiempo, al fin estaba al alcance de mi mano, un área bastante niche, que, sin dudas, me hace muy feliz.

Gasté mucho tiempo, en distintos juegos, haciendo pequeñas modificaciones para hacerlo más entretenido (hacer al personaje más fuerte, chiquitito, hacerlo volar, etc), pero sin duda una de las cosas que más me ha entretenido hasta ahora, es hacer freecam, o en el fondo, desvincular al personaje de la cámara, para poder explorar el mundo que los rodea

Freecam para Zelda: Breath of the Wild

Cheat Engine sin lugar a dudas es una herramienta muy poderosa, pero el hambre por el conocimiento no terminó allí.

Game Hacking, Bajo nivel

Es obvio, que si existe un software que actualmente cumple una función, tu también puedes hacerlo manualmente, i.e. Reinventar la rueda. No siempre es práctico, a nivel laboral es un gesto que generalmente hay que evitar, pero para aprender, ésta es una excelente instancia.

Aprendiendo sobre la WinAPI, y los procesos.

Una vez ya habiendo experimentado bastante con Cheat Engine, era hora de dar el siguiente paso: hacer algo completamente desde 0. Es un desafío gigantezco, ya que implica quitar esa gran capa de abstracción que se encargaba de muchas cosas que ocurrían por debajo e implementarlas nuevamente, entendiendo qué hace cada componente.

Para esto, fue necesario aprender sobre la API de Windows, como funcionan los procesos, y como se trabaja con memoria a nivel de sistema operativo. Para esto, habían dos caminos: hacerlo de manera interna o externa. Básicamente, la diferencia es que al hacerlo de manera interna, se debe inyectar un DLL y el espacio de memoria se compartiría con el proceso, en cambio, de manera externa, los espacios de memoria son distintos, por lo tanto es necesario solicitar permisos para acceder y/o modificar la memoria de un proceso ajeno.

Decidí irme por el externo, ya que, es la forma más fácil de compartir binarios, sin necesidad de tener que modificar los ejecutables originales de los juegos objetivos.

ASM inline, compilador open-source e inyección.

Por primera vez en mi vida, aprendí que existe el Assembly Inline, es decir, que una función se puede compilar en Naked Assembly dentro de C/C++, y, sorprendentemente, el compilador mingw-64 tiene mejor soporte que el compilador de Windows mismo, ya que permite compilar ASM inline para 64 bits.

Habiendo notado la existencia de ASM inline, y habiendo entendido como jugar con la API de Windows, era hora de la entretención: Crear un proyecto donde se inyecte código para que funcione como yo quiera.

Primer proyecto bajo nivel: Yakuza 0 freecam

Después de muchas semanas de investigación, era hora de poner a prueba todo el conocimiento adquirido. El objetivo era ahora: Escribir un programa en C++ que permita manipular la cámara del juego independientemente, sin necesidades de un proceso externo como Cheat Engine.

De todas formas, para concretar este objetivo, se utilizó Cheat Engine igual debido a que es un excelente debugger, permitía ver si los cambios que estaba haciendo a la memoria correspondían a lo que deseaba, y podía revertirlos modificando la memoria manualmente de ser necesario.

Finalmente, luego de muchas pruebas y error, y demasiados segfaults, logré mi objetivo: inyecté una función escrita en asm inline al proceso del juego, que me permitía correr una rutina propia para obtener los valores que yo quería.

El funcionamiento es bastante simple:

  1. Reservo un bloque de memoria en el proceso externo
  2. Cargo la función escrita en Assembly en ese bloque
  3. Busco un segmento de código donde se trabaje con la cámara, y le inyecto la desviación a mi código escrito
  4. El código escrito manualmente escribe la dirección actual de la cámara en el bloque asignado, para facilitar el acceso
  5. Mi proceso guarda esa dirección para consultarla frecuentemente
  6. El proceso originalmente sale de mi inyección, pero entrará cada vez que pase por esa parte del código

Con esto, básicamente me aseguro de obtener siempre el puntero correcto de la cámara ya que es el mismo que está ocupando el juego, y así, puedo manipular la cámara a gusto.

__declspec(naked) void shellcode()
{
    // rax -> jmpBackAddress
    // rax+8 -> camera pointer location
     __asm__ volatile (
         ".intel_syntax noprefix;"
         "lea r11,[rip+0x200];"
         "push rbx;"
         "mov rbx,rcx;"
         "mov [r11+8],rbx;"
         "pop rbx;"
         "movaps xmm1,[rcx+0x00000320];"
         "jmp [r11];"
         "nop;nop;nop;nop;" // ending function signature
        ".att_syntax;"
     );

}

void Camera::resolve_camera_pointers() {

    void *p_func = (void *)shellcode;
    int f_size = 0;
    // calc the size of the function
    for(f_size = 0;
	    *((UINT32 *)(&((unsigned char *)p_func)[f_size])) != 0x90909090;
	    ++f_size);

    // try allocate near module
    void *p_shellcode = nullptr;
    int instruction_size = 7;
    for (int i = 1; p_shellcode == 0; i++)
        p_shellcode = VirtualAllocEx(process,
	(BYTE*)(moduleAddress - (0x1000 * i)),
	f_size,
	MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    // absolute jmp
    uintptr_t moduleInjectionAddress = (moduleAddress + this->jumpOffset);
    uintptr_t jmpBackAddress = moduleInjectionAddress + instruction_size;

    // inject the shellcode
    WriteProcessMemory(process, p_shellcode, (LPCVOID)shellcode, f_size,
	    nullptr);

    // 0x207 -> jmp back address
    // 0x207 + 0x8 -> camera address
  
    // inject the jmp 
    WriteProcessMemory(process, p_shellcode + 0x207, &jmpBackAddress, 8,
	    nullptr);
  
    // read the camera pointer
    pCamera = (uintptr_t)(p_shellcode + 0x207 + 0x8);
    
    std::cout << "pCamera " << pCamera;
    std::cout << " Assigned address " << std::hex << p_shellcode << std::endl;

    // this function hooks with the process the jump.
    hookFunction(process, moduleInjectionAddress, (uintptr_t)p_shellcode,
	    instruction_size);
}

Ya contento con lo logrado, grabé un video para demostrar su funcionamiento, y lo subí a la comunidad del juego, con una super buena recepción (Al menos en reacciones jaja).

Freecam para Yakuza 0 en C++

Reacciones en Discord

Conclusión: ¿De qué me sirve el Game Hacking?

La gente podría pensar, que perdí todo este tiempo ya que solo lo hice para “hackear un juego”, pero en verdad, el conocimiento adquirido va mucho más allá. Todo lo que leí, me enseñó la importancia de los memory overflows, de el checkeo de la memoria de los procesos, de como funciona el stack, aprendí ASM x86_64, sobre la API de Windows, en fin, muchos tópicos que se pueden extrapolar fácilmente a seguridad/funcionamiento del sistema operativo, y qué mejor que hacerlo con algo que me encanta: Jugar.

Me he entretenido mucho aprendiendo sobre esta área, espero seguir explorándola, y atraer a más gente sobre este mundo, ya que no hay mucha gente que sabe de esto, y es una parte interesante del hacking.

Algunas fuentes de conocimiento

  1. Guía de Stephen Chapman sobre Cheat Engine
  2. Guided Hacking
  3. Memory api DOC