La capture de trafic HTTPS sur Android est devenue un véritable défi pour les ingénieurs en sécurité. De nombreuses applications intègrent désormais des mécanismes d'ancrage de certificats (Certificate Pinning) robustes, invalidant les approches traditionnelles comme l'installation d'un certificat racine personnalisé via un proxy tel que Fiddler ou Charles. R0capture se distingue en agissant au cœur des bibliothèques cryptographiques natives, sans modifier l'application, sans nécessiter Xposed ou Magisk, et parfois même sans accès root complet.
Fonctionnement de r0capture via ptrace
Contrairement aux outils d'injection comme Frida, r0capture s'appuie sur l'appel système ptrace du noyau Linux. Ce mécanisme permet à un processus de surveiller et de contrôler l'exécution d'un autre. R0capture s'attache au processus cible et intercepte les appels aux fonctions critiques de la pile SSL/TLS, tellles que SSL_read ou SSL_write, au moment précis de leur exécution dans la couche native.
L'interception se fait en lisant les registres du processeur conformément à l'ABI (Application Binary Interface). Sur une architecture ARM64, les paramètres d'une fonction comme SSL_read se trouvent dans les registres x0, x1 et x2. En capturant ces valeurs et la valeur de retour, r0capture reconstitue le contexte de l'appel sans altérer la mémoire du processus cible.
Contournement de l'ancrage des certificats
La validation des certificats peut intervenir à différents niveaux : dans la couche Java (via OkHttpClient ou une implémentation personnalisée de TrustManager), ou directmeent dans une bibliothèque native (.so) qui appelle les fonctions OpenSSL. R0capture ne perturbe pas cette logique de validation. Sa stratégie est de capturer les données en clair après que la poignée de main TLS a réussi, c'est-à-dire une fois la connexion établie. Il intercepte donc le flux de données décrypté circulant dans les tampons d'E/S (BIO) de la structure SSL.
L'identification de ces tampons requiert une connaissance précise de la structure mémoire interne de la bibliothèque SSL utilisée. R0capture contient des profils pré-définis pour les versions courantes d'OpenSSL et de BoringSSL, lui permettant de localiser les pointeurs rbio (lecture) et wbio (écriture) au sein de l'objet SSL.
Déploiement et capture effective
Le déploiement nécessite une préparation minutieuse de l'environnement. L'accès au processus cible via ptrace est soumis à des restrictions de sécurité Android. Sur les appareils non-rootés, cela est généralement possible jusqu'à Android 7.1. Au-delà, des permissions spécifiques (comme CAP_SYS_PTRACE) sont requises, souvent obtenues sur un appareil rooté.
La première étape consiste à identifier l'architecture (32 bits ou 64 bits) du processus cible, afin d'utiliser le binaire r0capture correspondant. La capture se lance ensuite avec un filtrage précis des fonctions à surveiller.
# Lancer la capture pour une application cible
adb shell "/data/local/tmp/r0capture-arm64 -p $(pidof com.exemple.app) -f SSL_read,SSL_write -o /sdcard/capture.log"
Le fichier journal généré contient des entrées pour chaque appel intercepté, avec des adresses mémoire et des tailles. L'extraction du contenu en clair nécessite alors de lire la mémoire du processus à l'adresse indiquée. La méthode standard consiste à utiliser l'interface /proc/<pid>/mem.
import re, subprocess
def extraire_memoire(pid, adresse, taille):
commande = f"adb shell 'dd if=/proc/{pid}/mem bs=1 skip={adresse} count={taille} 2>/dev/null'"
return subprocess.check_output(commande, shell=True)
# Analyse du journal de capture
with open("capture.log") as f:
for ligne in f:
correspondance = re.search(r'buf=0x([0-9a-f]+) ret=(\d+)', ligne)
if correspondance and "SSL_read" in ligne:
adr = int(correspondance.group(1), 16)
nb_octets = int(correspondance.group(2))
donnees_brutes = extraire_memoire(PID, adr, nb_octets)
# Tentative de décodage et détection de contenu HTTP
Les versions récentes d'Android restreignent l'accès à /proc/pid/mem pour les utilisateurs non-root. Une alternative est d'utiliser le paramètre --dump de r0capture (dans ses versions récentes) pour qu'il sauvegarde automatiquement le contenu des tampons dans des fichiers.
Adaptation aux variantes de SSL
Pour les applications utilisant BoringSSL (présent dans Chrome et de nombreuses applications Google) ou Conscrypt (fournisseur TLS par défaut sur Android), les noms de fonctoins et la structure interne diffèrent. R0capture propose des options pour cibler ces bibliothèques spécifiques.
# Ciblage d'une application utilisant BoringSSL
adb shell "/data/local/tmp/r0capture-arm64 -p $(pidof com.google.android.apps.photos) --boringssl -f SSL_read"
Lorsque l'application emploie des variantes non standard ou des symboles obscurcis, il peut être nécessaire d'identifier manuellement l'adresse de la fonction dans la table des symboles de la bibliothèque native à l'aide d'outils comme readelf.
Problèmes courants et solutions
**Problème : Erreur "Operation not permitted".**Ceci est souvent lié aux politiques SELinux qui empêchent l'attachement ptrace. La solution temporaire consiste à basculer SELinux en mode permissif (setenforce 0) avec les droits root. Sur certains systèmes, il peut être nécessaire de modifier les règles SELinux via un module Magisk.
**Problème : Données capturées corrompues ou vides.**L'adresse mémoire lue peut devenir invalide si le tampon est libéré immédiatement après l'appel. Utiliser le paramètre --wait pour introduire un court délai peut aider. Pour les applications utilisant HTTP/2, le contenu doit être réassemblé à partir des différentes trames, ce qui requiert souvent un traitement post-capture.
**Problème : Fonction non trouvée sur une version récente d'Android.**Les systèmes d'exploitation modernes renforcent les contrôles sur les capabilities des processus. S'assurer que le processus adbd ou le shell possède la capability CAP_SYS_PTRACE peut résoudre le problème. Cela peut être vérifié via cat /proc/self/status | grep Cap.