Table des matières

Hacking d'​applications Android

Introduction

J'utilise ici le terme "hacking" dans son sens noble: Comprendre le fonctionnement et modifier pour l'adapter à ses besoins.

Je vais donc décrire ici la manière d'examiner et modifier une application Android (fichier .apk). La motivation est double:

L'ingénierie inverse de fichiers APK

APK est le format standard de packaging d'applications Android. N'importe quel fichier APK est installable sur un système Android tant que vous avez autorisé l'installation d'applications tierces (dans la configuration d'Android). En fait, les fichiers APK sont de simples fichiers ZIP contenant un certain nombre de fichier (fichiers XML descriptifs, fichier de données, fichiers .dex contenant les programmes…)

Les applications Android sont développées en Java, mais compilées pour une machine virtuelle différente de celle de Java: Au lieu d'utiliser la JVM, Android utilise une machine virtuelle appelée Dalvik. Son code machine est bien entendu différent de celui de la JVM.

Un même code Java donnant habituellement à peu près les mêmes bytecodes, il existe des outils (comme JAD) capables de "décompiler" des .class en .java, mais cette décompilation n'est pas toujours possible et dans la quasi-totalité des cas, les fichiers java ne sont de toute manière pas recompilables.

Il en va de même pour les .dex: Les fichiers java obtenus à partir des .dex ne sont généralement pas recompilables. Ce n'est donc pas une bonne piste pour modifier des applications.

La bonne manière de procéder est donc d'aller modifier directement le code Dalvik.

Nous n'allons pas ici faire des cours de Java ou d'assembleur, mais la connaissances de ces langages est un plus pour comprendre ce qui suit.

PS: J'ai effectué ce hack sans aucune connaissance préalable du langage machine Dalvik.

Outils

Voici les outils que nous allons utiliser:

Pourquoi:

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.

Cas pratique

Récupérez le fichier APK de l'application à modifier, soit en copiant-collant l'URL GooglePlay de l'application dans cette page, soit en utilisant cette application de backup. Transférez l'APK sur votre ordinateur.

A titre d'exemple, nous allons supprimer la géolocalisation systématique de l'application Crédit Agricole Alsace Vosges (com.cavo.MonCAAlsace.apk). Chaque fois que vous voulez consulter vos comptes, l'application essaie de vous géolocaliser. Il n'existe aucune option pour le désactiver. Ce comportement ne me semble pas acceptable.

Étape 1 : Convertir l'APK en Jar

Faites:

./d2j-dex2jar.sh com.cavo.MonCAAlsace.apk

ou

d2j-dex2jar.bat com.cavo.MonCAAlsace.apk

Cela va créer le fichier com.cavo.MonCAAlsace-dex2jar.jar.

Étape 2 : Extraire les sources Java décompilées

Lancez JD-GUI et ouvrez le fichier .jar précédemment créé, puis allez dans le menu "Fichiers" > "Save all sources…".

Cela va créer le fichier com.cavo.MonCAAlsace-dex2jar.src.zip qui contient les sources Java décompilées de l'application.

Notes:

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 pas 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à:

Prenons en exemple la première, accueil.java:

On trouve l'appel au LocationManager dans l'initialisation:

      ...
      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);
      ...

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:

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:

.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;

...

Il s'agit de la classe Accueil.java que nous voulons modifier.

Que fait La ligne qui nous intéresse ?

((LocationManager)getSystemService("location")).requestLocationUpdates("network", 10000L, 0.0F, this);

Voyons si vous vous y retrouvez dans le code Dalvik correspondant:

    .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

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.

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:

    .line 146
    nop

    .line 147
    nop

(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:

    .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
    .line 50
    nop
    .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
    .line 101
    nop
    .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
    .line 195
    nop

    .line 196
    .local v0, "locMan":Landroid/location/LocationManager;
    nop
    .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
    .line 161
    nop

    .line 162
    nop

É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:

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

Liens divers

Je conserve ici des liens divers en rapport avec le bidouillage d'APK: