febrero 10, 2022

Software protegido con dongle de ingeniería inversa

Yo era joven, Internet recién comenzó y pudimos obtener toneladas de software gratis. Era gratis porque alguien por ahí era lo suficientemente «amable» como para romper/parchear el .archivo exe.

He puesto «amable» entre comillas, porque esta era la vista que tenía cuando era niño. Ahora soy ingeniero de software y sé cuánto esfuerzo se necesita para crear software. Así que, por favor, no descargues software agrietado. ¡Apoye al desarrollador y compre una licencia!

Aplicando tal grieta, parcheando el exe, siempre quise saber cómo hacer tal cosa. Resulta que necesitas entender ensamblador, un lenguaje de máquina que solo tu CPU entiende (y algunos otros nerds por ahí). Como era demasiado difícil, nunca llegué a aprenderlo. Hasta hace poco (como 20 años después 😊).

Foto de Patrick Hendry en Unsplash

Hace un año, compré el software (¡con licencia!) que necesita un dongle USB para funcionar. Es realmente engorroso tener ese dongle contigo en todo momento. Especialmente cuando estás en la carretera. Así que busqué formas de evitarlo. Lo primero que encontré fue un emulador de teclas llamado Multiclave. Vuelca la memoria de su dongle a su registro y luego emula su dongle leyendo de su registro. Eso funcionó bien, hasta que quise ejecutarlo en Windows 10. Al parecer, Microsoft no es un gran fan de las teclas múltiples. En realidad, no es un gran fan de los controladores sin signo y MultiKey usa un controlador sin signo. Así que necesitaba otra solución. ¡Es hora de sumergirse en esa cosa llamada código de ensamblaje!

Siempre supe que había una herramienta para ingeniería inversa, llamada IDA. Es capaz de descompilar el .archivo exe y muestra lo que está pasando. Desafortunadamente, la interfaz es muy difícil de entender. También sabía de OllyDbg. Es un depurador. Un depurador le permite pasar por el código del ensamblador mientras el programa se está ejecutando. Lo que significa, por ejemplo, que si depurara la aplicación de la calculadora, podría verla manejando una pulsación de botón, haciendo el cálculo y mostrando el resultado en la pantalla. Diablos, incluso puedes pausar y cambiar su memoria haciendo que la calculadora devuelva 5 al preguntar qué es 2 + 2.

Pero no estoy aquí para cambiar el cálculo (aunque eso sería genial). Quiero liberarme del dongle. Así que abrí mi aplicación con OllyDbg.

OllyDbg

Que fue realmente abrumadora. No tenía idea de lo que significaban todos estos códigos. Y mucho menos saber por dónde empezar. Así que volví a la mesa de dibujo. Resulta que hay algo llamado RetDec, un descompilador que intenta hacer que el código C salga del código máquina. Me llevó algún tiempo configurarlo y ejecutar la descompilación, pero el esfuerzo se pagó. El resultado fue enorme .archivo c, más de 2 millones de líneas de código con código semi-legible.

De hecho, pude encontrar el código que lee los bytes del dongle bastante fácil:

Salida RetDec: Ya cambié algunos de los nombres de las variables a algo más legible.

Con esta información, volví a mi depurador. Mientras tanto, descubrí que OllyDbg es muy antiguo (del año 2000) y no se ha actualizado desde 2013. Así que encontré este nuevo depurador mejorado, llamado x64dbg. Es de código abierto y tiene una gran comunidad de desarrolladores trabajando en él.

Lectura de lenguaje de máquina

En lenguaje de máquina, cada instrucción tiene una dirección de memoria. Así que con las direcciones que se encuentran en el código RetDec, me volví a x64dbg y he aquí, el código que lee el dongle:

Código del ensamblador que lee 2 bytes de la memoria del dongle.

En el código ensamblador, los argumentos de la función se cargan en la memoria utilizando el puntero de pila esp. En nuestro código, esto sucede justo antes de la llamada a la función. (las instrucciones de 3 mov indican que la llamada toma 3 argumentos). Después de la llamada, nuestro puntero de pila se restablece y se realiza una comprobación (prueba) si la llamada a la función fue exitosa. Si no, vemos el código haciendo un salto (jne). Este salto apunta a un fragmento de código que indica que el dongle no está presente.

Como puede ver, hay una llamada a una función específica para leer el dongle. Busqué la guía de referencia para averiguar qué hace esta función:

La función lee un 2 bytes de memoria (una palabra) de la llave. Como se ha adivinado, la función toma 3 argumentos donde el último argumento es un puntero a 2 bytes que contendrán algunos datos del dongle.

En el código ensamblador, los argumentos se cargan en orden inverso. Pasando el último argumento es este:

El último argumento apunta a esi, lo que significa que los datos del dongle se almacenarán en la dirección de memoria a la que apunta esi.

de Hecho, cuando la pausa justo después de la llamada, podemos ver el resultado en la memoria:

0x74. Eso es lo que se lee en el dongle y se almacena en la memoria del programa principal.

Para omitir esta llamada, solo necesito escribir 0x74 en la memoria a la que apunta esi. Esto es tan simple como reemplazar las 7 líneas anteriores con:

Como puede ver, también nop-ed el resto de las instrucciones del ensamblador, incluyendo la prueba de si la llamada a la función era válida. Esto significa que el salto no se realizará y el programa continuará funcionando sin el cheque.

Después de parchear todas las llamadas que involucran el dongle, guardé la nueva .exe. Saqué el dongle, corrí mi costumbre .exe y para mi propio asombro funcionó! Había descifrado con éxito una pieza de software.

Otra cosa que cruzo de mi lista de deseos

Pd: la mayoría de las cosas estaban ofuscadas, como 0x74 y el nombre de la aplicación. Esto no es para dañar de ninguna manera a los desarrolladores que trabajaron duro y crearon este software. También tuve mucha suerte de que el dongle solo devolviera bytes y no hiciera ningún cifrado por sí solo.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.