Désassembler une application Android (complément)

android

Cet article est un complément de celui de Julien.

Partons d’un APK Crackme01.apk. Le fichier est disponible ici.

Voici à quoi ressemble le Crack Me :
capture1Presentation

Deux methodes existent pour reverser une application android :

  1. La première avec dex2jar et jd-gui, cette méthode permet d’obtenir quasiment le code original, facile à analyser du code java et simple d’utilisation.Cependant avec cette méthode on ne peut pas modifier le code java (.class), nos ressources sont présentes sous la forme numérique uniquement dans les findviewbyid, par exemple.
  2. La seconde avec smali(assembleur) et baksmali(desassembleur), on retrouve ces outils dans apktool (d pour desassembler, b pour assembler).Lorsque l’on désassemble on obtient un code source smali, et on peut le réassembler. Une bible pour le code smali est présente ici : http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

 

Le but de ce crackme est de trouver le mot de passe pour la méthode 1.
Dans la seconde méthode, on ajoute un message rapide (Toasts) « Simple, non ? »

Methode 1 : Dex2jar et JD-GUI

On décompresse notre archive ZIP :

$ unzip Crackme01.apk 
Archive:  Crackme01.apk
  inflating: res/layout/activity_crack_me01.xml  
  inflating: res/menu/activity_crack_me01.xml  
  inflating: AndroidManifest.xml     
 extracting: resources.arsc          
 extracting: res/drawable-hdpi/ic_launcher.png  
 extracting: res/drawable-ldpi/ic_launcher.png  
 extracting: res/drawable-mdpi/ic_launcher.png  
 extracting: res/drawable-xhdpi/ic_launcher.png  
  inflating: classes.dex             
  inflating: META-INF/MANIFEST.MF    
  inflating: META-INF/CERT.SF        
  inflating: META-INF/CERT.RSA

Avant de continuer, on est obligé de vous parler de la machine Dalvik. Cette machine dalvik est une machine virtuelle utilisée par Android. Elle a été développée par Google pour ne pas utiliser la JVM. La différence notable avec la JVM est la gestion du registre. Pour la JVM, la gestion est basée sur la pile contrairement à la machine Dalvik qui est illimitée. Cette machine utilise un fichier .dex qui est le regroupement de l’ensemble des classes JAVA compilées.

Obtenons un jar de notre fichier .dex :
$ dex2jar classes.dex
dex2jar classes.dex -> classes-dex2jar.jar

Utilisons JD-GUI, afin de voir nos fichiers .class qui sont présents dans l’archive .JAR
jd-gui classes-dex2jar.jarjd-gui

Dans le fichier Crackme01.class on peut voir la ligne suivante :
final EditText localEditText = (EditText)findViewById(2131165185);

Cette ligne fait référence a un id, qui a pour intitulé motDePasse comme on peut le voir dans le fichier R.class :
public static final int motDePasse = 2131165185;

C’est l’EditText qui est utilisé pour saisir notre mot de passe.

On retourne dans le fichier Crackme01.class :

if ((localEditText.getText().toString() != null) && (localEditText.getText().toString().equals("oversimple")))
          localToast.setText(2130968580);

On voit que l’on compare notre EditText avec une chaîne de caractère « oversimple ». Cette chaine de caractère « oversimple » est notre mot de passe.

Méthode 2 : Smali & backsmali

Pour la deuxieme méthode avec smali et backsmali, on utilisera apktool qui contient un ensemble d’outils. De plus, celui ci est simple d’utilisation alors pourquoi s’en priver ?

On décompile notre APK.

$ apktool d Crackme01.apk reverseCrackme01/
I: Baksmaling...
I: Loading resource table...
I: Loaded.
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/pierre/apktool/framework/1.apk
I: Loaded.
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Done.
I: Copying assets and libs...

On obtient un répertoire reverseCrackme01 :

$ cd reverseCrackme01/
$ ls   
AndroidManifest.xml  apktool.yml  res  smali

La premiere chose a regarder est le Manifest :

$ cat AndroidManifest.xml 
<!--?xml version="1.0" encoding="utf-8"?-->

On peut voir que notre main est le fichier CrackMe01 car celui-ci possède les intents nécessaires (MAIN et LAUNCHER)

Regardons maintenant les fichiers avec le code source smali :

$ ls smali/fr/oversimple/crackme01/
BuildConfig.smali  CrackMe01$1.smali  CrackMe01.smali  R$attr.smali  R$drawable.smali  R$id.smali  R$layout.smali  R$menu.smali  R$string.smali  R$style.smali  R.smali

Si on regarde dans le fichier CrackMe01\$1.smali, on peut voir la méthode onClick. Cette méthode correspond à un clic sur le bouton « Valider ». Voici un bref aperçu du code smali :

invoke-interface {v0}, Landroid/text/Editable;-&gt;toString()Ljava/lang/String;
move-result-object v0
const-string v1, "oversimple"
invoke-virtual {v0, v1}, Ljava/lang/String;-&gt;equals(Ljava/lang/Object;)Z
move-result v0

Ce bout de code permet de comparer notre mot de passe « oversimple » avec notre EditText(dans le but de simplifier, on affiche uniquement le retour du toString)

Et le test de comparaison final :

if-eqz v0, :cond_0
 
.line 29
iget-object v0, p0, Lfr/oversimple/crackme01/CrackMe01$1;-&gt;val$toast:Landroid/widget/Toast;
const v1, 0x7f040004
invoke-virtual {v0, v1}, Landroid/widget/Toast;-&gt;setText(I)V
 
.line 33
:goto_0
iget-object v0, p0, Lfr/oversimple/crackme01/CrackMe01$1;-&gt;val$toast:Landroid/widget/Toast;
invoke-virtual {v0}, Landroid/widget/Toast;-&gt;show()V
 
.line 34
return-void
 
.line 31
:cond_0
iget-object v0, p0, Lfr/oversimple/crackme01/CrackMe01$1;-&gt;val$toast:Landroid/widget/Toast;
const v1, 0x7f040005
invoke-virtual {v0, v1}, Landroid/widget/Toast;-&gt;setText(I)V
goto :goto_0

Si l’instruction if-eqz est égale à 0 alors nous allons à la condition cond_0. sinon on continue la suite donc .line 29.
Pour information, les valeurs qui nous intéressent se trouvent dans le fichier R$string.smali :
.field public static final ok:I = 0x7f040004
.field public static final ko:I = 0x7f040005

Le but de la deuxième méthode n’étant pas forcement de voir le mot de passe mais d’ajouter un message au démarrage de l’application.

Dans le fichier CrackMe01.smali, ligne 37 et après nous avons :

const-string v4, ""
 
const/4 v5, 0x1
 
invoke-static {v3, v4, v5}, Landroid/widget/Toast;-&gt;makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
 
move-result-object v1

Nous souhaitons juste ajouter notre message, donc à la place de «  » mettons : « Simple, non ? » et appelons la méthode afin de le rendre visible :
invoke-virtual {v1}, Landroid/widget/Toast;->show()V

Ce qui donne :

const-string v4, "Simple, non ?"
 
const/4 v5, 0x1
 
invoke-static {v3, v4, v5}, Landroid/widget/Toast;-&gt;makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
 
move-result-object v1
 
invoke-virtual {v1}, Landroid/widget/Toast;-&gt;show()V

On reconstruit l’application avec apktool b, il faut se placer dans le répertoire racineCrackme01 (ou ce trouve le fichier apktool.yml)

$ apktool b 
I: Checking whether sources has changed...
I: Smaling...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...

Un nouveau repertoire apparait dist/

On crée une clé afin de signer notre application :
keytool -genkey -v -keystore oversimple.keystore -alias oversimple -keyalg RSA -validity 25000

Une fois la clé créée, on signe notre application :
jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore oversimple.keystore dist/Crackme01.apk oversimple

Notre apk est signée de source inconnu.

On envoie notre apk :

adb install dist/Crackme01.apk 
978 KB/s (184902 bytes in 0.184s)
	pkg: /data/local/tmp/Crackme01.apk
Success

Un article suivant présentera les commandes utiles de ADB.

Résultat au démarrage de notre APK :

resultatFinal

Conclusion

Pour cette introduction au reverse d’application Android, rien de bien difficile, plusieurs articles en tête, notammennt un article sur les commandes adb et les pouvoirs de cette commande 😉

Sources

dex2jar : http://code.google.com/p/dex2jar/
jd-gui : http://java.decompiler.free.fr/?q=jdgui
apktool : http://code.google.com/p/android-apktool/

It’s oversimple isn’t it?