La Ingeniería Inversa (Reversing) en Android consiste en desensamblar una aplicación (APK) para estudiar su lógica, extraer secretos o modificar su comportamiento (Patching). En esta guía abordaremos el parcheo de vulnerabilidades en InsecureBankv2 y cómo saltarse los controles del famoso CTF KGB Messenger.
El código Java/Kotlin que escriben los desarrolladores se compila a un formato bytecode llamado DEX (Dalvik Executable). Para analizarlo, tenemos dos caminos:
JADX o la combinación dex2jar + JD-GUI intentan reconstruir el código Java original. Es ideal para leer y entender la lógica, pero no se puede recompilar de vuelta a APK.Apktool, convertimos el DEX a Smali, una representación en texto del lenguaje de ensamblador de la Máquina Virtual de Android. El código Smali es feo y difícil de leer, pero sí se puede alterar y volver a compilar.En el laboratorio anterior vimos que la actividad .PostLogin estaba exportada, permitiendo un Bypass del Login. Vamos a parchear la APK para arreglar la vulnerabilidad.
# 1. Desensamblar la APK original:
apktool d InsecureBankv2.apk -o InsecureBank_Source
# 2. Abrir InsecureBank_Source/AndroidManifest.xml con tu editor.
# Cambiar: android:exported="true" -> android:exported="false"
# 3. Recompilar la APK a partir de la carpeta modificada:
apktool b InsecureBank_Source -o InsecureBank_Patched.apk
# 4. Firmar la nueva APK (Android no instala apps sin firma):
# Generar una clave falsa:
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
# Firmar la APK:
apksigner sign --ks my-release-key.keystore InsecureBank_Patched.apk
# 5. Instalar la versión parcheada en el dispositivo:
adb install InsecureBank_Patched.apk
El CTF KGB Messenger es una app que, al abrirla, comprueba si el idioma de tu dispositivo está en ruso ("Russia"). Si no lo está, la app se cierra. Nuestro objetivo es parchear el binario para saltarnos este control.
Abriendo la APK en JADX, vemos algo como esto en MainActivity.java:
String locale = Locale.getDefault().getCountry();
if (!locale.equals("RU")) {
System.exit(0);
}
Desensamblamos con Apktool y abrimos smali/com/kgb/messenger/MainActivity.smali. Buscamos la instrucción de salto condicional (Branching).
# Código Smali original:
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-eqz v0, :cond_0 # "if-eqz" significa "If Equal to Zero" (Si NO son iguales, salta a cond_0 que cierra la app)
...
:cond_0
invoke-static {v0}, Ljava/lang/System;->exit(I)V
El Parcheo: Cambiamos la instrucción if-eqz por if-nez (If Not Equal to Zero). Ahora la lógica se invierte: la app se cerrará solo si el dispositivo ESTÁ en ruso. Recompilamos, firmamos y la app se abrirá en nuestro emulador en inglés.
Te has infiltrado en el código ensamblador (Smali) de un Malware bancario. La app realiza una comprobación de seguridad: verifica si el dispositivo está "Rooteado". Demuestra tus habilidades de Reversing indicando cómo manipular las instrucciones para burlar esta defensa.
>_ INICIAR RETO CTF 27Una vez dentro del KGB Messenger, nos pide un usuario y contraseña. En el código Java descompilado (JADX), vemos que la app carga un string llamado user_name y comprueba la contraseña contra un MD5.
# En InsecureBank_Source/res/values/strings.xml encontramos:
<string name="user_name">Stearling Archer</string>
<string name="flag_part1">RkxBR3tLNEc4X...</string>
La contraseña no está en el código, pero aplicando OSINT/Ingeniería Social sobre el personaje "Sterling Archer", deducimos que la contraseña es Guest. Al introducirla, la app nos da acceso y podemos descifrar los mensajes en AES que están hardcodeados en MessengerActivity.java.
| Instrucción | Significado Lógico |
|---|---|
if-eqz v0, :cond_0 | If Equal Zero (Si v0 == 0 / false, salta a cond_0) |
if-nez v0, :cond_0 | If Not Equal Zero (Si v0 != 0 / true, salta a cond_0) |
move-result v0 | Guarda el resultado de la última función en el registro v0 |
const/4 v0, 0x1 | Asigna el valor 1 (true) al registro v0 |
goto :goto_0 | Salto incondicional hacia la etiqueta :goto_0 |