Вы находитесь на странице: 1из 46

Josu Rojas Silva

CracksLatinoS

Aula Steve Jobs


Josu Rojas Silva

GameHacking: CodeCave in Assembly


Tcnica que cambia el flujo de ejecucin, hacia una rutina previamente diseada.

Quin Soy?
The Art of Reverse Engineering

Cmo llegu aqu?


1 ao con temas de GameHacking. 6 meses con Ing. Inversa. Conocimientos en ASM, Java, Electrnica Analgica, y ms Present 2 Papers: -The Art of Reverse Engineering. -GameHacking: CodeCave in Assembly.

Qu es CodeCave?
Una tcnica muy usada en el GameHacking, un CodeCave, se describe literalmente a su traduccin, es hacer un hueco, tnel o cueva dentro del cdigo normal, cambiando el flujo, hacia una rutina arbitraria, de esa manera se modifica el compartimiento normal, de una aplicacin (en la demostracin).

Inicio

Qu es CodeCave?

Final

Qu veremos en esta charla?


Dos formas de hacer un CodeCave, la primera usando opcodes y reservando espacio en la memoria, esto puede ser muy tedioso si tenemos un cdigo largo, la segunda es la manera fcil ser saltar hacia nuestro propio espacio (para usar instrucciones), donde tendremos la rutina arbitraria.

Planteando el Problema
Ya mencionamos cmo funciona el CodeCave, pero, en qu momento debemos usarlo?

Un ejemplo. Al realizar una accin en algn game, esta nos disminuye la vida, pero, podramos cambiar esa accin por otra?

Pasos Bsicos
1er Paso: Obtener la direccin indicada que modificar el flujo haca una rutina creada por nosotros. 2do Paso: Calcular el desplazamiento desde donde se har el cambio de flujo, hasta nuestra rutina. 3er Paso: Crear la rutina que comportamiento arbitrariamente. modificar el

4to Paso: Regresar al flujo, como normalmente lo hara la aplicacin, como si nada hubiera pasado.

Funcionamiento del CodeCave

Funcionamiento del CodeCave

Funcionamiento del CodeCave


En pocas palabras si por alguna accin la vida disminuye en 1, con el CodeCave podemos modificar el flujo, hacer que valla hacia nuestra rutina y en vez de disminuir, incrementar en 2 la vida, esto es en pocas palabras, el concepto del CodeCave.

PRIMERA PARTE (usando opcodes y reservando espacio)


1er Paso. Obtener la direccin indicada.
Primero necesitamos encontrar la direccin que disminuya la vida en 1. Para esto podemos usar un debugger cualquiera, o para mayor facilidad el CheatEngine (desde ahora CE), que fue concebido para estas labores.

1er Paso. Direccin/Address


Usaremos est instruccin ficticia y diremos que la instruccin que disminuye la vida es dec [ebx+00000454]:
004226BC - FF 8B 54040000 - dec [ebx+00000454] 004226C2 - 8B B3 44040000 - mov esi,[ebx+00000444]
Address Opcodes Instrucciones

Y Nuestro objetivo es cambiar la instruccin dec [ebx+00000454] (es la cual decrementa en 1 la vida) por add [ebx+00000454], 2 (es la cual sumar en 2 la vida).

2do Paso. Calculando el Desplazamiento


2do Paso. Calcular el desplazamiento hacia nuestra rutina arbitraria.

Necesitamos encontrar el desplazamiento que hay entre la instruccin que disminuye la vida hasta nuestra rutina.

004226BCh + Offset = Direccin donde comienza nuestra rutina

2do Paso. Calculando el Desplazamiento


El cdigo que resuelve esto:
mov edx, dword ptr [lpMemory] mov eax, 004226BCh sub edx, eax sub edx, 5

Siendo lpMemory la variable que contiene la direccin donde comienza nuestra rutina.

2do Paso. Calculando el Desplazamiento


mov edx, dword ptr [lpMemory] mov eax, 004226BCh sub edx, eax

Calculamos el desplazamiento que hay de la direccin, 004226BCh hacia la direccin contenida en lpMemory, el desplazamiento lo tenemos en EDX.

2do Paso. Calculando el Desplazamiento


sub edx, 5

Restamos los 5 bytes del JMP (JUMP, es el salto que va a cambiar el flujo hacia nuestra rutina) esta ocupa 5 bytes y la tenemos que restar.

EDX = Desplazamiento u Offset.

3er Paso. Rutina


3er Paso: Crear la rutina que comportamiento arbitrariamente. modificar el

Esta Rutina contiene tanto la rutina que cambia una instruccin, as como el cdigo que reserva espacio del HEAP, lo cual veremos en el siguiente cdigo:

3er Paso. Rutina


invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, 512 Reservando mov [hMemory], eax espacio del invoke GlobalLock, eax Heap! mov [lpMemory], eax invoke VirtualProtect, 004226BCh, 6, PAGE_EXECUTE_READWRITE, offset oldProtect mov edx, dword ptr [lpMemory] Calculando mov eax, 004226BCh el sub edx, eax Desplazamiento sub edx, 5 mov byte ptr [eax], 0E9h mov dword ptr [eax + 1], edx mov byte ptr [eax + 5], 90h mov edx, dword ptr [lpMemory] mov word ptr [edx], 8383h mov dword ptr [edx + 2], 00000454h mov byte ptr [edx + 6], 02h Reemplazando una instruccin por otra Escribiendo la rutina arbitraria

3er Paso. Rutina


Lo primero que hacemos es reservar memoria donde podamos escribir; el puntero hacia dicho lugar en memoria lo contiene la variable lpMemory.

invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, 512 mov [hMemory], eax

Especificamos el flag GMEM_MOVEABLE, este deja a Windows mover el bloque de memoria, para consolidar la memoria. La bandera (flag) GMEM_ZEROINIT le dice a GlobalAlloc que rellene el nuevo bloque de memoria reservado con ceros.

3er Paso. Rutina


invoke GlobalLock, eax mov [lpMemory], eax

Cuando GlobalAlloc vuelve satisfactoriamente, EAX contiene el manejador (handle) al bloque de memoria reservado. Le pasamos este manejador (handle) a la funcin GlobalLock que nos devuelve un puntero al bloque de memoria.

3er Paso. Rutina


invoke VirtualProtect, 004226BCh, 6, PAGE_EXECUTE_READWRITE, offset oldProtect

Esto lo hacemos por seguridad ya que no todas las pginas de memoria tienen permiso de lectura o escritura.
mov edx, dword ptr [lpMemory] mov eax, 004226BCh sub edx, eax sub edx, 5

Calculando el Desplazamiento

Explicado en el Paso2.

3er Paso. Rutina


mov byte ptr [eax], 0E9h mov dword ptr [eax + 1], edx A partir de aqu estamos modificando la instruccin dec [ebx + 00000454], por un JMP [lpMemory].
0E9h (Opcode) = JMP EDX = Desplazamiento hacia la direccin allocada ([lpMemory]).

mov byte ptr [eax + 5], 90h


Como la instruccin dec [ebx + 00000454], tiene de tamao 6 bytes, el JMP 5 bytes, hay una que sobra y esa la NOPeo.

3er Paso. Rutina


mov edx, dword ptr [lpMemory] Pasamos el puntero de nuestro espacio de memoria reservada a EDX. mov word ptr [edx], 8383h Cambiamos los primeros opcodes FF 8B a 83 83, siendo los opcodes 83 83 = add [ebx. mov dword ptr [edx + 2], 00000454h Seguimos armando la instruccin dndole el offset 00000454, y tendramos: add [ebx + 00000454]

3er Paso. Rutina


mov byte ptr [edx + 6], 02h
Esta ltima instruccin es el valor con que ser sumando el primero operando, con esto tendramos la instruccin de esta manera: add [ebx + 00000454], 2

Cambi la instruccin : dec [ebx + 00000454] por add [ebx + 00000454], 2

3er Paso. Rutina


Muchos dirn porque ha puesto 00000454 del offset y no 54040000, y as para los dems opcodes, pues fcil LittleEndian tiene la culpa, es el formato en que se almacenan los datos, en palabras fciles lo que hace el microprocesador es almacenar los valores pero al revs (Little Endian es ese formato).
Ejemplo: 004226BC - FF 8B 54040000 - dec [ebx+00000454] Donde el offset que ha sido almacenado es 54040000. Entonces si yo muevo el valor de 00000454, lo que hace el microprocesador es voltear ese valor a 54040000, y como estamos trabajando con opcodes, ser interpretado como 00000454.

4to Paso. Regresando el Flujo


4to Paso: Regresar al flujo, como normalmente lo hara la aplicacin, como si nada hubiera pasado.

Calculando el tamao que ocupamos en la rutina arbitraria, obtendremos el desplazamiento desde el final del cdigo arbitrario, hasta la address que ejecutara normalmente el GAME.

4to Paso. Regresando el Flujo


lea eax, byte ptr [edx + 12] mov ecx, 004226C2h sub ecx, eax mov byte ptr [edx + 7], 0E9h mov dword ptr [edx + 8], ecx
Calculando el Offset para regresar el flujo

lea eax, byte ptr [edx + 12] Ocupamos 7 bytes en la anterior instruccin, y tenemos que sumarle 5 bytes del JMP del regreso del flujo, en total 12 bytes usaremos y la direccin final de la rutina est en EAX. EAX = Direccin final de la rutina arbitraria.

4to Paso. Regresando el Flujo


mov ecx, 004226C2h La siguiente direccin que se ejecutara como si nada hubiera pasado: 004226BC - FF 8B 54040000 - dec [ebx+00000454] 004226C2 - 8B B3 44040000 - mov esi,[ebx+00000444]

Obtenemos el desplazamiento desde el final de sub ecx, eax nuestra rutina hasta la direccin 004226C2h.
mov byte ptr [edx + 7], 0E9h mov dword ptr [edx + 8], ecx
Procedimiento igual al 3er Paso

PRIMERA PARTE - Resumen


En resumen esto fue lo que hicimos:
004226BC - E9 C898E3FF - JMP 00293930; Addy reservada en el HEAP 00293930 - 8383 54040000 02 - ADD DWORD PTR DS: [EBX+00000454], 2 00293937 - E9 58900500 - JMP 004226C2

Hicimos un JMP, hacia nuestra rutina (CodeCave), ejecutamos la instruccin que modifica el comportamiento arbitrariamente, y regresamos el flujo, como si el comportamiento de la aplicacin no hubiera cambiado, as nos evitamos del crash.

PRIMERA PARTE - Cdigo

Cdigo

SEGUNDA PARTE (Usando nuestro propio espacio)


Despus de hacer crear la primera parte, est segunda fue concebida al da siguiente luego de pensar porque hacer todo en opcodes y no usar mi propio espacio, quien sabe porque no se me ocurri esto antes, o estaba tan absorto depurando el cdigo anterior, que no tena espacio para pensar en otra cosa, pero pensando que lo primero no es factible para cdigos largos, as qu se concibi lo siguiente.

Les pego el code, gran parte ya est explicado, los pasos son los mismos, lo nico que cambia es el 3er Paso y 4to Paso, veamos como.

Segunda Parte - Cdigo


AllocMemory PROC
invoke VirtualProtect, 004226BCh, 6, PAGE_EXECUTE_READWRITE, offset oldProtect

mov edx, offset szCodeCave mov eax, 004226BCh sub edx, eax sub edx, 5
mov byte ptr [eax], 0E9h mov dword ptr [eax + 1], edx mov byte ptr [eax + 5], 90h
ret
AllocMemory ENDP

Calculando el Desplazamiento (2do Paso) Pisando la instruccin por un JMP haca szCodeCave (3er Paso)

Segunda Parte - Cdigo


szCodeCave PROC
;pushad add dword ptr [ebx + 454h],2 ;popad mov esi, 004226C2h jmp esi ;push 004226C2h ;ret szCodeCave ENDP
Escribiendo la rutina Arbitraria (3er Paso)

Jump Indirecto, para regresar al flujo (4to Paso)

3er Paso. Rutina


Lo que hacemos ya no es saltar a un espacio de memoria reservada desde el heap, por la api GlobalAlloc, si no saltar a nuestro propio espacio as nos evitamos de liar con opcodes e imaginarnos el dolor de cabeza si fuera un cdigo largo.
;pushad add dword ptr [ebx + 454h],2 ;popad
Escribiendo la rutina Arbitraria (3er Paso)

Al usar nuestro propio espacio, podemos escribir la instruccin tal cual la deseamos.

3er Paso. Rutina

Por qu pushad y popad?, Esto es por seguridad y buena costumbre ya que esto es un CodeCave y la rutina arbitraria que codeamos podra ser mucho ms larga que esta, seguramente usaremos registros que necesitan preservar su valor inicial, y seguramente esta aplicacin dara error si no hubiera preservado sus registros.

3er Paso. Rutina


La idea es dejar intactos todos los registros y aunque solo usamos EBX. Ahora, por qu esta en comentarios?, es que en los microprocesadores x64 los mnemnicos pushad y popad quedaron por decirlo as obsoletos, no son reconocidos ya que imagnense cuanto sera el tamao que ocupara en la pila, as que deberamos usar otros mtodos para preservar los registros que usemos.

4to Paso. Regresando el Flujo


Esta vez ya no se calcula el desplazamiento dejamos ese trabajo al microprocesador hacienda esto:
mov esi, 004226C2h jmp esi ;push 004226C2h ;ret
Jump Indirecto, para regresar al flujo (4to Paso)

S tanto hable de registros y preservarlos, Por qu usa ESI, esto puede influir en algn error de la aplicacin?, pudiera influir si antes no somos observadores, recordemos como est conformado las instrucciones ficticias que usamos para efecto del paper.

4to Paso. Regresando el Flujo


Esta vez ya no se calcula el desplazamiento dejamos ese trabajo al microprocesador hacienda esto:

004226BC - FF 8B 54040000 - dec [ebx+00000454] 004226C2 - 8B B3 44040000 - mov esi,[ebx+00000444]

A ESI, se mueve algn valor, as que no importa el valor de ESI en la direccin 004226BCh, porque en la siguiente instruccin va hacer modificada, as que lo usamos.

4to Paso. Regresando el Flujo


;push 004226C2h ;ret
Otro metodo, para regresar al flujo (4to Paso)

Este comentario, nos da otra idea de cmo hacer que salte hacia el flujo normal de la aplicacin, por si por alguna razn no se modifica algn registro y necesitamos otra forma de regresar. Al estilo de un CALL, un PUSH y un RET, es una tcnica muy usada y nos da una buena alternativa. Ocupa 6 bytes, un byte ms que al usar el JMP.

DEMO

DEMO

Links Interesantes
www.ricardonarvaja.info Web de Ricardo http://groups.google.com/group/crackslatinos - Crackslatinos http://indulgeoeddy.orgfree.com Web de Eddy http://www.crackmes.us/ - CrackMes
www.noxsoft.net Web de Nox

Gracias Totales!

Вам также может понравиться