Nuestro segundo crackme para Android (y último reto del año) consistía en evadir la implementación del proceso de licenciamiento de Android o Android License Verification Library (ALVL). La aplicación era muy sencilla pero, eso sí, tenía alguna trampa ;)
El ganador del reto, Jose Ayerdis (Necronet) de Nicaragua, ha publicado un completo solucionario en su blog , que recomendamos que visitéis para ver más tips adicionales y otros interesantes artículos.
También quería dar las gracias a todos los que habéis intentado solucionar el reto. Por último, os dejo con el procedimiento seguido por Necronet:
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:
Así que puedes revisar en la carpeta com/hpys/crackmes/LicenseCheck.smali. Veras mucho código, si tienes alguna experiencia con lenguaje ensamblador no te parecerá tan raro, sino estudia un poco y veras que sencillo que es.
Si miras bien en la linea 123 hay un doCheck este llama a un método en la misma clase LicenseCheck pero que hace realmente este método veamos:
Ahora es claro que el método doCheck hace la revisión, 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 lógico ahora sera ir a explorar la clase com/android/vending/licensing/LicenseChecker
Probablemente este método nos proporcione mejores pista que cualquier otro por que es donde se lleva acabo la revisión de la licencia.
El método checkAccess, es bastante grande así que procurare resumir las partes relevantes, por ejemplo:
if-eqz v1, :cond_0 esta condición es muy importante por que en caso de cumplirse te envía 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 fácil de hacer esta condición tiene una operación antagónica la cual es: if-nez vx,target así que al cambiar las operaciones debería 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 obstáculo 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 qué no funciona es clara: la clase MyAndroidAppActivity no tiene la invocación al metodo onCreate y hará falta agregárselo con backsmali.
El código anterior demuestra muchas faltas en la clase MyAndroidAppActivity, siendo un código pequeño y sencillo es fácil reconocerlas todas:
Podemos realizar los siguientes apuntes, como la invocación del método 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 único que falta es recompilarlo y empaquetarlo para regresarlo a un APK.
De regreso a un APK
A como mencione inicialmente apktool también 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 teléfono. Para recompilar la aplicación ejecuta el comando:
Tambien necesitas firmarlo, para ello necesitas de un keystore, puedes crearlo facilmente con keytool
Ahora ya tienes tu keystore para firmar tu aplicación
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.
Si todo esta bien, la imagen que debería aparecer es la siguiente:
Y LISTO!!
El ganador del reto, Jose Ayerdis (Necronet) de Nicaragua, ha publicado un completo solucionario en su blog , que recomendamos que visitéis para ver más tips adicionales y otros interesantes artículos.
También quería dar las gracias a todos los que habéis intentado solucionar el reto. Por último, os dejo con el procedimiento seguido por Necronet:
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 código decompilado backsmali.
Luego de seguir la instalación del APKTool procede a ejecutar el comando para extraer el APK.
1 | $apktool d cracme2hpys.apk out |
*out es el directorio donde se descomprime el apk.
Husmeando el directorio extraído
Lo primero que pensé es bypasear cambiando la clase en el AndroidManifest.xml que es la que comienza la aplicación, pero no tuve éxito.
Así que tuve que husmear el código 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.
Así que tuve que husmear el código 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.
Busca en el onCreate de LicenseCheck.smali el código donde revisa la licencia se realiza una invocacion a un metodo doCheck().
1 2 3 4 5 6 7 8 9 10 11 12 13 | invoke-direct {v1, p0, v2, v3}, Lcom/android/vending/licensing/LicenseChecker;-> .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 un doCheck este llama a un método en la misma clase LicenseCheck pero que hace realmente este método veamos:
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 | .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 |
Antes de empezar a leer todo el LicenseChecker y sus derivados, mejor ve directamente a la invocación del método checkAccess que es el que invoca la clase LicenseCheck recuerdas?.
1 | invoke-virtual {v0, v1}, Lcom/android/vending/licensing/LicenseChecker;->checkAccess(Lcom/android/vending/licensing/LicenseCheckerCallback;)V |
Probablemente este método nos proporcione mejores pista que cualquier otro por que es donde se lleva acabo la revisión de la licencia.
El método checkAccess, es bastante grande así que procurare resumir las partes relevantes, por ejemplo:
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 | # 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 condición es muy importante por que en caso de cumplirse te envía 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 fácil de hacer esta condición tiene una operación antagónica la cual es: if-nez vx,target así que al cambiar las operaciones debería 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 obstáculo adicional, al pasar la licencia el MyAndroidAppActivity no parece invocar al metodo onCreate, y te genera el siguiente error en logcat:
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 | . class public Lcom/hpys/crackmes/MyAndroidAppActivity; . super Lcom/hpys/crackmes/LicenseCheck; .source "MyAndroidAppActivity.java" # direct methods .method public constructor .locals 0 .prologue .line 6 invoke-direct {p0}, Lcom/hpys/crackmes/LicenseCheck;-> 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 código anterior demuestra muchas faltas en la clase MyAndroidAppActivity, siendo un código pequeño y sencillo es fácil reconocerlas todas:
- El método onCreate no llama al super.onCreate.
- El método onCreate tampoco tiene layout asignado debería tener main.xml con setContentView.
- La clase MyAndroidAppActivity hereda de LicenseCheck en vez de Activity y tambien en el método init se hace la invocación especial a este metodo.
Aquí el código del MyAndroidAppActivity con las fallas anteriores resueltas:
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 | . class public Lcom/hpys/crackmes/MyAndroidAppActivity; . super Landroid/app/Activity; .source "MyAndroidAppActivity.java" # direct methods .method public constructor .locals 0 .prologue .line 6 invoke-direct {p0}, Landroid/app/Activity;-> 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 |
De regreso a un APK
A como mencione inicialmente apktool también 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 teléfono. Para recompilar la aplicación ejecuta el comando:
1 | $ apktool b out crackemecracked.apk |
1 | $ keytool -genkey - v -keystore my-release-key.keystore |
Ahora ya tienes tu keystore para firmar tu aplicación
1 | 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.
1 2 | $ adb uninstall com.hpys.crackmes $ adb install crackemecracked-za.apk |
Si todo esta bien, la imagen que debería aparecer es la siguiente:
Y LISTO!!
Comentarios
Publicar un comentario