Introducción
- Pueden descargar el crackme #1 de hackplayers aquí
Cada vez voy aprendiendo más a la hora de resolver, modificar y hacer ingeniería inversa a las aplicaciones de Android. Y le he cogido gusto a resolver crackmes, la verdad es que me van pareciendo cada vez más sencillos. Así que… ¡Empecemos!
Comportamiento de la app
Instalamos el apk y vemos la pantalla:
E introducimos datos de prueba (usuario: mgp25 y contraseña: 12345).
Y al darle a Login
nos muestra: Login incorrecto
.
Análisis
¡Hora de analizar el código! Por cierto, estoy usando APK Analyser.
Siguiendo el código llegamos a esto:
Que básicamente lo que hace es comprobar que el usuario sea admin3
y la contraseña es modificada por el método doConvert
, y que comprueba que el resultado sea igual a la contraseña introducida. Si se introduce el usuario o la contraseña mal, nos llevará al mismo lugar: Login incorrecto
.
Aquí podeis ver el código de mejor manera:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
.local v0 -> java.lang.String password
1C 61 const-string v3, "PBAGENFRAN456"
1E 61 invoke-static {v3}, com.hpys.crackmes.crackme1hpys.doConvert(java.lang.String)java.lang.String
21 61 move-result-object v1
.local v1 -> java.lang.String secreto
22 63 const-string v3, "admin3"
24 63 invoke-virtual {v2, v3}, java.lang.String.equals(java.lang.Object)boolean
27 63 move-result v3
28 63 if-eqz v3, COND_3C:
2A 63 invoke-virtual {v0, v1}, java.lang.String.equals(java.lang.Object)boolean
2D 63 move-result v3
2E 63 if-eqz v3, COND_3C:
30 64 iget-object v3, p0, com.hpys.crackmes.crackme1hpys$1.this$0:com.hpys.crackmes.crackme1hpys
#getter for: com.hpys.crackmes.crackme1hpys.lblResult:android.widget.TextView
32 64 invoke-static {v3}, com.hpys.crackmes.crackme1hpys.access$2(com.hpys.crackmes.crackme1hpys)android.widget.TextView
35 64 move-result-object v3
36 64 const-string v4, "\u00a1Bien hecho!"
38 64 invoke-virtual {v3, v4}, android.widget.TextView.setText(java.lang.CharSequence)void
GOTO_3B:
3B 68 return-void
COND_3C:
3C 66 iget-object v3, p0, com.hpys.crackmes.crackme1hpys$1.this$0:com.hpys.crackmes.crackme1hpys
#getter for: com.hpys.crackmes.crackme1hpys.lblResult:android.widget.TextView
3E 66 invoke-static {v3}, com.hpys.crackmes.crackme1hpys.access$2(com.hpys.crackmes.crackme1hpys)android.widget.TextView
41 66 move-result-object v3
42 66 const-string v4, "Login incorrecto."
44 66 invoke-virtual {v3, v4}, android.widget.TextView.setText(java.lang.CharSequence)void
47 66 goto GOTO_3B:
|
Podemos extraer el método doConvert
y pasarle el String para que nos devuelva la verdadera contraseña. Así que obtenemos las clases del apk y la pasamos a java.
Aquí se ve mucho mejor:
1
2
3
4
5
6
7
8
9
10
11
12
|
public void onClick(View paramView)
{
String str1 = crackme1hpys.access$0(this.this$0).getText().toString();
String str2 = crackme1hpys.access$1(this.this$0).getText().toString();
String str3 = crackme1hpys.doConvert("PBAGENFRAN456");
if ((str1.equals("admin3")) && (str2.equals(str3)))
{
crackme1hpys.access$2(this.this$0).setText("¡Bien hecho!");
return;
}
crackme1hpys.access$2(this.this$0).setText("Login incorrecto.");
}
|
Solución
Y aquí tenemos el código que nos devuelve la contraseña correcta:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import java.io.*;
public class clave
{
public static String doConvert(String s)
{
int abyte = 0;
StringBuffer localStringBuffer = new StringBuffer();
int i = 0;
do
{
int j = s.length();
if(i >= j)
return localStringBuffer.toString();
abyte = s.charAt(i);
int k = abyte & 0x20;
int l = abyte;
int i1 = ~k;
abyte = l & i1;
int j1;
char c;
StringBuffer localStringBuffer2;
if(abyte >= 65 && abyte <= 90)
j1 = ((abyte - 65) + 13) % 26 + 65;
else
j1 = abyte;
abyte = j1 | k;
c = (char)abyte;
localStringBuffer2 = localStringBuffer.append(c);
i++;
} while(true);
}
public static void main(String[] args)
{
System.out.println("La contraseña es: " + doConvert("PBAGENFRAN456"));
}
}
|
Probamos a ver si funciona esto…
¡Bien! Hemos conseguido que funcione. Pero sin embargo yo quiero que funcione con cualquier usuario y con cualquier contraseña, así que vamos a modificar el bytecode para que haga lo que nosotros queremos.
Anteriormente, puse el código smali, así que simplemente citaré el código donde se hace la comparación del usuario y la contraseña y según su resultado, vaya a un lado u otro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
const-string v3, "PBAGENFRAN456"
invoke-static {v3}, Lcom/hpys/crackmes/crackme1hpys;->doConvert(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
.line 63
.local v1, secreto:Ljava/lang/String;
const-string v3, "admin3"
invoke-virtual {v2, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v3
if-eqz v3, :cond_0
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v3
if-eqz v3, :cond_0
|
Cambiamos esto:
1
|
invoke-virtual {v2, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
A esto otro..
1
|
invoke-virtual {v2, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
Y esto:
1
|
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
a esto…
1
|
invoke-virtual {v0, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
Construímos e instalamos de nuevo la apk, y probamos a ver si funciona:
¡Reto superado con éxito!
Espero que os haya gustado, ¡y hasta la siguiente entrada!