Bien, hice este parche para una gente que queria jugar a este juego y es un ejemplo muy simple de un cracking en la practica: un viejo (1997) juego argentino para msdos llamado Sauro [1] que no arranca en DOSBox. Al cargar SAURO.EXE en DOSBox el programa nos devuelve al DOS con el mensaje "Atencion el sistema necesita una placa VGA valida, instale una. GRACIAS por usar este producto RAL SOFT".
Comenzamos cambiando en la configuracion de DOSBox la tarjeta grafica que DOSBox presenta al juego y seguimos con el mismo problema, asi que decidimos acudir al debugger.
El ejecutable SAURO.EXE es un ejecutable de MSDOS, por lo que necesitamos un debugger que pueda leer binarios de DOS. Yo he usado la version free de IDA 5.0 [2], ya que versiones free posteriores eliminaron soporte DOS. Manos a la obra.
Arranco IDA y cargo SAURO.EXE indicando que es un EXE de DOS. Espero unos segundos a que se complete el analisis y como en este caso el codigo no esta empaquetado, ni tiene protecciones antidebug, ni tiene codigo que se modifica a si mismo en tiempo de ejecucion (SMC), ni nada raro, en cuanto IDA termina el analisis tengo ante mi el codigo en ensamblador de SAURO.EXE
Es muy largo por lo que necesito acotarlo a la seccion que me interesa. Bien, sabemos que al ejecutar SAURO.EXE el programa finaliza y nos devuelve al DOS con el mensaje "Atencion el sistema necesita una placa VGA compatible". Esa cadena esta en algun lado, podria estar en texto claro, o codificada o no estar en SAURO.EXE sino en algun archivo que lee SAURO.EXE, o ser un mensaje que devuelve el S.O., pero por algun sitio tenemos que empezar, la buscamos en IDA y nos encontramos con el siguiente codigo ensamblador:
loc_31DD:loc_31DD: es una etiqueta puesta por IDA porque en algun momento del codigo el flujo de ejecucion nos lleva hasta ahi. Bien, pedimos a IDA que nos muestre desde donde se salta a loc_31DD y el debugger nos muestra esto:
push ds
push offset aAtencionElSist ; "\nAtencion el sistema necesita una placa"...
call sub_1BD5
pop cx
pop cx
push ds
push offset aGraciasPorUsar ; "GRACIAS por usar este producto RAL SOFT"...
call sub_1BD5
pop cx
pop cx
push 0
call sub_261
pop cx
sub_31B9 proc farYa viendo esto sabemos que muy probablemente ya lo tenemos y solo necesitariamos invalidar el salto JNZ. Justo antes de llegar al salto condicional JNZ vemos que se compara con un TEST el valor que hay en la direccion de memoria [bp+var_1] con el valor 30 en hexadecimal. Solo si es 30h el TEST devolvera un 0. Luego viene el salto JNZ que dice que si no es 0 (JNZ = Jump if Not Zero) saltamos a loc_31DD, que equivaldria a que el programa no ha detectado una placa VGA valida y finalizaria, que es lo que nos esta pasando.
var_1= byte ptr -1
enter 2, 0
push 14h
call sub_1AED
pop cx
mov [bp+var_1], al
test [bp+var_1], 30h
jnz short loc_31DD
Si vemos la funcion sub_1AED a la que llama CALL tenemos esto:
; Attributes: bp-based frameEsta es la rutina que chequea si tenemos una VGA o compatible y vemos que no llama a la INT de Video de la BIOS (INT_10), sino que se comunica con la CMOS mediante las instrucciones de acceso a puertos IN/OUT. out 70h/in 71h parece no estar correctamente emulado en DOSBox, ya que como vimos en sub_31B9, el juego espera un valor diferente al que le comunica DOSBox, con lo cual acaba saliendo al DOS con el mensaje de que no encuentra VGA valida.
sub_1AED proc far
var_1= byte ptr -1
arg_0= byte ptr 6
enter 2, 0
mov dx, 70h ; 'p'
mov al, [bp+arg_0]
out dx, al ; CMOS Memory:
; used by real-time clock
inc dx
in al, dx ; CMOS Memory
mov [bp+var_1], al
mov al, [bp+var_1]
leave
retf
sub_1AED endp
Para "crackearlo" tenemos al menos dos opciones. Una seria modificar la funcion sub_1AED para que siempre devolviera el valor 30h, que es el que comprueba el TEST que vimos, pero quizas la solucion mas simple y por tanto la mejor seria invalidar el salto jnz short loc_31DD de tal forma que no saltaramos al codigo que nos muestra por pantalla "no hay vga valida" sino que el programa continuara y pudieramos jugar a SAURO.
Bien, el codigo ensamblador es mas bajo nivel que un lenguaje como C pero aun no es lo que entiende la CPU, la CPU solo entiende de ceros y unos. Y para que los humanos podamos entenderlo un poco mejor representamos los ceros y unos en hexadecimal. Cada instruccion ensamblador se traduce a lo que se conoce como opcodes. Si pedimos a IDA que nos muestre los opcodes al lado de las instrucciones para el salto jnz short y las instrucciones inmediatamente anteriores tenemos:
0BCF call sub_1AEDLa columna de la izquierda son los opcodes en hexadecimal para cada instruccion (1 opcode=1 byte, 0B es un byte, CF otro byte). El salto JNZ se traduce como los dos bytes en hexadecimal "0B DC". Para invalidar el salto existe una instruccion en ensamblador x86 que es NOP, y simplemente no hace nada, cuando la CPU ejecuta un NOP se consume algun ciclo de cpu pero no hace nada y continua con la siguiente instruccion. El opcode de NOP en arquitectura x86 es 90 en hexadecimal.
0BD4 pop cx
0BD5 mov [bp+var_1], al
0BD8 test [bp+var_1], 30h
0BDC jnz short loc_31DD
Pues manos al crakeo. Si sustituimos el fragmento de codigo anterior por...
0BCF call sub_1AED...cuando el programa haga la comprobacion con TEST no importara el resultado de esa comprobacion porque luego ejecutara los dos NOP que siguen y continuara hacia el flujo de ejecucion de que ha encontrado una placa VGA valida, es decir, veremos el juego en si.
0BD4 pop cx
0BD5 mov [bp+var_1], al
0BD8 test [bp+var_1], 30h
90 nop
90 nop
Para parchearlo podemos por ejemplo abrir SAURO.EXE con un editor hexadecimal y buscar la cadena de bytes "0B CF 0B D4 0B D5 0B D8 0B DC", asegurarnos de que sea unica (si no buscariamos con una cadena mas larga) y sustituirla por "0B CF 0B D4 0B D5 0B D8 90 90"
Y ya estaria crackeado. Digo crackeado porque imagina que en vez de comprobar un valor que devuelve la memoria CMOS el programa estuviera comprobando si la clave que has puesto es valida o no. La logica seria la misma o muy similar, invalidar el salto hacia chico_malo para que siempre siguiera el flujo de ejecucion por el camino chico_bueno.
Este era un ejemplo simple: no empaquetado, no SMC, no antidebugging, nada, solo anular un salto, pero puede complicarse y mucho y ahi pues paciencia y determinacion.
No es necesario conocer todas las instrucciones ensamblador, aunque cuanto mas mejor. Saber como el sistema operativo en que nos movemos maneja la memoria, pila, interrupciones, BIOS, acceso a ficheros, etc es mas necesario que conocer todas las instrucciones ASM, pero lo mas importante de todo es tener claro el flujo de ejecucion del programa. Una vision global y no dejar de aprender.
¿Quieres practicar? bien, te contare un pequeño secreto: busca en la red PC Futbols /Baskets /Futbol Argentina... antiguos sin desproteger, y hasta la version 4 aprox, todos son iguales y se pueden desproteger en menos de un minuto aplicando lo aprendido en esta entrada. La rutina de proteccion es clavada, pero clavada en todos ellos y se puede localizar rapidamente en IDA o desensamblador similar. Malditos vagos, roto uno rotos todos ;/
Busca como hacer en IDA las cosas que he explicado y sigue tu camino.
Feliz reversing.
[1] Sauro https://www.mediafire.com/file/nyvd996o90ty107/SAURO.7z/file
[2] IDA 5.0 free https://wiki.scummvm.org/index.php/HOWTO-Reverse_Engineering
[+] HOW TO CRACK, by +ORC, A TUTORIAL https://zen7.vlan7.org/file-cabinet/howtocrk_.txt
0 comentarios :
Publicar un comentario
Nota: solo los miembros de este blog pueden publicar comentarios.