Para hacer un poco de prologo revisa el Reto 14: Android crackme #2, es una interesante publicación que te retan a pasarte el licenciamiento de Android de un APK; así que es la excusa perfecta para aprender un poco de decompilado de Android, el cual hasta el momento sabia de manera teorica y nunca habia tenido una motivación mas alla de simplemente ser "el sabiondo teorico" para pasar a ser un curioso pragmatico, así que gracias a Hackerplayers por el reto.
Aclaraciones
Este post no es un explicativo profundo acerca de la forma que Android compila las clases y empaqueta el APK. Tampoco voy a explicar que es Smali/Backsmali (código decompilado) para ello ya hay buenos blogs , como Dissasembling Dex File y claro Android Cracking el ultimo un cracker de Android te cuenta muchos secretos y trucos acerca de código decompilado.
Este post es más acerca de como te pasas el licenciamiento de seguridad resolviendo el Reto 14: Android crackme #2. Asi que empezemos a divertirnos aqui esta mi respuesta (la cual fue aprobada por el autor del blog):
Descarga el APKTool
El apktool es una herramienta maravillosa, si te quieres hacer de esto de cracking aplicaciones android el apktool es un fiel compañero, permite realiza muchas cosas entre ellas:
- Extraer y decompilar fuentes de empaquetados Android(apktool), esto incluye recursos(res), manifiesto(AndroidManifest), y fuentes decompiladas.
- Recompilar dichas fuentes y volverlas a empaquetar.
- Depurar codigo decompilado backsmali.
Luego de seguir la instalacion del APKTool procede a ejecutar el comando para extraer el APK.
$apktool d cracme2hpys.apk out
*out es el directorio donde se descomprime el apk.
Husmeando el directorio extraido
Lo primero que pense es bypasear cambiando la clase en el AndroidManifest.xml que es la que comienza la aplicacion, pero no tuve exito.
Asi que tuve que husmear el codigo decompilado. El AndroidManifest.xml siempre te da la pista de donde comenzar en general procuro que sea la Actividad inicial, por que es donde probablemente se de la invocación del ALVL.
Asi que tuve que husmear el codigo decompilado. El AndroidManifest.xml siempre te da la pista de donde comenzar en general procuro que sea la Actividad inicial, por que es donde probablemente se de la invocación del ALVL.
Asi que puedes revisar en la carpeta com/hpys/crackmes/LicenseCheck.smali. Veras mucho codigo, si tienes alguna experiencia con lenguaje ensamblador no te parecera tan raro, sino estudia un poco y veras que sencillo que es.
Busca en el onCreate de LicenseCheck.smali el codigo donde revisa la licencia se realiza una invocacion a un metodo doCheck().
invoke-direct {v1, p0, v2, v3}, Lcom/android/vending/licensing/LicenseChecker;->(Landroid/content/Context;Lcom/android/vending/licensing/Policy;Ljava/lang/String;)V
.line 120
iput-object v1, p0, Lcom/hpys/crackmes/LicenseCheck;->mChecker:Lcom/android/vending/licensing/LicenseChecker;
.line 123
invoke-direct {p0}, Lcom/hpys/crackmes/LicenseCheck;->doCheck()V
.line 125
return-void
Si miras bien en la linea 123 hay hay un doCheck este llama a un metodo en la misma clase LicenseCheck pero que hace realmente este metodo veamos:
.method private doCheck()V
.locals 2
.prologue
.line 106
iget-object v0, p0, Lcom/hpys/crackmes/LicenseCheck;->mChecker:Lcom/android/vending/licensing/LicenseChecker;
iget-object v1, p0, Lcom/hpys/crackmes/LicenseCheck;->mLicenseCheckerCallback:Lcom/android/vending/licensing/LicenseCheckerCallback;
invoke-virtual {v0, v1}, Lcom/android/vending/licensing/LicenseChecker;->checkAccess(Lcom/android/vending/licensing/LicenseCheckerCallback;)V
.line 107
return-void
.end method
Ahora es claro que el metodo doCheck hace la revision, y llama a la clase LicenseChecker y aparentemente le pasa un callback LicenseCheckerCallback probablemente para informar que el licensamiento se realizo de forma correcta. Entonces el paso mas logico ahora sera ir a explorar la clasecom/android/vending/licensing/LicenseChecker
Antes de empezar a leer todo el LicenseChecker y sus derivados, mejor ve directamente a la invocacion del metodo checkAccess que es el que invoca la clase LicenseCheck recuerdas?.
invoke-virtual {v0, v1}, Lcom/android/vending/licensing/LicenseChecker;->checkAccess(Lcom/android/vending/licensing/LicenseCheckerCallback;)V
Probablemente este metodo nos proporcione mejores pista que cualquier otro por que es donde se lleva acabo la revision de la licencia.
El metodo checkAccess, es bastante grande así que procurare resumir las partes relevantes, por ejemplo:
# virtual methods
.method public declared-synchronized checkAccess(Lcom/android/vending/licensing/LicenseCheckerCallback;)V
.locals 9
.parameter "callback"
.prologue
.line 133
monitor-enter p0
:try_start_0
iget-object v1, p0, Lcom/android/vending/licensing/LicenseChecker;->mPolicy:Lcom/android/vending/licensing/Policy;
invoke-interface {v1}, Lcom/android/vending/licensing/Policy;->allowAccess()Z
move-result v1
if-eqz v1, :cond_0
.line 134
const-string v1, "LicenseChecker"
if-eqz v1, :cond_0 esta condicion es muy importante por que en caso de cumplirse te envia a cond_0 y mas abajo indica que es la instanciacion del validador de licencias. Si nos saltamos esta parte tendremos el ejercicio terminado!!. Es bien facil de hacer esta condicion tiene una operacion antagonica la cual es: if-nez vx,target asi que al cambiar las operaciones deberia funcionar.
Pero no funciona.... ¬¬
Si, si, cambiamos esta linea y ejecutamos el paso de recompilación de codigo y reempaquetamiento (lo explicare luego), el reto nos regala un obstaculo adicional, al pasar la licencia el MyAndroidAppActivity no parece invocar al metodo onCreate, y te genera el siguiente error en logcat:
¿Así que pasa? ¿por que no funciona?, Bueno la respuesta del por que no funciona es clara la clase MyAndroidAppActivity no tiene la invocación al metodo onCreate hara falta agregarselo con backsmali.
.class public Lcom/hpys/crackmes/MyAndroidAppActivity; .super Lcom/hpys/crackmes/LicenseCheck; .source "MyAndroidAppActivity.java" # direct methods .method public constructor()V .locals 0 .prologue .line 6 invoke-direct {p0}, Lcom/hpys/crackmes/LicenseCheck;->()V return-void .end method # virtual methods .method public onCreate(Landroid/os/Bundle;)V .locals 0 .parameter "savedInstanceState" .prologue .line 11 invoke-super {p0, p1}, Lcom/hpys/crackmes/LicenseCheck;->onCreate(Landroid/os/Bundle;)V .line 15 return-void .end method
El codigo anterior demuestra muchas faltas en la clase MyAndroidAppActivity, siendo un codigo pequeño y sencillo es facil reconocerlas todas:
- El metodo onCreate no llama al super.onCreate.
- El metodo onCreate tampoco tiene layout asignado deberia tener main.xml con setContentView.
- La clase MyAndroidAppActivity hereda de LicenseCheck en vez de Activity y tambien en el metodo init se hace la invocacion especial a este metodo.
Aqui el codigo del MyAndroidAppActivity con las fallas anteriores resueltas:
.class public Lcom/hpys/crackmes/MyAndroidAppActivity; .super Landroid/app/Activity; .source "MyAndroidAppActivity.java" # direct methods .method public constructor()V .locals 0 .prologue .line 6 invoke-direct {p0}, Landroid/app/Activity;-> ()V return-void .end method # virtual methods .method public onCreate(Landroid/os/Bundle;)V .locals 1 .parameter "savedInstanceState" .prologue .line 15 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V .line 17 const/high16 v0, 0x7f03 invoke-virtual {p0, v0}, Lcom/hpys/crackmes/MyAndroidAppActivity;->setContentView(I)V .line 20 return-void .end method
Podemos realizar los siguientes apuntes, como la invocacion del metodo onCreate() y de setContentView con la variable v0, en este tienes que tener sumo cuidado en declarar locals 1 que es el numero de variables que utilizaras.
¿Ya terminamos?, algo así lo unico que falta es recompilarlo y empaquetarlo para regresarlo a un APK.
De regreso a un APK
A como mencione inicialmente apktool tambien te permite recompilar la aplicación y regresarla a un APK, pero vas a necesitara un poco mas de eso para colocarla devuelta en el telefono. Para recompilar la aplicacion ejecuta el comando:
$ apktool b out crackemecracked.apkTambien necesitas firmarlo, para ello necesitas de un keystore, puedes crearlo facilmente con keytool
$ keytool -genkey -v -keystore my-release-key.keystore
Ahora ya tienes tu keystore para firmar tu aplicacion
jarsigner -verbose -keystore keystore.keystore crackemecracked.apk crackmecracked
Si deseas saber mas de como firmar aplicaciones android desde consola no te olvides pasar por la documentación oficial.
Ahora si tenemos la aplicacion firmada, es muy sencillo desintalarla y volverla instalar con el adb.
$ adb uninstall com.hpys.crackmes $ adb install crackemecracked-za.apk
Si todo esta bien, la imagen que deberia aparecer es la siguiente:
Y LISTO!!
¿Algunos Tips adicionales ?
En lo particular nunca habia realizado esto, y la informacion de como modificar codigo backsmali no es muy amplia, pero es posible y no es tan dificil.
- Te recomiendo que veas algo de codigo Assembler por que es similar al backsmali basicamente son operadores y cambios registros.
- Te recomiendo que veas algo de codigo Assembler por que es similar al backsmali basicamente son operadores y cambios registros.
- Cuando estaba perdido con alguna operación acudia a Dalvik OpCode el cual fue como un diccionario para mí.
- Tambien cree clases sencillas, como el hola mundo o una imagen para ver como se decompilaba y como se veia.
- No hay necesidad de revisar todas las clases como LicenseChecker$ResultListener$1 por que se refiere a clases internas (anonimas o declaradas) en el archivo, así que obviemos eso por un momento y dediquemonos al metodo doCheckAccess en la clase LinceseChecker.
- Para la parte de la recompilación y empaquetamiento me hice un shellscript por si quieres utilizarlo.
- No hay necesidad de revisar todas las clases como LicenseChecker$ResultListener$1 por que se refiere a clases internas (anonimas o declaradas) en el archivo, así que obviemos eso por un momento y dediquemonos al metodo doCheckAccess en la clase LinceseChecker.
- Para la parte de la recompilación y empaquetamiento me hice un shellscript por si quieres utilizarlo.
- Te recomiendo dos excelentes presentaciones de I/O.
Google I/O 2008 - Dalvik Virtual Machine Internals
Google I/O 2010 - A JIT Compiler for Android's Dalvik VM






1 comentario:
tienes un muy buen blog amigo, felicidades, lastima que no tengas mucha difucion :S
Publicar un comentario en la entrada