.NET Tutorial 11. Como »Juankear» aplicaciones .NET y estrategias para evitarlo (Parte I)

Antes de dar inicio a este tutorial me gustaría aclarar un par de cosas:

  • Este tutorial no pretende ser un tutorial de "cracking". Por lo tanto rogaría que os abstuvierais de pedir "ayuda" para tal o cual programa.
  • La mejor forma de proteger nuestras aplicaciones es saber como piensan "los chicos malos". Sabiendo lo que hacen, será más fácil tomar "contramedidas".
  • Por último, ten por seguro que siempre "hay alguien más listo que tú". Por lo tanto por muchos esfuerzos que empeñes en poner "trabas" en una aplicación, ten por seguro que si "alguien" quiere "saltar" tu protección, lo hará tarde o temprano.

Cito de la Wikipedia:

Common Intermediate Language (CIL, pronunciado "sil" o "kil") (anteriormente llamado Microsoft Intermediate Language o MSIL) es el lenguaje de programación legible por humanos de más bajo nivel en el Common Language Infrastructure y en el .NET Framework. Los lenguajes del .NET Framework compilan a CIL, el cual a su vez es ensamblado en bytecode. CIL es un lenguaje ensamblador orientado a objetos, y está basado en pilas. Es ejecutado por una máquina virtual. Los lenguajes .NET principales son C#, Visual Basic .NET, C++/CLI, y J#.

CIL fue conocido originalmente como Microsoft Intermediate Language (MSIL) durante las versiones de prueba de los lenguajes .NET. Debido a la estandarización de C# y CLI, el bytecode es ahora conocido oficialmente como CIL. Debido a esto, CIL es frecuentemente llamado MSIL. Es posible ejecutar este lenguaje en plataformas GNU/Linux gracias al Proyecto Mono, que implementa una maquina virtual similar a la de .NET pero de software libre.

En lenguaje "terricola" esto quiere decir que cualquier aplicación de .NET (C#,VB.NET, J#, etc) produce un código llamado CIL. El .NET Framework "interpreta" dicho codigo y genera "el exe en memoria".
Esto tiene sus ventajas e incovenientes. La principal ventaja es que dicho código CIL cumple una serie de estándares lo que puede (y de hecho es) ser "interpretado" con otros "Frameworks". El mejor ejemplo es el proyecto Mono, con el cual se pueden "ejecutar" aplicaciones escritas en C#/VB.NET bajo GNU/Linux.

Podriamos "perfectamente" escribir una aplicación en código CIL, con el bloc de notas, ya que a la postre el .NET Framework lo que "entiende" es código CIL.

Y "ete" aquí el "problema" del asunto.

Para este tutorial me he creado esta "super-aplicación":

Si introducimos el código "correcto" accederemos a estas opciones:

Sin embargo, si no introducimos el código "correcto" hay opciones deshabilitadas (lo típico en programas "demo" o "trial")

Por un momento podrías llegar a pensar:

"Bua tio, el algoritmo que comprueba el código es tan enrevesado que es imposible que ningún terricola lo descubra en los próximos 200 años (introducir aquí muchos X-D, xD, XD, ja ja’s y demás onomatopeyas)".

Si bueno, pues entonces te advierto que es posible que tengas algún vecino, conocido, amigo que sea de Venus 😉

En el evento Click del botón Aceptar tenemos este código:

If VerificarLogin(TxtPassword.Text) = True Then
UsuarioPremium = True
Else
UsuarioPremium = False
End If

(Ver imagen del código)

Como podras ver, se usa una función, VerificarLogin que nos devuelve si la contraseña es correcta o no. El código de dicha función es este:

Public Function VerificarLogin(ByVal Password As String) As Boolean
If Password = "1234" Then
    Return True
Else
Return False
End If
End Function

Cómo puedes ver, tampoco es que me haya "matado" mucho en esa función. El código correcto es el "1234".

Nota mental: Pues chico, porque no has puesto que el código fuese el 12312375123987393810430240347198324, asi seguro que nadie lo "adivina".

Si bueno, quizas tengas razón. ¿Código CIL/MSIL, recuerdas? 😉

¿Conoces .NET Reflector?

The "Easy" way.

Verás que poner un código "largo" tampoco es ninguna solución. El .NET Reflector interpreta el código CIL/MSIL de nuestro "exe".

Hmmm….un formulario que se llama FrmLogin…interesante:

Hmmm…un evento que se llama BtnAceptar_Click…interesante:


(Haz click para agrandar la imagen)

Hmmm…una función que se llama VerificarLogin…interesante:


(Haz click para agrandar la imagen)

Te recuerdo que esto lo estoy mirando en el EXE.

¿Aún crees que sería mas "complicao" si hubiese puesto el código 12312375123987393810430240347198324?

Ahora es cuando alguien dice: OMFG!: ¿Pero que me estas contando colega? ¿Quieres decir que cualquiera puede ver el "codigo fuente" de una aplicación escrita en .NET con solo tener el ejecutable?.

 

The "Hard" way

Bueno, pues si creías que lo del "Reflector" es un problema lo que verás a continuación puede ser ya de "apaga y vámonos".

Primero dos links de la MSDN:

Ildasm: Desesamblador de código CIL/MSIL
Ilasm: Ensamblador de código CIL/MSIL

Cuando instalas Visual Studio u otras herramientas de desarrollo (SDKs y similares) también se te instalan el ildasm y el ilasm.

El ensamblador (ilasm) suele estar en esta carpeta:

C:WindowsMicrosoft.NETFrameworkv2.0.50727

Mientras que el desensamblador (ildasm) suele estar en esta:

C:Program FilesMicrosoft SDKsWindowsv6.0ABin

(Nota: Estas ubicaciones pueden variar dependiendo del S.O y SDKs que tengas instalados en tu PC)

Pues bien…atentos a la jugada:

  • Vamos a abrir nuestro EXE con el ildasm
  • Vamos a "volcar" el contenido del EXE en un fichero de texto con el código CIL/MSIL, que es lo que "entiende" el .NET Framework
  • Vamos a cambiar la rutina "VerificarLogin" para que pongas el password que pongas, siempre devuelva "Verdadero"
  • Finalmente vamos a "recompilar" ese código "modificado" con el ilasm para generar de nuevo otro EXE con esa "particularidad" ("particularidad" = pongas el password que pongas, éste siempre sera correcto)

Antes de nada comentar que .NET Reflector también puede mostar el código fuente en formato CIL/MSIL:


(Haz click para agrandar la imagen)

Desensamblando nuestro ejecutable en código CIL/MSIL.

Abrimos el ildasm y cargamos nuestro exe:


(Haz click para agrandar la imagen)

Una vez cargado el ejecutable nos podemos mover por todo el árbol de clases y ver todos los eventos, procedimientos, funciones, etc de cada objeto:


(Haz click para agrandar la imagen)

Al hacer doble click sobre la función VerificarLogin se muestra el código CIL/MSIL de dicha función:


(Haz click para agrandar la imagen)

Cómo puedes ver este código es el mismo que muestra .NET Reflector cuando en .NET Reflector le decimos que queremos ver el "código fuente" en formato IL.
Obviamente, este formato es "bastante algo más" complicado que "leer" el código en formato C# o en VB.NET.

Bueno, a lo que ibamos. Una vez cargado nuestro exe, hay que volcar la información:


(Haz click para agrandar la imagen)

Dejaremos las opciones de volcado por defecto:

Al guardar el volcado le daremos un nombre:

Una vez finalizado el volcado verás que se ha creado el arhivo .IL y otros archivos adicionales (archivos de recursos):


(Haz click para agrandar la imagen)

Cambiando el código MSIL con la superherramienta "Bloc de Notas".

Una vez que se tiene el archivo .IL, lo abrimos con el bloc de notas y buscamos la sección de código CIL/MSIL de la función VerificarLogin:


(Haz click para agrandar la imagen)

Cambiaremos la linea que pone:

IL_0011:   ldc.i4.0

por esto:

No entraré en detalle de que hace esa instrucción y el "por qué" de ese cambio. Recordar lo que apunté al principio de este tutorial. ¬¬

Guardamos los cambios. Ahora toca "re-compilar" ese .il "modificado"

Recompilando el código.

Para volver a tener el "ejecutable" con la "modificación" que hemos hecho tendremos que volver a compilar el archivo .IL

Para ello usaremos el ilasm:


(Haz click para agrandar la imagen)

Llamaremos al ilasm pasandóle como argumento la ruta y el nombre del archivo .IL que modificamos con el Bloc de notas. Una vez finalizada la compilación nos mostrará el siguiente mensaje:


(Haz clic para agrandar la imagen)

Y efectivamente, si ahora miramos en la carpeta veremos que tenemos el exe "modificado":

Si ahora ejecutas el archivo tutorial11disasm.exe verás que pongas el código que pongas, dicho código será "válido".

Finalmente y sólo por curiosidad, abrimos ese nuevo exe desde el .NET Reflector y vemos que la función VerificarLogin, después del "cambio" ha quedado así: (en "lenguaje" VB.NET)

Como ves,  la función siempre devuelve "True", pongas el password que pongas.

Apuntes finales.

Como supongo que has podido comprobar, no hace falta ser miembro de 29A, ni ser miembro del Black Hat para hacer esto que acabamos de hacer. De hecho es la propia Microsoft la que proporciona todas estas herramientas de depuración y diagnostico, amén de la ingente cantidad de información que hay en la MSDN.

Obviamente nuestro ejemplo tenía pocas lineas de código, pero esto no quita que en programas "grandes" y sin las "contramedidas" adecuadas se pueda llegar a hacer lo mismo.

Espero que esta entrada os haya sido interesante. En la próxima entrada veremos que de algún modo esto es "subsanable" y por lo menos, nos podremos quitar de encima a los "imitadores" de Kevin Mitnick o a los "juankers de fin de semana" 😉

 

Saludos.
mov eax,ollydbg; Int 13h 

 

Descargar proyecto .NET Tutorial 11
(140 KB. Visual Studio 2008)

Nota: El archivo *.il y su posterior "ejecutable" se encuentran en la carpeta Release del proyecto.