Solución a LyCrackME @Leyer

Disclaimer

El api ByteBuddy nos puede dar una solución diferente.

Bueno señores que talco testeando aburrido me encontré este crackME de Leyer tiene como 10 años de antigüedad jajaaj primera vez que me asomo en esta cuestión crackMEs, antes solo los usaba y listo sin mucha pasión, pero de verdad que digamos, estaba algo aburrido, asi que vacilen.

Herramientas y Entorno

Lo primero que debemos hacer es descompilar nuestro .jar con el decompilador de preferencia por ejemplo esta web javadecompilers.com ahi debemos subir el .jar, existen otras opciones offline como el uso de Krakatau programado en python por consola, también recaf lector de bytecode e incluye cfr decompilador interno.

También tengo la opción con el decompilador por defecto que trae IntelliJ IDEA versión que use para esto:

  • (Community Edition) 2017.2 EAP
  • Build #IC-172.2656.10, built on May 30, 2017

Aquí en este enlace está, el crackME de leyer bueno no se si el tiene otros mas, que seguro si XD Ly-CrackME.jar para decompilar hacemos así, creamos un proyecto java y agregamos nuestro .jar desde File/project Structure y en el menú Libraries damos a + para importar el jar

Ya podemos ver todo el código fuente , en el menú External Libraries la primera linea si oprimo en el + dijera Source code recreated from a .class file by IntelliJ IDEA ..blalba by Fernflower, tocaría ahora crear una nueva clase y copiar el contenido de todo el código que se ve abajo, o usar krakatau para convertir este .class (Bytecode) a código fuente .java

Directamente en bandeja de plata esta casi todo, no tiene ningún wrapper con alguna aplicación tipo Jar2Exe, así que no tenemos que quejarnos tanto XD , otra cosa en su web tiene un source code que es como una versión nueva del crackME que es casi lo mismo, pero si tiene algunas diferencias y es el código que usaremos se ve así:

Vemos que las variables están escritas con $ que hacen bastannnte falta en Vzla, para darle un toque más intenso jajaj si o no ? Y ofuscar algo el código, en java se puede escribir así, aunque por convención se evita su uso, pero este es otro caso.

Aquí es importante acotar que la ofuscación de los String no es tan tann dura, como lo hacen algunos otros ofuscadores como Allatori ofuscator, el método _$as_OIsl que recibe un String como parámetro y luego lo pasa por un algoritmo de digestión usando la clase MessageDisgest() con SHA1 lo cual no podemos descifrar, a menos que seas empleado de google y puedas lograr una colisión con 100 VGA XD o hasta masss, bueno ya basta de tanta cotorra y empesemos por partes como el popular jack.

Ejecutamos el crackME Mayús+ F10

Debe aparecer asi

Introducimos cualquier valor, arrojando error claramente, pero eso ya da una pista que el boton validar quiza realize la validacion o invoque a un metodo que la haga, vamos por más, si oprimo
control + F que es para buscar e introdusco la palabra validar asi:

Para que lo hacemos? pues para ir destripando como hacia jack, ahora con la opción de oprimir control + click justo en el nombre de la instancia del boton _$b__$hsqqso__ linea 85 deberia de aparecer como la imagen, indicandome que en la linea 108 esta el listener de el, vamos a ver que talco

En la linea 112, obtenemos un array de caracteres que viene del JPasswordField que es el campo donde introducimos el serial que debe ser valido , se usa un for para concatenar todos los valores en un String este _$I_pos123 ver linea 115

la linea 117 es el condicional que compara si $I_pos123** es igual a **$r_easte pero quien rayos es el puto _$r_easte ? vamos a buscarlo:

la linea 105 vemos que el valor de _$r_easte en realidad se le asigna desde otro String mas $c_Cor ok vamos bien

Depurando con IntelliJ básico

En la linea 105 justo donde está el circulo rojo es para colocar un BreakPoint y saber que valor posee esa variable String _$r_easte

Ahora para ejecutar el depurador podemos oprimir Mayús + F9 o en la ezquina superior izquierda oprimir donde tenemos el icono del bug.

IMPORTANTE

Muchas veces no tenemos una configuracion lista y nuestra app no se ejecuta, miren que yo tengo mi configuracion del archivo a ejecutar/depurar que es CrackME2_ORIGINAL que eso le dice al IDE que clase ejecutar

Si por alguna razón tienen esa lista de items _vacia creen una configuracion previa con EDIT CONFIGURATION… y seleccionen el proyecto a ejecutar/depurar, cosa que espero que no les pase.

Al hacer todo bien el debug tendria que aparecernos asi:

vamos a la pestaña Variables observando que el String $c_Cor contiene este valor

cacaba0dff27b124ae5bc688b77c14f136b989118

que esa es la key aleatoria que se genero en ese momento de ejecutar el crackME, la pude obtener con control + c , e igual podemos obterner mayor infor con clickDerecho en ella

Este listener presentado aquí esta en el método main, como no tenemos variables de instancia y el alcance de las variables son locales pues trabajaremos dentro del main , sino, puedo crear variables de instancia y trabajar mas limpio como buen desarrollador(XD) o buena practica para no mojonearme, pero a la hora del cracking nos encontraremos en entornos o escenarios mucho peores jajjaaj recontra peores despues muestro XD

_$b__$hsqqso_.addActionListener(e -> {
   final String $faHA_$oPL = __gXb$.getText();
   if ($faHA_$oPL == null || "".equals($faHA_$oPL.trim())) {
     return;
   }
   if (!$faHA_$oPL.matches("[0-9]{0,9}") ) {
     JOptionPane.showMessageDialog(null, "Invalid value");
   } else {
     final int shitDesireMyEX = $1(_$Y_sy76, Integer.valueOf($faHA_$oPL.trim()));
     if(shitDesireMyEX != -1) {
        String _$c_Cor_ = "";
        final int _$_foP = shitDesireMyEX;
        for (int _$i_INDEX_ = 0; _$i_INDEX_ < _$Y_sy76.length; ++_$i_INDEX_) {
           if (_$Y_sy76[_$i_INDEX_] == _$Y_sy76[_$_foP]) {
             for (int index = 0; index < _$i_INDEX_; ++index) {
                 _$c_Cor_ = _$c_Cor_ + String.valueOf((byte) _$Y_sy76[index]);
             }
      //aqui el método es el que cifra el String _$c_Cor_ y lo concatena
      _$c_Cor_ = _$as_OIsl(_$c_Cor_) + String.valueOf(Math.pow((double) _$2341s, 2.0D) / 6.0D - 36.0D);
           }
        }//for externo XP
       _$lH$j$.setText("");
       _$lH$j$.setText(_$c_Cor_);
       _$c_Cor_ = "";
     }else {
        JOptionPane.showMessageDialog(null, "Invalid value");
     }
  }
});

Para validar la entrada del usuario usamos condicionales como en la linea 3 y 6, justo en la linea 6 hay una expresion regular (máximo 9, y rango del 0 al 9 inclusive) que cada index contiene ese largo 9 numeros, como lo siguiente:

matches("[0-9]{0,9}")

La linea 9 del código anterior se invoca al método $$1 mostrado abajo, este retorna el index, donde esta el valor de la variable X del crackME, por cada index de array estatico de valores hexadecimales ejemplo 0x7031101 es igual a el decimal 117641473, cada uno tiene un hash único que es lo que queremos, de otra manera seria -1 en caso de que no este, si es así la linea 10 daría falso y saltaría de una a la linea 25 notificando con Invalid Value

private static int $1(final int $_23DeSh$T[], final int $Bul$) {
        return IntStream.range(0, $_23DeSh$T.length)
                .filter($__Fkl -> $_23DeSh$T[$__Fkl] == $Bul$)
                .findFirst()
                .orElse(-1);
}

Con este index que lo llamaremos _shitDesireMyEX mi jodida EX, en caso de que exista lo setearemos a _$_foP ver linea 12

La linea 13 esta un for que recorre el array y en cada iteracion consulta el condicional de la linea 14 así,

if(_$Y_sy76[_$i_INDEX_] == _$Y_sy76[_$_foP]) {

Cuando el valor del contador _$i_INDEX_ sea igual a _$_foP osea mi fuckEX que me hizo la vida imposible con tanto drama por 3 meses, entraremos en el for mas interno para castearle explicitamente los valores del contador del for a bytes, + otro casting a String y concatenarlo a _$c_Cor_, al terminar ese for interno se invoca a _$ as_OIsl cifrandolo con el algoritmo de hashing SHA1 retornando de nuevo a la linea 13 for externo, esa condición de la linea 14 siempre se cumplirá solo una vez, es decir si la X es 7414755 index 0, ese for iterara 71 veces en vano, nuestro array posee 72 posiciones.

El valor del String lo setearemos en el JTextField aqui, o ver linea 23.

_$lH$j$.setText(_$c_Cor_);

Bueno antes de que alguien se queje me voy a quejar yo

FIXME EASTER EGG

Depurando esa linea, dando a la flecha como en la imagen para ver el resultado de la operacion que, aqui la variable _$2341s se le asignara 18, otras veces cuando nuestro PoC se va a la mier·””$ es xq tiene este valor 268435465 y de paso es constante.

Entonces si _$2341s puede presentar un valor constante que se da a veces, podemos crearnos un metodo y otro boton que setee ese valor nuevamente al JTextField o no? continuo varias veces más y me topo de nuevo con el grandisimo huevo de pascua, pero se me ocurrio la idea entonces de aplicarle el ácido.

para ejecutarlo en linux abrimos la consola nos movemos en el directorio donde este el jar y escribimos,

java -jar KeyGenPoC.jar

En guindo$ ya sabrán , tiene una linda _música, otra cosa JDK 8 XD

Comments