Hola,
El crackMe de leyer resuelto medianamente en el 2017 por mi
Solución lycrackme, veo una mejor manera de hacerlo con Instrumentación dinamica usando el api de ByteBuddy, para construir un agente y adjuntarlo en tiempo de ejecución al crackME o proceso de este.
-
Importante: para usar el APi de Java de instrumentación, estoy usando la JDK 8, dado en contiene el
tools.jar, si o si es necesario para poder crear el agente, abria que investigar como hacerlo con versiones mas nuevas de Java.
- El código del crackME para que no se pierda, y recordarlo, leyer me odiara ya...
- Aún asi es un escenario fácil ya que el código no esta ni cifrado, ni ofuscado, podemos leer las variables incluso, decompilar también el .jar del crackME, o sea ventajas, en otros escenarios, un decompilador de Java con un .jar
ofuscado no lograria decompilar bien y se confundiría.
-
Ventajas de esta manera: que tenemos mas desacople, claramente, debemos analizar este .jar u otro, por medio de un decompilador bueno, y en lo posible entender, en dado caso desofuscarlo, etc, muchas comparaciones de password son con ese equals, para los Strings si es igual a otro etc...
- Quizas también con bytebuddy se podria cambiar la condicion, invertirla ? con el operador de negacion ? en este caso como todo esta en el main, no lo c rick...
import...
public class CrackMe {
static int[] _$$Y_sy76 = new int[]{7414755, 3219665, 175186692, 136322726, 136419744, 4066036, 15685602, 103481, 8331326, 14522496, 254443529, 117440530, 0x100000, 10066673, 0xEEE122, 0x421442, 1183806, 11019024, 140529167, 118489840, 19071234, 0xF00004, 3109537, 594494, 7406141, 9476832, 18812418, 9969838, 34803714, 3298805, 2302368, 15368608, 8916253, 9445024, 51519491, 31, 241696768, 7414181, 2299045, 39441, 9539087, 16392240, 0x9090090, 117641473, 258080912, 16115104, 0x120120, 0x10101A, 1183501, 7413822, 236060690, 257294849, 125830118, 66016, 8983278, 624289, 16609425, 14844138, 27270816, 239404033, 51389454, 7414690, 593951, 7709524, 9969409, 9847050, 118646528, 158482433, 0x1110011, 2299045, 2299045, 3739700};
byte[] _$$d_defaultBytes_ = _$s_String_.getBytes();
try {
}
// empty catch block
}
_$$a_algorithm.reset();
_$$a_algorithm.update(_$$d_defaultBytes_);
byte[] messageDigest = _$$a_algorithm.digest();
int _$I_Index = 0;
while (_$I_Index < messageDigest.length) {
hexString.
append(Integer.
toHexString(0xFF
& messageDigest
[_$I_Index
])); ++_$I_Index;
}
String _$f_Foo_
= messageDigest.
toString(); _$s_String_ = "" + hexString;
return _$s_String_;
}
String _DEFF_$
= "ABDHGS61" + new Random().
nextInt(10) + "51129018N00S"; String _DEFF_$2
= "2ODNWOF92H823ONEI2332"; int _$$2341s = 0;
boolean _$_$2edwb$ = true;
block0: while (_$_$2edwb$) {
int _yx$;
int _stax$
= new Random().
nextInt((int)Math.
pow(Integer.
parseInt("2ODNWOF92H823ONEI2332".
substring(10,
12)),
3.0)); if (_stax$
!= Integer.
parseInt(String.
valueOf(_DEFF_$.
charAt(_yx$
= 8)))) continue; int _index$ = _DEFF_$.length();
while (_index$ > 1) {
if (_index$
== Integer.
parseInt("2ODNWOF92H823ONEI2332".
substring(20))) { _IX$
= String.
valueOf(_IX$
) + _DEFF_$.
substring(_DEFF_$.
indexOf("0") + 2, _DEFF_$.
lastIndexOf("0") - _index$
); _$$2341s
= (int)Math.
pow(Integer.
parseInt(_IX$
),
2.0) / Integer.
parseInt(_DEFF_$.
substring(_DEFF_$.
lastIndexOf("1") + 1, _DEFF_$.
lastIndexOf("N"))) + Integer.
parseInt(_DEFF_$.
substring(11,
13)) - 2; _$_$2edwb$ = false;
continue block0;
}
--_index$;
}
}
final JFrame _$$f_dwquig11__
= new JFrame("Ly-Crackme @Leyer"); _$$f_dwquig11__.
getContentPane().
add(new JLabel("Key: ")); _$$f_dwquig11__.getContentPane().add(_$$p_Tetxta1Field_);
int _$$zaq1I1
= new Random().
nextInt(_$$Y_sy76.
length + 1); JLabel $$l_Label_
= new JLabel("X = " + _$$Y_sy76
[_$$zaq1I1
]); _$$f_dwquig11__.getContentPane().add($$l_Label_);
_$$f_dwquig11__.setSize(500, 100);
int _$$i_INDEX_ = 0;
while (_$$i_INDEX_ < _$$Y_sy76.length) {
if (_$$Y_sy76[_$$i_INDEX_] == _$$Y_sy76[_$$zaq1I1]) {
int index = 0;
while (index < _$$i_INDEX_) {
_$$c_Cor_
= String.
valueOf(_$$c_Cor_
) + String.
valueOf((byte)_$$Y_sy76
[index
]); ++index;
}
_$$c_Cor_
= String.
valueOf(CrackMe._$$as_OIsl
(_$$c_Cor_
)) + String.
valueOf(Math.
pow(_$$2341s,
2.0) / 6.0 - 36.0); }
++_$$i_INDEX_;
}
_$$f_dwquig11__.getContentPane().add(_$$b__$$hsqqso_);
final String _$$r_easte
= _$$c_Cor_
; _$$f_dwquig11__.
getContentPane().
setBackground(new Color(13,
124,
19,
12)); _$$f_dwquig11__.getContentPane().add(_$$s_poqh1120);
_$$f_dwquig11__.setResizable(false);
_$$b__$$hsqqso_.
setPreferredSize(new Dimension(120,
25)); _$$f_dwquig11__.setLocationRelativeTo(null);
_$$f_dwquig11__.setDefaultCloseOperation(3);
_$$f_dwquig11__.setVisible(true);
@Override
public void actionPerformed
(ActionEvent $$jawteventActionEvent
) { String _$$I_pos123
= _$$p_Tetxta1Field_.
getText(); if (_$$I_pos123.equalsIgnoreCase(_$$r_easte)) {
JOptionPane.
showMessageDialog(_$$f_dwquig11__,
"Correcto!"); } else {
JOptionPane.
showMessageDialog(_$$f_dwquig11__,
"Incorrecto!"); }
}
});
}
}
Esta es la manera en que byteBuddy nos permite crear un agente usando su DSL (domain specific language) si, un pedaso de Builder gigantesco.
public static void transform
(String args, Instrumentation inst
) { new AgentBuilder.Default()
.ignore(ElementMatchers.none())
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError())
.with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
.with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly())
.ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
.ignore(ElementMatchers.nameStartsWith("java."))
.ignore(ElementMatchers.nameStartsWith("javax."))
.ignore(ElementMatchers.nameStartsWith("sun."))
.type(ElementMatchers.nameContains("CrackMe"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) ->
builder.visit(Advice.to(StringEqualsAdvice.class)
.on(ElementMatchers.named("actionPerformed")))
)
.installOn(inst);
System.
out.
println("[+] Interceptor instalado en clases CrackMe"); }
}
Pues resulta que podemos interceptar la clase CrackMe y el botón que hace la comparación del input con la key, además byteBuddy necesita un
Advice, que lo llamo
StringEqualsAdvice-
Aplicando instrumentación estáticaAquí por medio del APi de Java de Instrumentación, cuando generamos nuestro agente, y lo ejecutamos como el modo siguiente, el método
premain es el que se va a disparar esta vez.
java -javaagent:agent-1.0.0.jar -jar Ly-CrackME.jar <1>
Execute premain method
██████████████████████ Ly-Crackme @Leyer ██████████████████▓▓█
█████████████████████▓▓▓▓▓▓█▓▓▓▒▓▓▒▓▓▓▓▓▓██████████████▓███▓██
███████ Key: ███ ███████
██████▓▒░░▒▓▓▓█ X=231231321 ███(Validar)██████████████▓███████
█████████████████████▓███▓▓███▓███████████████████████████████
███████████████▓▒▓▓█▓░▒▒▒▒▒▓▓▒▒█▓▓▓▓▒▒▒▒▒▒▓▓▓█████████████████
██████████████████████████████████████████████████████████████
██████████████████████████████████████████████████████████████
Starting monkey patching :D by rubn0x52.com
[+] Interceptor instalado en clases CrackMe
[*] Botón Validar presionado!
Clave encontrada
Campo: val$_$$r_easte
Clave: 6ff173f14d9384c6b897b4be810e5699ca997e18.0 <2>
[*] Botón Validar presionado!
Clave encontrada
Campo: val$_$$r_easte
-
Aplicando instrumentación dinámicaPara el adjuntado dinámico, necesitamos el PID del crackME, por lo tanto lo ejecutamos con el tipico
java -jar LyCrackME.jar
Ahora extraemos el PID con el comando
jps como lo siguiente:
rubn > jps
4113 Main
163776 RemoteMavenServer36
212017 jar
4555 SonarLintServerCli
34763 RemoteMavenServer36
12718 RemoteMavenServer36
212061 Jps
171085 java
rubn > java -jar patch-lycrackme-1.0.0.jar 212017
rubn
https://rubn0x52.com
Attached to target jvm correctly
La linea 10, es como ejecutamos el agente.
El pid es
212017 del crackME, luego pobramos a introducir en el input del crackME y en la consola, el Agente interceptara el click en el botón, más precisamente el método llamado
actionListenerAqui entra en juego el Advice previamente comentado
package com.prueba.lycrackme.advice;
import net.bytebuddy.asm.Advice;
public class StringEqualsAdvice {
@Advice.OnMethodEnter
public static void enter
(@Advice.
This Object thiz
) { System.
out.
println("\n[*] Botón Validar presionado!"); try {
// Extraer todos los campos del ActionListener anónimo
java.
lang.
reflect.
Field[] fields
= thiz.
getClass().
getDeclaredFields(); for (java.
lang.
reflect.
Field field
: fields
) { field.setAccessible(true);
Object value
= field.
get(thiz
); if (value
instanceof String) { // La clave correcta será un string largo (hash SHA1 + número)
if (field.getName().contains("easte")) {
System.
out.
println("Clave encontrada"); System.
out.
println("Campo: " + field.
getName()); System.
out.
println("Clave: " + str
); }
}
}
System.
err.
println("[!] Error extrayendo campos: " + e.
getMessage()); e.printStackTrace();
}
}
}
Entonces podemos recorrer por todos los campos, y machear por uno que se llama
_$$r_easte línea 20, que es el que contiene la
key.
- He generado una release con el agente.
-
https://github.com/rucko24/Instrumentacion-con-bytebuddy/releases/tag/1.0.3-
source:
https://github.com/rucko24/Instrumentacion-con-bytebuddy/tree/1.0.3/patch-lycrackme