Outils pour utilisateurs

Outils du site


apk-hacking-en

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
apk-hacking-en [2014/10/27 12:16] – [Step 2 : Extract decompilated java sources] sebsauvageapk-hacking-en [2022/02/02 10:14] (Version actuelle) – supprimée sebsauvage
Ligne 1: Ligne 1:
-====== Hacking Android applications ====== 
  
- 
-<note important>This page is currently being translated. Please check back later for the final version.</note> 
- 
-===== Introduction ===== 
- 
-I use the term "hacking" in its noble meaning: Understand the inner workings and alter the behaviour in order to adapt it to our needs. 
- 
-In this page I will explain how to inspect and alter an Android application (.apk files).  My motivation is twofold: 
- 
-  * Have fun understanding how Android applications work and how to alter them (including Dalvik machine code). 
-  * Protect our privacy by disabled some features (GPS, etc.) 
- 
-//Side note//: English is not my primary language and I apologize in advance for mistakes and clumsiness. 
-===== Reverse-engineering APK files ===== 
- 
-APK is the standard Android application packaging format. Any APK file can be installed on an Android system as long as you have authorized third party application installation in system configuration. APK files are simple ZIP files which contain a certain set of files (descriptive XML files, resources such as images and other files, .dex files containing executable code...) 
- 
-Android applications are developed in Java, but compiled for a different virtual machine than the standard JVM. Android uses its own virtual machine named **Dalvik**. Its bytecode is different than the JVM. 
- 
-  * In standard Java, a **.java** source code is compiled in **.class** file (containing Java bytecode). Class files and other resources are packed into **.jar** files. 
-  * With Android, a **.java** source code is compiled in **.dex** file (containing Dalvik bytecode). Dex files and other resources are packed into **.apk** files. 
- 
-A specific java code giving //usually// the same bytecode, you can use some tools (like [[https://en.wikipedia.org/wiki/JAD_%28JAva_Decompiler%29|JAD]]) to "decompile" bytecode (.class) into java sources (.java). But this "decompilation" is far from perfect and is sometimes not possible. In all cases, it is not possible to recompile these java sources directly. 
- 
-The same goes for dex files: You cannot recompile resulting java sources. This is not an interesting path to alter Android applications. 
- 
-The right way to do it is to directly alter the Dalvik bytecode. 
- 
-<note>I will not provide here courses of Java and assembly language, but the knowledge of both will help to understand the article below.</note> 
- 
-**PS**: I performed this hack with no preliminary knowledge of Dalvik bytecode. 
-===== Tools ===== 
- 
-Here are the tools we are going to use: 
- 
-  * [[https://code.google.com/p/dex2jar/|dex2jar]] to convert .apk in .jar 
-  * [[http://jd.benow.ca/|JD-GUI]], an application to decompiler .jar files. 
-  * [[https://apkstudio.codeplex.com/|APK-Studio]], to alter the .dex files, re-generate .apk files and re-sign them (because I'm lazy). 
- 
-Why: 
- 
-  * Converting .apk in .jar and running them into JD-GUI will help us to inspect the code: We will get (for most .dex files) the corresponding java source code. This will make code inspection much easier than reading raw Dalvik code. 
-  * Once we have spotted the code we want to change, we will use APK-Studio to directly alter the corresponding Dalvik bytecode. 
- 
-APK-Studio permet de montrer le code machine Dalvik sous forme de source Smali. Smali est une sorte de langage assembleur qui donne du bytecode Dalvik. Le code Smali n'est pas très difficile à comprendre et se compare facilement au source Java. 
- 
-===== Practical case ===== 
- 
-Download the APK file of the application you want to alter, either by copy-pasting the GooglePlay URL in [[http://apps.evozi.com/apk-downloader/|this page]], either by using [[https://play.google.com/store/apps/details?id=mobi.infolife.appbackup|this application]] to backup the APK. 
- 
-As an example, we will remove the geolocation of the application [[https://play.google.com/store/apps/details?id=com.cavo.MonCAAlsace|Crédit Agricole Alsace Vosges]] (''com.cavo.MonCAAlsace.apk'', a French Bank application). Every time you want to browse your accounts, the application tries to geolocate you. There is not option to disable this. I do not find this behaviour acceptable. 
-==== Step 1 : Convert APK into JAR ==== 
- 
- 
-<code>./d2j-dex2jar.sh com.cavo.MonCAAlsace.apk</code> 
-or 
-<code>d2j-dex2jar.bat com.cavo.MonCAAlsace.apk</code> 
- 
-This will create the file **com.cavo.MonCAAlsace-dex2jar.jar**. 
- 
-==== Step 2 : Extract decompilated java sources ==== 
- 
-Run JD-GUI, open the .jar file created in previous step, then go to menu "Files" > "Save all sources...". 
- 
-This will create **com.cavo.MonCAAlsace-dex2jar.src.zip**. This files contains all decompiled java sources from the application. 
- 
-Notes: 
- 
-  * Pas de miracle: Ces sources java ne sont pas recompilables. 
-  * Certaines classes ou méthodes ne seront pas décompilées (parce-que JAD n'y sera pas parvenu). Dans ce cas, JD-GUI affiche directement le code Dalvik. 
- 
-Nous n'allons pas utiliser ces sources java pour les modifier. Nous allons juste les utiliser pour trouver que ce nous cherchons. 
- 
-Dézippez le fichier, ce qui vous permettra ensuite rechercher dans les sources (Je n'utilise par la recherche interne de JD-GUI car je ne la trouve pas fiable). 
- 
-==== Étape 3 : Rechercher ce que nous voulons modifier ==== 
- 
-Note importante: Un certain pourcentage d'applications Android ont leur code "obfusqué": Toutes les méthodes et attributs sont renommés (a/aa/ab/ac/....) afin de rendre le code incompréhensible. Cela complique en effet la lecture du code, mais ces applications doivent faire appel aux API Android qui doivent - elles - porter des noms explicites. On arrive donc généralement à retrouver ses petits. 
- 
-Dans notre cas, vous voulons empêcher l'application de faire appel aux fonctions GPS pour nous localiser. L'opération est donc assez simple: Localiser les appels aux API GPS et les neutraliser. 
- 
-Dans le SDK Android, les fonctions GPS sont gérées par le //LocationManager//. Nous allons donc simplement rechercher ce mot dans les sources. On les trouve là: 
- 
-  * \com\cavo\MonCAAlsace\Accueil\accueil.java 
-  * \com\cavo\MonCAAlsace\Bibliotheques\ARLayout.java 
-  * \com\cavo\MonCAAlsace\Quotidien\agences.java 
-  * \com\cavo\MonCAAlsace\Quotidien\geoloc_agence.java 
-  * \com\cavo\MonCAAlsace\Quotidien\ra_agences.java 
-  * \com\flurry\android\monolithic\sdk\impl\in.java 
- 
-Prenons en exemple la première, **accueil.java**: 
- 
-On trouve l'appel au LocationManager dans l'initialisation: 
- 
-<code java>      ... 
-      Global.Tablette = isTablet(this); 
-      AppRater.app_launched(getParent()); 
-      ((LocationManager)getSystemService("location")).requestLocationUpdates("network", 10000L, 0.0F, this); 
-      this.progressDialog = new ProgressDialog(getParent()); 
-      this.progressDialog.setCancelable(false); 
-      ...</code> 
- 
-Ils instancient un LocationManager, puis lui demandent une geolocalisation rapide (par le réseau), et quand c'est fait, appeler la callback ''onLocationChanged'' que possède ''this''. 
- 
-Pour cette classe, il suffit donc de neutraliser cette ligne. Allons-voir dans le source Dalvik. Accrochez-vous à votre caleçon, on plonge. 
- 
-==== Étape 4 : Modifier le code Smali/Dalvik ==== 
- 
-Lancez **APK-Studio**, menu File > APK. Dans la fenêtre qui s'affiche: 
-  * Project name: Entrez ce que vous voulez. Par exemple 'CA'. 
-  * APK Path: indiquez-lui votre fichier APK. 
-  * Project location: Créez un répertoire vide et indiquez-le là.  APK-Studio y placera ses fichiers de travail. 
- 
-Cliquez sur le bouton "Create" et laissez-le mouliner. 
- 
-Dans APK-Studio, ouvrez ''CA/smali/android/com/cavo/MonCAAlsace/Accueil/accueil.smali''. Vous devez voir un code qui commence comme cela: 
- 
-<code>.class public Lcom/cavo/MonCAAlsace/Accueil/accueil; 
-.super Landroid/app/Activity; 
-.source "accueil.java" 
- 
-# interfaces 
-.implements Landroid/location/LocationListener; 
- 
- 
-# static fields 
-.field private static final ALERT_DIALOG:I 
- 
-.field public static Actus:Landroid/widget/Button; 
- 
-.field public static Agences:Landroid/widget/Button; 
- 
-...</code> 
- 
-Il s'agit de la classe Accueil.java que nous voulons modifier.  
- 
-Que fait La ligne qui nous intéresse ? 
-<code java>((LocationManager)getSystemService("location")).requestLocationUpdates("network", 10000L, 0.0F, this);</code> 
- 
-  * Elle appelle la fonction getSystemService (en passant la valeur "location"). 
-  * Elle caste le résultat en LocationManager. 
-  * Elle appelle la méthode requestLocationUpdates en passant les paramètres "network", 10000, 0 et //this//. 
- 
-Voyons si vous vous y retrouvez dans le code Dalvik correspondant: 
-<code>    .line 146 
-    const-string v5, "location" 
-    move-object/from16 v0, p0 
-    invoke-virtual {v0, v5}, Lcom/cavo/MonCAAlsace/Accueil/accueil;->getSystemService(Ljava/lang/String;)Ljava/lang/Object; 
-    move-result-object v2 
-    check-cast v2, Landroid/location/LocationManager; 
-     
-    .line 147 
-    .local v2, "locMan":Landroid/location/LocationManager; 
-    const-string v3, "network" 
-    const-wide/16 v4, 0x2710 
-    const/4 v6, 0x0 
-    move-object/from16 v7, p0 
-    invoke-virtual/range {v2 .. v7}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V 
-</code> 
- 
-Pas si compliqué, hein ? 
- 
-Vous pouvez voir, dans la section ''.line 146'', l'appel (invoke) à la fonction getSystemService(), le stockage du résultat dans le registre v2, puis le casting en LocationManager. Et dans la section ''.line 147'', l'appel à la méthode requestLocationUpdates() avec différents paramètres. 
- 
-  * Dalvik utilise des registres (v0,v1,v2...) dans lesquels il charge les valeurs à traiter. 
-  * p1,p2,p3... sont les paramètres passés à la méthode.  p0 est équivalent à ''this''. 
-  * Les constantes sont signalées simplement avec leur type et leur valeur. 
-  * Les appels de méthode sont invoke-* 
-  * Les variables locales déclarées avec .local 
-  * etc. 
-  * Je ne vais pas rappeler ici l'intégralité de ce langage assembleur (voir [[http://source.android.com/devices/tech/dalvik/dalvik-bytecode.html|là]]), mais vous pouvez constater qu'on arrive assez facilement à retrouver la correspondance entre les instructions java et les instructions Dalvik. 
- 
-Note: Vous ne devez pas supprimer les directives ''.lines'' L'assembleur Smali/Dalvik s'en sert pour se repérer. 
- 
-Pour annuler complètement la ligne, on va effectuer une opération classique: la 'NOPer' (NOP est une instruction qui ne fait rien: "NOP" = "No OPeration"). 
- 
-Le code devient: 
-<code>    .line 146 
-    nop 
- 
-    .line 147 
-    nop</code> 
-     
-(Ne touchez pas ce qu'il y a avant ''.line 146'' ni à ce qu'il y a après ''.line 148''.) 
- 
-Il va nous falloir trouver tous les autres appels au LocationManager et les neutraliser. 
- 
-Voici les autres fichiers modifiés: 
- 
-  * **\CA\smali\com\cavo\MonCAAlsace\Bibliotheques\ARLayout.smali**: 
- 
-<code>    .line 50 
-    iget-object v0, p0, Lcom/cavo/MonCAAlsace/Bibliotheques/ARLayout;->locMan:Landroid/location/LocationManager; 
-    const-string v1, "network" 
-    const-wide/16 v2, 0x64 
-    const/high16 v4, 0x3f800000 
-    move-object v5, p0 
-    invoke-virtual/range {v0 .. v5}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V</code> 
- 
-<code>    .line 50 
-    nop</code> 
- 
- 
-  * **\CA\smali\com\cavo\MonCAAlsace\Quotidien\geoloc_agence.smali**: 
- 
-<code>    .line 101 
-    iget-object v0, p0, Lcom/cavo/MonCAAlsace/Quotidien/geoloc_agence;->lm:Landroid/location/LocationManager; 
-    const-string v1, "network" 
-    const-wide/16 v2, 0x2710 
-    const/4 v4, 0x0 
-    move-object v5, p0 
-    invoke-virtual/range {v0 .. v5}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V 
-</code> 
- 
-<code>    .line 101 
-    nop 
-</code> 
- 
-  * **\CA\smali\com\cavo\MonCAAlsace\Quotidien\ra_agences.smali**: 
- 
-<code>    .line 195 
-    sget-object v1, Lcom/cavo/MonCAAlsace/Quotidien/ra_agences;->ctx:Landroid/content/Context; 
-    const-string v2, "location" 
-    invoke-virtual {v1, v2}, Landroid/content/Context;->getSystemService(Ljava/lang/String;)Ljava/lang/Object; 
-    move-result-object v0 
-    check-cast v0, Landroid/location/LocationManager; 
- 
-    .line 196 
-    .local v0, "locMan":Landroid/location/LocationManager; 
-    const-string v1, "network" 
-    const-wide/16 v2, 0x2710 
-    const/4 v4, 0x0 
-    iget-object v5, p0, Lcom/cavo/MonCAAlsace/Quotidien/ra_agences;->gpsListener:Landroid/location/LocationListener; 
-    invoke-virtual/range {v0 .. v5}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V 
-</code> 
- 
-<code>    .line 195 
-    nop 
- 
-    .line 196 
-    .local v0, "locMan":Landroid/location/LocationManager; 
-    nop 
-</code> 
- 
-  * **\CA\smali\com\flurry\android\monolithic\sdk\impl\in.smali**: 
- 
-<code>    .line 161 
-    invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z 
-    move-result v0 
-    if-nez v0, :cond_0 
- 
-    .line 162 
-    iget-object v0, p0, Lcom/flurry/android/monolithic/sdk/impl/in;->f:Landroid/location/LocationManager; 
-    const-wide/32 v2, 0x1b7740 
-    const/4 v4, 0x0 
-    iget-object v5, p0, Lcom/flurry/android/monolithic/sdk/impl/in;->i:Lcom/flurry/android/monolithic/sdk/impl/io; 
-    invoke-static {}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper; 
-    move-result-object v6 
-    move-object v1, p1 
-    invoke-virtual/range {v0 .. v6}, Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;Landroid/os/Looper;)V 
-</code> 
- 
-<code>    .line 161 
-    nop 
- 
-    .line 162 
-    nop 
-</code> 
- 
- 
-==== Étape 5: Re-packager l'APK ==== 
- 
-Une fois les modifications apportées aux différentes classes dans APK-Studio, rien de plus simple pour générer l'APK correspondant: 
-  * Sauvegardez vos modifications: Menu Files > Save all. 
-  * Re-générez l'APK: Menu Project > Build. 
- 
-L'opération prendra un certain temps. 
- 
-Regardez ensuite dans votre répertoire projet /CA/build/rebuilt.apk. Voilà votre fichier .apk modifié prêt à être installé. 
- 
-Dé-installez l'application d'origine et installez ce nouvel APK. (Si l'application plante, c'est que vos modification ne sont pas correctes.) 
- 
-Dans notre cas, le lancement de l'application "Crédit Agricole" ne déclenchera plus l'appel au GPS (même si ce dernier n'est pas désactivé). 
- 
-===== Notes ===== 
- 
-  * Là nous avons neutralisé les appels aux fonctions de géolocalisation car l'application accepte de fonctionner sans, mais certaines applications refuseront. Dans ce cas, il vous faudra changer de stratégie: Leur fournir malgré tout les données, mais avec des latitutes/longitudes bidon (par exemple en allant modifier la callback onLocationChanged() du programme.) 
-  * Cette méthode vous obligera à re-faire votre hack à chaque mise à jour de l'application en question. 
-  * Les choses peuvent être plus compliquées pour les applications qui chargent dynamiquement du code. 
-  * L'obfuscation peut compliquer la compréhension du code. Dans ce cas il peut être utile de charger les sources générées par JD-GUI dans un IDE (IntelliJ, Eclipse...) afin de faire un peu de refactoring (renommage des méthodes et attributs), ce qui aidera grandement à comprendre le code. 
-  * Dans notre exemple nous avons juste NOPé le code qui nous embêtait, mais dans certains cas il vous faudra faire des choses plus complexes (renvoyer null directement (''return-void''), instancier un objet du bon type (non initialisé) et le renvoyer, shunter un saut conditionnel, etc.) 
apk-hacking-en.1414412182.txt.gz · Dernière modification : 2014/10/27 12:16 de sebsauvage