Crear un trainer: Hackeando juegos para hacer trampa (II de II)

En la primera parte de este post vimos como localizar las direcciones de memoria que nos interesaban y que valores deberían tener. En esta última parte haremos un "trainer", una pequeña aplicación en C# que se encargue de inyectar esos valores en memoria.

Para que esto funcione, necesitamos que nuestro programa pueda escribir en las direcciones de memoria de Microsoft Fury3. ¿Cómo logramos esto? Pues usando las siguientes funciones de la librería "kernel32.dll":

        #region DllImports

        [DllImport("kernel32.dll")]
        public static extern Int32 CloseHandle(IntPtr hObject);
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);
        [DllImport("kernel32.dll")]
        public static extern Int32 WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, uint[] lpBuffer, UInt32 nSize, IntPtr lpNumberOfBytesWritten);

        #endregion

Solamente son tres funciones: "OpenProcess", "WriteProcessMemory" y "CloseHandle". Su función básica es sencilla, por orden: acceder al proceso, escribir algo en alguna parte de su espacio de memoria, cerrar el manejador del proceso.

Lo primero que tenemos que hacer es saber si Fury3 está ejecutándose o no. Para ello, podemos echar mano de "System.Diagnostics.Process" que muy amablemente nos lo dirá:

        /// 
        /// Gets Fury3 process or null if it's not loaded
        /// 
        Func GetFury = () => Process.GetProcessesByName("FURY3").SingleOrDefault();

La función GetFury nos devolverá el proceso Fury o el valor null si no se está ejecutando. Bien, supongamos que se está ejecutando, lo siguiente sería poder escribir los valores que queremos en las direcciones que encontramos en el anterior post. Para ello podría servirnos un método de este estilo:

        /// 
        /// Writes a value to a specific memory address
        /// 
        /// Memory address in which we want to write
        /// Desired value for the address
        private void WriteAddress(IntPtr address, uint value)
        {
            var fury = GetFury(); //Look for Fury3
            var pHandle = OpenProcess(0x1F0FFF, 0, (UInt32)fury.Id); //Open it
            WriteProcessMemory(pHandle, address, new uint[] { value }, 4, (IntPtr)0); //Write the new value
            CloseHandle(pHandle); //Close
        }

Puede parecer lioso, pero si vais línea por línea veréis que no tiene mucha complicación. Recibimos la dirección de memoria en la que queremos escribir como primer parámetro, y el valor que queremos poner como segundo parámetro. Los cambios de tipo que hay son los que exigen las funciones de la librería "kernel32.dll".

Parece que lo tenemos todo listo para hacer las llamadas oportunas a WriteAddress. Yo he escrito estos tres métodos:

        #region Patches

        /// 
        /// Sets 8000 to Turbo
        /// 
        private void SetTurbo()
        {
            WriteAddress((IntPtr)0x0050E050, 0x00001F40);
        }

        /// 
        /// Sets health to its maximum
        /// 
        private void SetMaxHealth()
        {
            WriteAddress((IntPtr)0x004EBCA9, 0xFF);
        }

        /// 
        /// Sets all weapons to -1 in decimal (Byte, which means FFFFFFFF in 4Bytes)
        /// 
        private void SetAllWeaponsWithInfiniteAmmo()
        {
            WriteAddress((IntPtr)0x0050E048, 0xFFFFFFFF); //Weapon FFF
            WriteAddress((IntPtr)0x0050DFB0, 0xFFFFFFFF); //Weapon DC14
            WriteAddress((IntPtr)0x0050E040, 0xFFFFFFFF); //Weapon BFM
            WriteAddress((IntPtr)0x0050DFB8, 0xFFFFFFFF); //Weapon RFL20
            WriteAddress((IntPtr)0x0050E030, 0xFFFFFFFF); //Weapon Dom
        }

        #endregion

Ahora podríamos hacer una interfaz como esta:

Vale, no hay que ser un lince para darse cuenta de qué los botones simplemente tienen que llamar a los tres métodos anteriores pero, ¿para qué son las checkbox?

Nosotros podemos restaurar nuestra salud tantas veces como queramos, pero es un coñazo. Es mucho más práctico que la salud se restaure sola. Lo que haremos será crear un Timer que se ejecute cada X tiempo (100 milisegundos en mi caso) y vuelva a escribir los valores :D

No hay mucha miga, simplemente añadimos un timer y le asignamos el siguiente método:

        private void timer_Tick(object sender, EventArgs e)
        {
            var furyIsLoaded = GetFury() != null;
            foreach (Control x in Controls) x.Enabled = furyIsLoaded;
            if (furyIsLoaded)
            {
                if (chbGodMode.Checked)
                    SetMaxHealth();
                if (chbInfiniteTurbo.Checked)
                    SetTurbo();
                if (chbInifiniteWeapons.Checked)
                    SetAllWeaponsWithInfiniteAmmo();
            }
        }

Ya de paso, le he añadido que se desactiven todos los botones y checkboxs cuando Fury3 no esté abierto. Principalmetne porque de no hacerlo, si alguien pulsa un botón con Fury cerrado, el programa dará una bonita petada por no encontrar el proceso en el que intenta escribir :P

Solo queda un pequeño detalle, iniciar el timer. Yo he optado por iniciarlo en el constructor:

        public FuryTrainer()
        {
            InitializeComponent();
            timer.Start();            
        }

Todo listo :) Ya puedes jugar a Microsoft Fury3 haciendo uso de tus propios trucos. Te recomiendo cronometrar el tiempo que tardas en pasarte el juego completo usando el arma FFF, jejeje.

Por Carballude

Me llamo Pablo Carballude González, soy graduado en computación con master en HCI y Seguridad Informática. Actualmente trabajo para Amazon en Seattle como Software Developer Engineer. Soy de esas personas que no saben si los textos autobiográficos deben ser en primera o tercera persona. Lo intenté en segunda, pero no le entendí nada :P

9 comentarios

  1. Buenas, admito que no he buscado mucho acerca d esto, pero tu tutorial me fue como la seda. Logré cambiar valores no en ese juego que tomaste como ejemplo, pero sí en uno que me interesaba. Ahora, lo de hacer el programita, sólo se puede hacer en C#? y si es así, hay algún compilador ligerito xD que pueda utilizar? Pa que me pases algún link de donde lo pueda descargar.
    Gracias, tío. Reitero, está alucinante tu tutorial y lo de hacer trainers. xD
    Un abrazo y suerte en todo. :D

  2. Incluso podrías se podría saltar la primera parte de utilizar apps de terceros implementando ReadProcessMemory, lo malo es que cada vez nos lo ponen más difícil para los que nos gusta hacernos nuestros cheats, desde hace mucho tiempo que tanto Read como WriteProcessMemory no funcionan con los sistemas anti-cheat, nos metemos con el hookeo de las dlls y lleva mucho más tiempo.

    Por cierto, me gusta como escribes, saludos ;)

  3. Hola, tengo una pregunta haber si me puedes ayudar, cada vez que se inicia un juego las direcciones en memoria cambian. Como puedo hacer el seguimiento de estos cambios? asi solo dejar que el trainer se ocupe de todo cada vez que inicie el juego. Espero tu respuesta, muy bueno tu tutorial

  4. buenas, me han dicho que se puede una vez encontrado las direciones con el CheatEngine tiene la funcion de generar ya un trainer con teclans hot. me podrias decir como? no encuentro informacion

  5. Hola me gusto tu tutorial, pero tengo un problema para encontrar un Adrees, el del cronometro siempre que lo busco no me aparece, te apreciaria que me pudieras ayudar con algun consejo
    De antemano gracias

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *