Tutorial 3 - Crackme en Ensamblador

Material

Bueno pues hoy vamos a estudiar un Crackme hecho en ASM, Este crackme esta hecho por Miele y tiene una protección del tipo Hardcoded, como ya anuncié en el artículo anterior este será el último de los Hardcoded fáciles, luego estudiaremos otros hardcoded que ya no comparan el serial correcto e incorrecto directamente, sino que hacen una serie de operaciones para comparar ambos serials

Nociones básicas de ASM

  • Este lenguaje es muy ordenado a la hora de depurar, pero claro, debido a su dificultad solamente se usa para pequeños programas
  • Es un lenguaje muy rápido pero es difícil programar con él

Antes de nada vamos a ver el lenguaje/compilador con el PEiD para coger costumbre:

0

 

Vemos que esta escrito en ASM y compilado con la versión 5.12 del MASM32/TASM32

Bueno, como siempre, lo primero de todo es abrir el crackme para ver como se comporta, así que lo abrimos, metemos un serial cualquiera y le damos a check y vemos:

 

1

Vaya, no hemos acertado, y nos pone “Quizás deberías intentarlo de nuevo ¡¡Es muy fácil!!”. Y ya de paso nos dan un mensaje de error para tener algo de lo que tirar hasta llegar al serial correcto.

Bueno, haremos como siempre, primero romperemos la puerta y luego haremos una copia de las llaves.

Rompiendo la Puerta

Abrimos el OLLY y cargamos este crackme (File > Open) y en donde se nos muestra el código en ASM hacemos clic con el 2º botón y vamos a Search for > all referenced text Strings (Para ver las referencias de texto) y vemos lo siguiente:

2

Yo haré doble clic sobre el mensaje de felicitación y aparezco en:

4

Vemos como aparecemos en el mensaje de felicitación, debajo esta el de error y arriba vemos una string rara que es cannabis que cuando tengamos que hallar el serial ya lo explicaré, así mismo aquí vemos 2 nuevas API’s que para romper la puerta no importan, así que lo explicare cuando intentemos copiar la llave, justo encima del mensaje de felicitación podemos ver un salto condicional muy sospechoso, nos situamos sobre ese salto para ver, en el caso de que se efectuará, donde nos lleva:

5

Nos lleva al mensaje de error, es decir, si no son iguales saltar al mensaje de error,

Vamos a recordar lo que dije en el manual (la parte de teoria)

Dije que para parchear se podrían hacer 3 cosas

  • Cambiar el JE por JNZ o viceversa
  • Cambiar el salto condicional por NOP’s
  • Cambiar el salto condicional por instrucciones que dejen el programa como estaba al principio, como por ejemplo INC y DEC

En el artículo del 1º crackme lo hice invirtiendo el salto condicional y dije que las otras 2 maneras no se podían hacer por que el mensaje de error estaba primero que el de felicitación, ¿pero que pasa ahora?, vemos claramente que ahora 1º esta el mensaje de felicitación y luego el de error, por lo que podemos usar la técnica que queramos, yo voy a elegir la del INC/DEC.

Así que manos a lo obra, me coloco sobre el salto condicional hago clic con el 2º botón y elijo Assemble, borro el texto que me sale en el cuadro de texto (que es el del salto condicional) y escribo: INC EAX doy al botón assemble y veo como desaparece el salto y aparece un INC y un NOP, esto no nos sirve, por que modificaría el programa, así que tenemos que cambiar el NOP por un DEC EAX y nos tendría quedar así:

6

Ejecutamos el programa con F9 metemos cualquier serial y…..

7

¡Y Listo!

Para guardar de forma permanente los cambios hacemos clic con el 2º boton en la zona donde se nos muestra el código en ASM elegimos copy to executable > all modifications ene. Cuadro que nos sale elegimos copy all y se nos abrirá otra ventana (dentro del OLLY) en la que solo se muestra código ASM, en esa ventana hacemos clic con el 2º botón y luego save file y le ponemos otro nombre para no sobrescribir el crackme original.

Haciendo copia de las llaves

Vamos de nuevo a las String references, ahí vemos el mensaje de error que se nos ha dado y mas arriba esta el mensaje de felicitación (si os habéis dado cuenta “Maybe, you should…..” es el texto del mensaje, y arriba vemos el titulo del mensaje “Nope!” y entonces “You entered…” será el texto del mensaje de felicitación y “Correct” será el titulo del mensaje, esto es solo curiosidad), y si nos fijamos aparecen algunos textos sospechosos, sospecharemos de “cannabis” y de “static” (en un principio) por que lo demás ya hemos visto que son títulos y texto de los mensajes de error y felicitación, “Password” es una string que aparece en el programa (por lo tanto no puede ser el serial o al menos no debería), “info” es un botón del programa y lo de “coded in…” es el texto que aparece al apretar el botón “info”. Así que simplemente viendo las referencias de textos sospechamos de cannabis y static. Pero vamos a descartar static, por que static suele ser una propiedad o una palabra reservada, si queremos verlo podemos hacer doble clic sobre “static” para ver donde nos lleva:

3

Vemos como efectivamente es una propiedad de la etiqueta “Password”, así que el principal sospechoso es “cannabis”, pero que sea sospechoso no quiere decir que sea el correcto.

Bueno yo seleccionaré de nuevo el string de felicitación y apareceré aquí

4

Aquí vemos 3 API’s distintas, 2 de las cuales son nuevas para nosotros, vamos a ver:

MessageBox: Esta ya la vimos, vimos que sirve para crear un mensaje

lstrcmpA: Esta es una de las nueva y su función es comparar 2 valores

GetWindowTextA: esta es nueva, pero cumple la misma función que la API GetDlgTextItemA, es decir, se encarga de recoger un texto

Así que deduzco lo siguiente, con GetWindowTextA recogerá mi serial falso, con lstrcmpA comparará mi serial falso con el correcto y con MessageBox mostrará el mensaje de error o de felicitación,

Visto lo visto voy a poner un BreakPoint en la API GetWindowTextA, bien al inicio de la API (0040122C) o bien directamente en el CALL (00401239) (para ello nos colocamos sobre esa línea y pulsamos F2), ejecuto el programa con F9 y meto el serial cualquiera y nos saltará la ventana del OLLY, traceo un poco (con F7 o F8 para no entrar en los call) y nada mas pasar el Call de la APi de GetWindowTextA veo que en la API lstrcmpA se pone String1=RdlP

8

Vemos que los 2 valores que compara son “cannabis” y “RdlP” así que definitivamente deducimos que el serial correcto es “cannabis”, de esta manera la sospecha se convierte en realidad.

Lo probamos y vemos que funciona. Ya tenemos una copia de las llaves.

Una pequeña reforma

Vamos a cambiar el serial correcto por RdlP. Vamos a ello, cargamos de nuevo el crackme en el OLLY vamos a las referencias de texto y esta vez pinchamos sobre cannabis y aparecemos sobre String2=cannabis, con esa línea seleccionada pinchamos con el 2º botón y elegimos Folow in Dump > inmediate constant y vemos en el DUMP que nos lleva hacia:

9

 

Y veo que en la primera línea pone “cannabis”, así que la selecciono como vimos en el tutorial anterior, pinchamos con el 2º botón sobre el DUMP y vamos a Binary > Edit y nos saldrá la ventana que vimos en el tutorial anterior y como yo ya se como se escribe mi nick en hexadecimal (por que lo vimos en el tutorial anterior) pues lo escribo en dicha sección y con la casilla keep size seleccionada (teniendo en cuenta que la longitud de cannabis = 8 y la de RdlP = 4, por lo tanto habrá que poner 4 bytes de 0, lo que se traduce en 8 ceros después de que acabe el string RdlP).

10

 

Veo que al acabar mi nick que es 52646C50 me faltan bytes por modificar así que lo relleno de 0’s y hago clic en ok. Ahora el serial correcto será RdlP.

En este tutorial hemos visto como saltarnos un sistema de protección bastante sencillo, hemos vuelto a insistir en que hasta que no estemos seguro del serial que no lo probemos por si acaso los programadores han metido código malicioso, hemos visto como cambiar el serial correcto por otro y hemos utilizado otra técnica distinta para romper la puerta (una táctica distinta a invertir el salto condicional).

RdlP
19 de agosto de 2007

Métodos anti-depuración en Linux: método basado en ptrace

Hace unos días leyendo un artículo me acordé sobre la API de windows IsDebuggerPresent localizada en Kernel32.dll para detectar si hay un depurador actuando sobre el programa se me ocurrió escribir una serie de artículos cortos sobre técnicas para detectar depuradores en Linux.

Es realmente frecuente encontrar en ejecutables técnicas para detectar si un depurador está activo o no, en función de si hay un depurador activo realizará una acción diferente a la acción realizada si no hubiese ningún depurador. Estas técnicas suelen ser usadas por aquellos programas que no se quiere que se le haga ingeniería inversa y de esta manera dificultar el estudio del ejecutable.

Unos cuantos ejemplo de ejecutables que usan este tipo de técnicas son los malware y los virus, pero también sistemas de empaquetado de ejecutables y sistemas de protección anticopia.

La primera técnica que vamos a ver se basa en el principio de que en Linux, un sistema que está siendo depurado por un proceso no puede ser depurado de nuevo por otro proceso. En linux la mayoría de depuradores usan la llamada al sistema ptrace para realizar su trabajo, de tal manera que si nosotros en nuestro programa llamamos a dicha función evitaremos que podamos ser depurados.

Si ejecutamos este programa desde la shell y luego probamos a ejecutarlo en gdb obtenemos

gdb

Vemos que si se ejecuta directamente sobre la shell nos dice que no hay depurador pero en cuanto lo ejecutamos en gdb nos dice ¡Depurador detectado!

Pero no solo eso, si lo ejecutamos con ltrace

ltrace

y con strace

strace

Vemos que obtenemos el mismo resultado ¡Depurador detectado!. En la última imagen se ve un poco mejor que es lo que realmente está pasando, vemos que cuando hace la llamada a ptrace nos devuelve -1

ptrace(PTRACE_TRACEME, 0, 0x1, 0)       = -1 EPERM (Operation not permitted)

Esto ocurre porque el programa está siendo traceado por strace y la llamada a ptrace de nuestro código no está permitida cuando ya hay otro ptrace en ejecución, el de strace.

Una de las formas mas sencillas para combatir esta técnica es modificar EAX a la salida de ptrace. EAX (o RAX en arquitecturas de 64 bits) contendrá el resultado devuelto por ptrace, que como hemos visto arriba, cuando hay un depurador activo es -1. Si modificamos y ponemos un valor 0 o mayor habremos conseguido saltarnos la técnica.

Para ello podemos cargar el programa en gdb, poner un breakpoint en main y ver cual es la instrucción inmediatamente posterior a ptrace y poner un breakpoint allí.

gdb1

si ponemos un breakpoint en la dirección 0x0804846c y continuamos la ejecución veremos que en eax devolverá -1 (como nos avisaba strace) si nosotros cambiamos este valor por 0 habremos conseguido saltarnos la protección

gdb2

Esta técnica es bastante sencilla pero requiere la modificación del registro EAX, otra técnica sería parchear el ejecutable y aquí tenemos bastantes opciones, podemos eliminar el call a ptrace y sustituirlo por nops, podríamos invertir el salto jns que hay a continuación de test, podríamos ponerle nops a ese salto, podríamos cambiar la instrucción test y cambiarla por alguna mas apropiada, etc.

Estas técnicas comentadas arriba son técnicas intrusivas porque requieren la modificación del binario o de la memoria del proceso en tiempo de ejecución, podemos realizar un enfoque mucho menos intrusivo si conseguimos que la llamada a ptrace devuelva automáticamente 0 (o cualquier número positivo).

Para ello nos programamos nuestra propia función ptrace

y la compilamos de la siguiente forma

gcc -m32 -shared -fPIC ptrace.c -o ptrace.so

De esta forma le decimos que va a ser una librería compartida (-shared) y que el código va a ser independiente de la posición (-fPIC), esto lo que hace es que en el binario en vez de guardar direcciones de memoria va a almacenar offset de esta manera esta librería podrá ser cargada en tiempo de ejecución en cualquier posición dentro del espacio virtual del proceso (gracias a esto funciona ASLR, aquí explico como funciona ASLR y como romper su seguridad: http://bitybyte.angelluispg.es/2016/11/13/bypassing-aslr/)

Ahora podríamos decirle a Linux que utilice nuestro ptrace.so en vez de la librería del sistema para ello tendríamos que establecer la siguiente variable de entorno

export LD_PRELOAD=./ptrace.so

En mi caso no me interesa exportarla en la shell de linux así que la voy a exportar dentro de gdb con

set environment LD_PRELOAD ./ptrace.so

Si ahora ejecutamos el programa que implementa la técnica antidepuración vemos

gdb3

Efectivamente hemos conseguido evitar la la técnica antidepuración de una forma más limpia.

Programar es Fácil

Hoy he encontrado una pequeña joya entre mis armarios.

Programar es fácil era una curso de introducción a la programación que estaba apoyado por IBM y que cuando lo acababas, tras superar un examen te daban un diploma.

El curso se vendió en 2001 en España en fascículos semanales si no recuerdo mal, y el primer tema a tratar era programación web, seguido de Delphi con Borland Delphi y C++ con Borland C++.

Y efectivamente en 2001 es donde empecé mi carrera como programador, tenía unos 11 años y gracias a estos fascículos conseguí dominar con bastante fluidez delphi, donde program´3 unas cuantas aplicaciones e incluso 2 juegos.

El curso no lo pude acabar porque mi paga semanal no me daba para comprarme los fascículos

Este era el anuncio del curso: https://www.youtube.com/watch?v=L656idB33Mo

Programar es Fácil