Como crackear assemblies….. con nada de experiencia

Hace algunas semanas leí un artículo del blog de Mike, llamado Cracking code 3: Cracking an obfuscated .NET assembly, donde como su nombre lo indica, muestra como crackear un assembly ofuscado.


En este caso, quise poner a prueba mi vasta experiencia (NADA) como crackeador de programas con un programa que bajé de internet y que tenía una limitante para el numero de lineas que podía trabajar.


Como la limitante era del tipo, if (lineas > N) –> no se puede procesar, en vez de cambiar el tamaño de N, invertí el if, para no tener nunca más el problema. Siempre tengo muchas más de N.


Lo primero que hice fue ejecutar mi gran amigo, .Net Reflector para ver el código del programa. Sorpresa mía, el código estaba ofuscado, pero con un papel, lápiz y buena memoria, la ofuscación es un problema menor.


Esto me muestra Reflector para un método que se llama z_b259, que por la firma, se entiende que es un evento. Los nombres del producto los he omitido por que no es lo importante de este post. Tambien no voy a mostrar los cambios que hice. He decidido mostrar en las pantallas el mismo bloque de códgo, visto desde reflector e IL (Intermediate Language), para lograr seguir la secuencia..



Una vez identificado el código donde está lo que quiero modificar, ejecuto el desensamblador de IL (ILDASM.EXE) y cargo el programa en cuestión. ILDASM se encuentra generalmente en \Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin. Se puede ejecutar sobre mi archivo crack.exe desde la consola de visual studio .net.


Si busco en ILDASM el código que veo en Reflector, me encuentro con lo siguiente. El lenguage IL es “parecido” al lenguaje de máquina. Observando detenidamente verán en los ovalos rojos las mismas ejecuciones marcadas en ovalos rojos en reflector.



Cuando ya encuentro el código que deseo modificar, vuelco el IL con ILDASM.EXE a un archivo de nombre crack.il. Esto volcado me genera una serie de archivos como los siguientes:



Que me falta ahora?. Ya tengo identificado el código y el if que debo invertir. En IL, un IF que compara menor o igual a n se representa por la instrucción ble.s (lower equal). Como necesito invertir el if, invierto la instrucción intuitivamente, cambiando la l por un g (lower, greater), dejando bge.s. Mi intuición es buena ya que luego de compilar el código IL a un archivo exe hago la prueba y funciona.


Si bien no pretendo dedicarme al crackeo de programas (creo que es mucho más valioso producir buenos programas), encuentro la experiencia muy interesante y a la vez, generadora de buenas interrogantes.



  • ¿Que creemos que es seguro?
  • ¿De que sirve no entregar el código fuente si se puede hacer ésto?
  • ¿Los ofuscadores, son realmente útiles?
  • ¿CAS no ayuda en esto?

Lo de CAS lo podemos dejar para otra oportunidad. Despues de ver el siguiente Post de Mike, Replacing a Strong Name y las preguntas y respuestas generadas, hoy ya no se que decir.


Estoy anonadado.


Patrick Mac Kay
Diciembre 2004

Encriptación Asimétrica V2.0

Como mencioné en el post Encriptación Asimétrica, existe una versión más funcional que combina algorítmos simétricos y simétricos.


Debido a que la encriptación asimétrica es casi 1000 veces más lenta que la simétrica, cuando la información a encriptar es mucha, se utiliza una combinación de algoritmos. El algoritmo simétrico se utiliza para encriptar la información y el asimétrico para encriptar la llave del algoritmo simétrico con que se encriptó a información. Entonces, el proceso es mucho más rápido. Esta técnica se utiliza hoy en SSL en la negociación entre el navegador del cliente y el servidor. En cada ida y vuelta al servidor se generan nuevas llaves y se realiza todo el proceso. También es utilizada por Windows en la encriptación de los archivos.


Otro motivo para utilizar esta encriptación combinada, es la necesidad de encriptar textos lagos. La encriptación asimétrica además de ser ineficiente en tiempo, tiene limitaciones de tamaño.


El código en el receptor de lo encriptado es el siguiente:



public class miRSA


{


       private RSACryptoServiceProvider _objRSA = null;


       public miRSA()


       {


             this._objRSA = new RSACryptoServiceProvider(1024);


       }


       public string ObtenerLlavePublica()


       {


             return this._objRSA.ToXmlString(false);


       }


       public string DesEncriptar(byte[] bytEncriptado)


       {


               byte[] keyArray = new byte[_objRSA.KeySize/8];


               byte[] encrypted = new byte[bytEncriptado.Length – keyArray.Length];


               Array.Copy(bytEncriptado, 0, keyArray, 0, keyArray.Length);


               Array.Copy(bytEncriptado, keyArray.Length, encrypted, 0, encrypted.Length);


               byte[] simKey = this._objRSA.Decrypt(keyArray, false);


               return MiRijndael.Desencriptar(encrypted, simKey);


       }


}


El código en el cliente es el siguiente:



miRSA _objKey  = null;


_objKey = new miRSA();


byte[] _bytEncriptado = null;


//Creamos una instancia del encritador publico


RSACryptoServiceProvider _objEncriptadorPublico = new RSACryptoServiceProvider();


//Le asignamos la llave genarada


_objEncriptadorPublico.FromXmlString(this._objKey.ObtenerLlavePublica());


//Se declara la memoria para almacenar la llave utilizada por nuestro Rijndael personalizado


byte[] _bytKey = (Rijndael.Create()).Key;


//Se encripta el texto y se obtiene la llave que se utilizó para la encriptación


byte[] _bytEncriptadoSimetrico = MiRijndael.Encriptar(TEXTO QUE QUIERO ENCRIPTAR, _bytKey);


//Se encripta la llave con el algoritmo RSA


byte[] _bytEncriptadoLlave = _objEncriptadorPublico.Encrypt(_bytKey, false);


//Se copia en un arreglo la llave encriptada y el encriptado de Rijndael


_bytEncriptado = new byte[_bytEncriptadoLlave.Length + _bytEncriptadoSimetrico.Length];


_bytEncriptadoLlave.CopyTo(_bytEncriptado,0);


_bytEncriptadoSimetrico.CopyTo(_bytEncriptado, _bytEncriptadoLlave.Length);


//Para desencriptar se utiliza el arreglo de bytes obtenido mas arriba. Esta función no debiera ser pública. Sólo lo es aquí para efectos de la demo.


this._objKey.DesEncriptar(_bytEncriptado);


La clase MiRijndael que se hace referencia esta en el link de encriptación simétrica, en el siguiente link :


http://msmvps.com/pmackay/archive/2004/11/27/21085.aspx.


Patrick Mac Kay
Diciembre 2004.