Rétro-ingénierie d’apps mobiles et de leur protocole

Une démarche d’analyse d’applications Android pour comprendre leurs protections : désassemblage, instrumentation dynamique et interception de trafic.

Année
2025–2026
Type
Projet personnel
Domaine
Sécurité
Période
janvier 2025 – juin 2026
Stack
jadx, apktool, Ghidra, Frida, interception HTTPS

En bref

Problème
Une application mobile ne livre pas son code et chiffre son trafic, et ses API authentifient leurs clients et vérifient l’intégrité des requêtes ; comprendre ces protections demande de savoir les observer de l’extérieur.
Ce que j’ai réalisé
Une démarche d’analyse en trois temps, appliquée à des applications Android : désassemblage statique, instrumentation dynamique au runtime et cartographie du trafic HTTPS.
Résultat
Je sais lire une application obfusquée, observer son comportement en mémoire et cartographier ses échanges réseau, et j’en tire une lecture critique des protections mobiles.
Rôle
Recherche et analyse personnelles.
Équipe
Projet individuel
Statut
Terminé
Sommaire7 sections

Contexte

Travail de recherche personnel, hors cadre scolaire, mené pendant mon BUT. J’ai voulu comprendre comment des applications Android protègent leurs échanges avec leurs serveurs, et comment on analyse une application quand on n’a pas son code source. Je décris ici la démarche et les compétences : aucune application n’est nommée et aucun contournement n’est détaillé.

Le problème

Une application mobile n’expose jamais son code : il est compilé, souvent obfusqué, et son trafic est chiffré, parfois épinglé à un certificat. Ses API vérifient en plus les clients qui les appellent : protections côté client, signaux comportementaux, limites de débit. Pour comprendre ce qu’une protection arrête, je dois savoir l’observer de l’extérieur.

Démarche et méthode

J’ai travaillé en trois temps. En statique, je décompile l’APK avec jadx et apktool, je lis le smali et le Java reconstruit, et je remonte les points d’entrée et les références croisées malgré l’obfuscation. En dynamique, j’instrumente l’application au runtime avec Frida pour observer les valeurs calculées en mémoire et le comportement réel d’une fonction, là où la lecture statique s’arrête. En réseau, j’intercepte le trafic HTTPS pour cartographier la structure des requêtes : en-têtes, ordre, champs calculés. L’épinglage de certificat, quand l’application l’utilise, peut bloquer cette interception. Ghidra me sert quand une partie sensible passe par du code natif.

départ arrivée APKapplicationcompilée,sans source jadx · apktoolGhidra :code natif smali · Javalu et reconstruit points d’entréeréférencescroisées Fridainstrumentation s’attacherau runtime valeur calculéeen mémoire interceptionHTTPS structureen-têtes · ordre ·champs épinglagede certificatmur d’analyse Synthèserelierstatique,dynamiqueet réseau
1 / 5

  1. Le point de départ. Une application Android livrée compilée, sans code source, et dont le trafic est chiffré : tout s’observe de l’extérieur.
  2. En statique. Je décompile l’APK avec jadx et apktool (Ghidra pour le code natif), je lis le smali et le Java reconstruit, et je remonte les points d’entrée et les références croisées.
  3. En dynamique. J’attache Frida au runtime pour observer une valeur calculée en mémoire et le comportement réel d’une fonction, là où la lecture statique s’arrête.
  4. En réseau. J’intercepte le trafic HTTPS pour cartographier la structure des requêtes : en-têtes, ordre, champs calculés. L’épinglage de certificat peut bloquer cette interception.
  5. La synthèse. Je relie ce que chaque voie révèle (le code possible, le comportement réel, les échanges envoyés) pour comprendre le fonctionnement de l’application.
Fig. 1 — La démarche en trois temps. Depuis une application sans code source, le statique (jadx, apktool, Ghidra) remonte au code, le dynamique (Frida) observe le runtime, le réseau cartographie les requêtes et bute sur l’épinglage de certificat ; la synthèse relie les trois. Parcours pas à pas au clavier (← →).

Résultat

J’ai vérifié mes observations en les recoupant d’une couche à l’autre : ce que le code décompilé laissait prévoir, je l’ai confronté à ce que Frida montrait en mémoire, puis au trafic intercepté. La Fig. 2 montre ce recoupement sur une requête fictive.

Couches d’analyse

Requête HTTPS fictive et générique

{ }
  • lu à cette couche
  • en partie : un nom, une origine ou une valeur seule
  • invisible

Couche 1 : APK sans source

Je vois le paquet et ses chaînes figées : le domaine de l’API, le chemin, les noms d’en-têtes et de champs, le gabarit du User-Agent.

Je ne vois pas une seule valeur, ni l’ordre d’envoi : rien ne relie encore une chaîne au moment où elle part.

Couche 2 : Code décompilé

Je vois qui construit quoi : la fonction qui calcule la signature et ses entrées, l’assemblage de l’URL et du corps, l’appel aux protections côté client.

Je ne vois pas les valeurs : le jeton et la clé qui signe ne sont lus qu’à l’exécution. Le cookie m’échappe aussi : la bibliothèque HTTP le gère sans que ce code le nomme.

Couche 3 : Runtime instrumenté

Je vois les valeurs au moment où elles naissent : le jeton lu depuis le stockage, le nonce tiré, la signature calculée avec ses entrées, le corps en clair avant chiffrement.

Je ne vois pas la requête telle qu’elle part, avec l’ordre de ses en-têtes. L’intérieur du jeton de protection m’échappe aussi : il est produit hors de l’application.

Couche 4 : Trafic HTTPS

Je vois la requête exactement comme elle part : ordre et casse des en-têtes, cookie posé par le serveur.

Je ne vois pas d’où viennent les valeurs : la signature n’est plus qu’un nombre sans origine. L’épinglage de certificat peut aussi fermer cette fenêtre.

1 / 4

Les boutons ← → changent de couche ; dans la requête, les flèches haut et bas parcourent les lignes et Entrée ouvre la couche qui explique la ligne.

  1. Ligne de requête. La route : une chaîne du binaire, assemblée par le code ; le runtime et le fil la confirment.
  2. Host. Le domaine de l’API : lisible dès les chaînes du paquet, avant toute exécution.
  3. Authorization. Le jeton de session : le code montre d’où il est lu, seul le runtime en donne la valeur, le fil l’emporte tel quel.
  4. X-Signature. La signature : le code dit comment elle se calcule, le runtime donne sa valeur et ses entrées, le fil ne montre qu’un nombre.
  5. X-Client-Check. Un jeton de protection côté client, produit hors de l’application : aucune couche n’en lit le contenu.
  6. User-Agent. L’identité déclarée du client : un gabarit du binaire rempli par le code ; les protections côté client vérifient si elle est crédible.
  7. Cookie. Posé par le serveur et géré par la bibliothèque HTTP : absent du code de l’application, visible en mémoire et sur le fil.
  8. Champ action. Le champ fixe du corps : un nom dans les chaînes du paquet, une valeur assignée dans le code.
  9. Champ nonce. Tiré au hasard à chaque requête ; il n’existe qu’au runtime et sur le fil.
  10. Champ ts. L’horodatage, lu sur l’horloge à l’envoi et entrée de la signature : une valeur, donc une affaire de runtime.
Fig. 2 — Inspecteur de requête par couches. Une requête fictive et générique, relue depuis les quatre couches de la démarche : le paquet sans source, le code décompilé, le runtime instrumenté, le trafic intercepté. À chaque couche, les lignes lues s’allument et les autres restent dans l’ombre ; une note dit ce que je vois et ce que je ne vois pas. Une ligne survolée ou activée encadre la couche qui l’explique.

Ce que les protections m’ont appris

Le versant défense m’a le plus appris. J’ai vu pourquoi une API signe ses requêtes, et comment elle authentifie ses clients. Les regarder de près m’apprend surtout à les concevoir.

Chaque couche pose une question, du point de vue du défenseur. protections côté client Ce client est-il bien ce qu’il prétend être ? signaux d’appareil et de comportement Un humain sur un vrai appareil, ou un script ? limite de débit Ce volume de requêtes est-il plausible ?
Fig. 3 — Trois couches de défense d’une API et la question que chacune pose au client.

Ce que j’ai appris, ce que je referais

J’ai appris une démarche d’analyse reproductible, et à documenter ce que j’observe avant de conclure. Ce travail est un projet personnel, mené sans mandat d’un éditeur : un exercice d’apprentissage. Il s’arrête à la compréhension des mécanismes. Je voudrais refaire ce type d’analyse dans le cadre d’un mandat ou d’un programme de bug bounty.

Compétences BUT mobilisées

Compétences du référentiel BUT Informatique démontrées dans ce projet : niveau, ce que le projet montre et preuve.
CompétenceNiveauCe que le projet montre, et preuve
RéaliserRéaliser un développement d’applicationNiveau 2Mettre en œuvre une démarche de rétro-ingénierie logicielle.Preuve : Désassemblage statique (jadx, apktool, Ghidra) et instrumentation dynamique (Frida) d’applications Android.
AdministrerFaire évoluer et maintenir un système informatique communicant en conditions opérationnellesNiveau 2Analyser les échanges réseau d’une application.Preuve : Interception et cartographie du trafic HTTPS, lecture de l’épinglage de certificat, de l’authentification des clients et de la signature des requêtes.