Curiosity is insubordination in its purest form. -Vladimir Nabokov

sábado, 19 de enero de 2019

Cracking de un juego MS-DOS usando DOSBox debugger (analisis dinamico)

El candidato es Megatraveller 2 [1], un viejo (1991) juego msdos de rol en su version en castellano con una proteccion bastante comun en su epoca: al iniciar el juego se nos pregunta por algo cuya respuesta viene en el manual. Si la respuesta es correcta jugamos, de lo contrario el juego termina y volvemos al DOS.

Para no repetirnos, a diferencia de la entrada anterior donde usamos IDA para hacer un analisis estatico, en esta ocasion usaremos el debugger de DOSBox para hacer un analisis dinamico, es decir, ejecutaremos el juego paso a paso, pondremos breakpoints hasta localizar la parte del codigo donde esta la proteccion y la anularemos modificando el codigo en memoria en caliente. Todo mientras vemos en la pantalla de DOSBox que es lo que va mostrando el juego por pantalla, lo cual es enormemente util. Finalmente haremos el crack permanente modificando el archivo responsable de la proteccion con un editor hexadecimal.

Lo primero necesitamos compilar una version de DOSBox con el debugger activado, ya que por defecto no lo esta. Para windows hay precompilados en Vogons [2]. Para compilar en Linux:
./autogen.sh && ./configure --enable-debug=heavy && make
Aunque yo he utilizado dosbox-x [3], que he compilado de una forma un poco diferente ejecutando ./build-debug que ya incluye --enable-debug=heavy

Bien, cargamos el juego:
user@host:~/crack/MT2$ ~/emus/dosbox-x-0.82.14/src/dosbox-x -c "keyb sp" -c "mount c ." -c "c:" -c "MT2.COM"
Avanzamos hasta que nos pida las claves y activamos el modo debugger con ALT+PAUSA. Veremos algo parecido a:

Si tecleamos HELP en la ventana Output veremos una ayuda de los comandos aceptados por el debugger. Para este crack usaremos los siguientes:
F5                        - Run.
F10/F11                   - Step over / trace into instruction.
BP [segment]:[offset]     - Set breakpoint.
SM [seg]:[off] [val] [.]..- Set memory with following values.
Atencion: segun las asociaciones de teclas que tengas en tu programa emulador de terminal puede que necesites redefinir alguna tecla de funcion, ya que tendra preferencia sobre el debugger de DOSBox.

Si miramos el titulo de la ventana de DOSBox veremos que se esta ejecutando CHARGEN. DOSBox no muestra la extension del archivo en el titulo pero CHARGEN.DAT tiene todas las papeletas de ser realmente un ejecutable de DOS. Si miramos con file:
user@host:~/crack/MT2$ file CHARGEN.DAT
CHARGEN.DAT: MS-DOS executable, MZ for MS-DOS Self-extracting PKZIP archive
user@host:~/crack/MT2$
Efectivamente, es un ejecutable de MS-DOS, concretamente un .EXE (los magic-bytes MZ lo delatan) empaquetado con PKLITE. Pues antes de nada vamos a desempaquetarlo. Usare UNP [4].

Un empaquetado conocido es un desempaquetado instantaneo. Volvemos a cargar el juego con MT2.COM, pulsamos ALT+PAUSA y para llegar al punto donde se comprueban las claves, iremos pulsando F10, prestando atencion a los CALL o los saltos Jxx. Si queremos entrar en alguna funcion llamada por CALL pulsaremos F11. Si vemos que pulsando repetidamente F10 entramos en un bucle podemos fijarnos en los saltos y ver si hay algun camino que no estamos siguiendo. Pondremos breakpoints en esos caminos y haremos F5, veremos si podemos teclear, si el codigo se para seguiremos con F10/F11.

Bien, despues de poner breakpoints, ejecutar, breakpoints, ejecutar, paciencia con breakpoints cada vez mas avanzados en el flujo de ejecucion llegamos a ver la rutina de comprobacion de claves. Puede que acabe haciendo un video con todo el proceso desde inicio a final, pero mientras sugiero los siguientes breakpoints.
BP 0B74:0000506E -> Se activa cuando se introduce la clave y se pulsa intro.
BP 0B74:0000BB98 -> Comprobacion claves.
BP 0B74:0000506E -> Clave correcta, se carga INTRO.DAT y empieza el juego.
Una vez introducidos en la ventana Output del debugger pulsamos F5 para ejecutar el juego, avanzamos hasta que nos pida las claves y justo cuando introducimos una clave y pulsamos intro vemos que la ejecucion se pausa, es el primer breakpoint:
      0B74:00005064 E8BDD4    call 00002524 ($-2b43)
      0B74:00005067 8BF0      mov  si,ax
      0B74:00005069 83FE0D    cmp  si,000D                         ; SE HA PULSADO INTRO? (EL CODIGO ASCII DE INTRO ES 0D)
      0B74:0000506C 7503      jne  00005071 ($+3)     (no jmp)     ; NO
BP    0B74:0000506E E94102    jmp  000052B2 ($+241)   (down)       ; SI
Volvemos a pulsar F5 y el segundo breakpoint nos lleva a:
      (...)
      0B74:0000BB8B E8321A    call 0000D5C0 ($+1a32)
      0B74:0000BB8E 83C402    add  sp,0002
      0B74:0000BB91 8BC8      mov  cx,ax
      0B74:0000BB93 8BC7      mov  ax,di
      0B74:0000BB95 8BDA      mov  bx,dx
      0B74:0000BB97 99        cwd
BP    0B74:0000BB98 3BC8      cmp  cx,ax                           ; ¿CLAVE CORRECTA?
      0B74:0000BB9A 7504      jne  0000BBA0 ($+4)     (jmp)        ; CHICO_MALO
      0B74:0000BB9C 3BDA      cmp  bx,dx                           ; CHICO_BUENO
      0B74:0000BB9E 7411      je   0000BBB1 ($+11)    (down)       ; CHICO_BUENO
Es la parte de codigo donde se comprueban las claves. Nos encontramos en BP donde se compara la clave introducida con la clave que el juego espera. La linea siguiente "jne 0000BBA0" es el primer chequeo de claves. JNE es chico_malo. Lo anulamos sustituyendo JNE por NOP NOP, es decir, 75 04 por 90 90. El debugger de DOSBox nos permite modificar el codigo en memoria en caliente ya que si puedes cambiar la memoria puedes cambiar el codigo en ejecucion, recuerda: todo lo que se esta ejecutando esta en memoria. Asi:
SM 0B74:BB9A 90 90
y veremos que automaticamente el codigo cambia a:
BP    0B74:0000BB98 3BC8      cmp  cx,ax                           ; ¿CLAVE CORRECTA?
      0B74:0000BB9A 90        nop
      0B74:0000BB9B 90        nop
      0B74:0000BB9C 3BDA      cmp  bx,dx                           ; CHICO_BUENO
      0B74:0000BB9E 7411      je   0000BBB1 ($+11)    (down)       ; CHICO_BUENO
Despues de los NOP viene un segundo chequeo de claves. JE es chico_bueno. Para una clave corta se cumple el JE y no seria necesario cambiarlo, pero cuando el usuario introduce una clave con toda la longitud, por ejemplo 555555555555555555 _NO_ se cumple el JE (no saltamos) y el programa considera incorrecta la clave introducida. Como el camino chico_bueno es saltar cambiamos JE por JMP (74 11 por EB 11) y asi saltamos siempre independientemente de la longitud de la clave que introduzcamos. Lo modificamos con otro SM:
SM 0B74:BB9E EB 11
Y ahora tenemos:
BP    0B74:0000BB98 3BC8      cmp  cx,ax                           ; ¿CLAVE CORRECTA?
      0B74:0000BB9A 90        nop
      0B74:0000BB9B 90        nop
      0B74:0000BB9C 3BDA      cmp  bx,dx                           ; CHICO_BUENO
      0B74:0000BB9E EB11      jmp  0000BBB1 ($+11)    (down)       ; CHICO_BUENO
En este punto ya esta crackeado, no importara la clave que introduzcamos, todas seran validas. Volvemos a pulsar F5 (Run) y el programa se parara en el tercer y ultimo breakpoint que pusimos:
      (...)
BP    0B74:00000CEB E85EC0    call FFFFCD4C ($-3fa2)               ; CARGAMOS INTRO.DAT Y EMPIEZA EL JUEGO
Este BP no es necesario para el crackeo pero sirve para mostrar cual es el CALL que carga INTRO.DAT. Es decir que CHARGEN.DAT ha tomado la clave como valida y empieza el juego en si.

Para hacer el crack permanente editamos el archivo CHARGEN.DAT con un editor hexadecimal, buscamos una ristra de bytes que contenga los bytes que queremos cambiar y nos aseguramos de que sea unica (si no buscariamos con una cadena mas larga) y lo cambiamos por los nuevos opcodes.
hexedit CHARGEN.DAT (Ojo! primero hay que desempaquetarlo) y sustituir
3B C8 75 04 3B DA 74 11
por
3B C8 90 90 3B DA EB 11
y guardar cambios.
Feliz reversing.

[1] Megatraveller 2 https://www.mediafire.com/file/id5q6tsgfve6ea5/MT2.7z/file
[2] DOSBox Debugger https://www.vogons.org/viewtopic.php?t=7323
[3] DOSBox-xhttps://github.com/joncampbell123/dosbox-x/releases
[4] UNP http://unp.bencastricum.nl

Related Posts by Categories



0 comentarios :