Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Reverse engineering de Revolut Android 10.145 - synthèse consolidée
- > Application étudiée : `com.revolut.revolut` - version `10.145` - `versionCode=1030145101`.
- >
- > Les observations portent principalement sur un POCO/Xiaomi `22101320G` (`redwood`) sous Android 15 / SDK 35, dans un environnement système modifié (rom Matrixx + KernelSu Next) accompagné d'un fork privé de l'agent android "Reins" embarquant un support llama.cpp avec endpoint openai, intégrant en son sein tout un environnement Termux dédié en capacité d'accéder aux droit superutilisateurs et sortir de sa sandbox à des fins d'étude. Ce dernier utilise le modèle de langage "Qwen 3.8-27B-abliterated.i1-Q4_K_S" fourni par un serveur local.
- >
- > Le document distingue systématiquement capacité statique, chemin de code réellement établi, observation runtime, donnée effectivement obtenue et éventuelle transmission réseau.
- ---
- ## Table des matières
- 1. [Confidentialité et conséquences pour l'utilisateur final](#1-confidentialité-et-conséquences-pour-lutilisateur-final)
- 2. [Périmètre, méthode et hiérarchie des preuves](#2-périmètre-méthode-et-hiérarchie-des-preuves)
- 3. [Environnement matériel et système étudié](#3-environnement-matériel-et-système-étudié)
- 4. [État installé de Revolut 10.145](#4-état-installé-de-revolut-10145)
- 5. [Reproduction du crash et chronologie du démarrage](#5-reproduction-du-crash-et-chronologie-du-démarrage)
- 6. [Activité protégée, écran d'erreur et code 4674 / 0x1242](#6-activité-protégée-écran-derreur-et-code-4674--0x1242)
- 7. [Architecture de protection observée](#7-architecture-de-protection-observée)
- 8. [DexProtector : structure ELF, reconstruction et image native protégée](#8-dexprotector--structure-elf-reconstruction-et-image-native-protégée)
- 9. [Bitfield d'environnement DexProtector](#9-bitfield-denvironnement-dexprotector)
- 10. [Détection ADB - bit 0x200](#10-détection-adb---bit-0x200)
- 11. [Verified Boot, propriétés système et bit 0x40](#11-verified-boot-propriétés-système-et-bit-0x40)
- 12. [AndroidKeyStore, attestation, RootOfTrust et bit 0x40](#12-androidkeystore-attestation-rootoftrust-et-bit-0x40)
- 13. [Fourthline : contrôles root, hook, instrumentation et environnement](#13-fourthline--contrôles-root-hook-instrumentation-et-environnement)
- 14. [Credolab / Incognia : collecte et détection root réellement câblées](#14-credolab--incognia--collecte-et-détection-root-réellement-câblées)
- 15. [Second détecteur root : DeviceInfo.getIsRooted](#15-second-détecteur-root--deviceinfogetisrooted)
- 16. [Inventaire de paquets, QUERY_ALL_PACKAGES et applications ciblées](#16-inventaire-de-paquets-query_all_packages-et-applications-ciblées)
- 17. [Play Integrity, SafetyNet, Keystore et décision serveur](#17-play-integrity-safetynet-keystore-et-décision-serveur)
- 18. [Cartographie statique des SDK, DEX, permissions et API sensibles](#18-cartographie-statique-des-sdk-dex-permissions-et-api-sensibles)
- 19. [Bibliothèques natives et capacités observées](#19-bibliothèques-natives-et-capacités-observées)
- 20. [Assets, DEX embarqués et MessageGuardException](#20-assets-dex-embarqués-et-messageguardexception)
- 21. [Snapshots du processus Revolut et visibilité réelle des traces root](#21-snapshots-du-processus-revolut-et-visibilité-réelle-des-traces-root)
- 22. [Profils Android et espaces utilisateurs](#22-profils-android-et-espaces-utilisateurs)
- 23. [Matrice de causalité et conclusions de confiance](#23-matrice-de-causalité-et-conclusions-de-confiance)
- 24. [Critères de compatibilité à vérifier sur un autre appareil](#24-critères-de-compatibilité-à-vérifier-sur-un-autre-appareil)
- 25. [Artefacts et scripts d'analyse](#25-artefacts-et-scripts-danalyse)
- 26. [Limites méthodologiques et périmètre exclu](#26-limites-méthodologiques-et-périmètre-exclu)
- 27. [Résumé final](#27-résumé-final)
- ---
- # 1. Confidentialité et conséquences pour l'utilisateur final
- ## 1.1. Constat général
- Le reverse engineering de Revolut Android 10.145 met en évidence une surface d'observation de l'appareil particulièrement large. L'application ne se limite pas aux données strictement nécessaires à l'affichage d'un compte bancaire ou à l'exécution d'un paiement : elle embarque des mécanismes capables d'examiner de nombreux aspects de l'appareil, de son système, de ses applications, de ses identifiants, de ses interfaces matérielles et de son environnement d'exécution.
- Pour l'utilisateur final, le problème de confidentialité principal est l'ampleur potentielle de cette collecte et de ce profilage technique. Les éléments présents dans le paquet permettent notamment d'observer ou d'inférer :
- - l'identité logicielle détaillée de l'appareil ;
- - le modèle, la marque, le fabricant, le bootloader et le fingerprint Android ;
- - la version Android, le niveau de patch et diverses propriétés système ;
- - l'état de verrouillage et d'intégrité du démarrage ;
- - la présence de root, de frameworks d'injection ou d'outils de modification ;
- - la présence de certaines applications installées ;
- - les identifiants publicitaires et différents identifiants d'instance ;
- - des informations de téléphonie et de réseau ;
- - la localisation ;
- - les capteurs ;
- - la caméra et le microphone ;
- - la biométrie ;
- - les contacts ;
- - le presse-papiers et l'accessibilité dans certains chemins référencés ;
- - le NFC ;
- - l'état de capture ou d'enregistrement de l'écran ;
- - les caractéristiques du Keystore matériel et de l'attestation cryptographique de l'appareil.
- Cette surface permet potentiellement de construire un profil technique très détaillé du terminal et de son environnement. Elle permet aussi de conditionner l'accès au service à des éléments qui dépassent la seule authentification bancaire : ROM, bootloader, ADB, root, applications installées, capacité d'attestation matérielle et autres propriétés de l'appareil.
- ## 1.2. Permissions demandées
- Le paquet installé demande 44 permissions. Parmi les plus significatives pour la vie privée :
- - `android.permission.ACCESS_ADSERVICES_AD_ID` ;
- - `android.permission.ACCESS_ADSERVICES_ATTRIBUTION` ;
- - `android.permission.ACCESS_COARSE_LOCATION` ;
- - `android.permission.ACCESS_FINE_LOCATION` ;
- - `android.permission.ACCESS_WIFI_STATE` ;
- - `android.permission.BLUETOOTH_CONNECT` ;
- - `android.permission.BLUETOOTH_SCAN` ;
- - `android.permission.CAMERA` ;
- - `android.permission.DETECT_SCREEN_CAPTURE` ;
- - `android.permission.DETECT_SCREEN_RECORDING` ;
- - `android.permission.GET_ACCOUNTS` ;
- - `android.permission.HIGH_SAMPLING_RATE_SENSORS` ;
- - `android.permission.MANAGE_OWN_CALLS` ;
- - `android.permission.NFC` ;
- - `android.permission.QUERY_ALL_PACKAGES` ;
- - `android.permission.READ_CONTACTS` ;
- - `android.permission.WRITE_CONTACTS` ;
- - `android.permission.RECORD_AUDIO` ;
- - `android.permission.USE_BIOMETRIC` ;
- - `android.permission.USE_FINGERPRINT` ;
- - `android.permission.READ_EXTERNAL_STORAGE` ;
- - `android.permission.WRITE_EXTERNAL_STORAGE` ;
- - `com.google.android.gms.permission.AD_ID`.
- Le relevé runtime ne montre pas toutes ces permissions comme accordées. Cinq permissions install/grant non-runtime ressortaient comme accordées, et les app-ops sensibles observées étaient majoritairement en `ignore` ou `default`, avec notamment `WAKE_LOCK` et `USE_BIOMETRIC` en `allow`. Cette distinction ne réduit pas la surface déclarée : elle signifie seulement qu'une permission demandée n'est pas forcément active dans le relevé considéré.
- ## 1.3. Identifiants, attribution et télémétrie
- Le code embarque plusieurs briques de mesure, d'attribution et de télémétrie, parmi lesquelles AppsFlyer, Firebase, Google Play Services, Sentry, Credolab, Incognia, Onfido, Incode et Twilio.
- Des chaînes et chemins de code référencent notamment :
- - `advertisingIdClientWrapper` ;
- - `appInstanceId` ;
- - `FirebaseAnalytics.appInstanceId` ;
- - `android_id` ;
- - `sha1_android_id` ;
- - `collectIMEI` ;
- - `collectIMEIForceByUser`.
- La présence de ces références démontre une capacité de collecte ou de traitement d'identifiants dans les SDK embarqués. Elle ne prouve pas que chaque identifiant est obtenu ou envoyé pendant le lancement pré-crash analysé.
- ## 1.4. Inventaire des applications installées
- Revolut déclare `android.permission.QUERY_ALL_PACKAGES`. Le manifeste contient une liste explicite de familles d'applications liées au root, au hooking, au clonage, à l'émulation ou au contrôle distant : Magisk, KernelSU, SukiSU, APatch, Xposed/EdXposed, Substrate, SuperSU/Superuser, Lucky Patcher, App Cloner et d'autres outils.
- Cette capacité d'inventaire est importante pour la confidentialité : la liste des logiciels présents sur un appareil révèle des usages et des choix techniques qui dépassent le strict fonctionnement d'une application bancaire.
- ## 1.5. Profilage technique de l'appareil
- Le split `feature_credit_data_monitoring_sdk` contient des collecteurs Credolab/Incognia pour :
- `FINGERPRINT`, `TAGS`, `SDK_INT`, `RELEASE`, `SECURITY_PATCH`, `BOARD`, `BOOTLOADER`, `BRAND`, `DEVICE`, `MODEL`, `MANUFACTURER`, `PRODUCT`, `HARDWARE`.
- Le PID Revolut a lui-même journalisé avant la terminaison protégée :
- ```text
- Fingerprint: [20260614-202608251249 aarch64 35 POCO/redwood_global/redwood:14/UKQ1.240624.001/OS2.0.7.0.UMSMIXM:user/release-keys 5.4.302-Scarlet-v6.0]
- ```
- Le fingerprint système et le noyau personnalisé font donc partie de l'état effectivement manipulé ou journalisé pendant le lancement.
- ## 1.6. Root, intégrité et environnement
- Plusieurs mécanismes distincts inspectent le système : DexProtector, Fourthline, Credolab, `DeviceInfo.getIsRooted()`, Play Integrity/SafetyNet et AndroidKeyStore/attestation.
- Les indicateurs recherchés couvrent `su`, Magisk, KernelSU, APatch, Zygisk, Xposed, LSPosed, Riru, Frida, BusyBox, `test-keys`, `dev-keys`, SELinux, montages, `/proc/self/maps`, `/proc/mounts`, propriétés Android, état ADB, Verified Boot, bootloader et attestation TEE/KeyMint.
- Du point de vue de l'utilisateur, cette inspection permet à Revolut de caractériser la manière dont il administre son propre terminal, et pas seulement de vérifier un identifiant de compte.
- ## 1.7. Localisation, téléphonie, capteurs et interfaces sensibles
- La cartographie DEX compte de nombreuses références à `FusedLocationProviderClient`, `LocationManager`, `ConnectivityManager`, `TelephonyManager`, `SensorManager`, caméra, microphone, NFC, Bluetooth et biométrie.
- | Catégorie | Références d'API observées |
- | ------------------------------ | -------------------------: |
- | Localisation | 628 |
- | Biométrie | 384 |
- | Caméra / microphone / capteurs | 183 |
- | Keystore / attestation | 167 |
- | État réseau | 84 |
- | Téléphonie | 65 |
- | Accessibilité / presse-papiers | 60 |
- | Inventaire packages | 46 |
- | NFC | 29 |
- | Identifiants / Settings | 9 |
- Ces nombres mesurent des références statiques et non des événements de collecte réels.
- Le code référence aussi `AccessibilityManager.isEnabled()`, `getEnabledAccessibilityServiceList()`, `getInstalledAccessibilityServiceList()`, `ClipboardManager.getPrimaryClip()` et `getPrimaryClipDescription()`.
- ## 1.8. Attestation matérielle et liaison à l'application
- DexProtector utilise AndroidKeyStore et l'attestation X.509 Android. Le chemin reconstruit crée ou retrouve une clé EC P-256, utilise un challenge de 8 octets, parse l'OID Android Attestation `1.3.6.1.4.1.11129.2.1.17`, examine `RootOfTrust`, `deviceLocked`, `verifiedBootState`, classe la racine SPKI et vérifie une Application ID associée au package et au signataire APK.
- Une clé persistante du namespace Revolut contient bien `com.revolut.revolut` dans son Application ID d'attestation et un digest de signature concordant avec les APK installés. Cette voie donne à l'application une vue matériellement attestée distincte des simples propriétés Android publiques.
- ## 1.9. Ce qui est prouvé et ce qui ne l'est pas en matière de transmission
- L'analyse sépare quatre niveaux :
- 1. capacité statique présente ;
- 2. code effectivement appelé ;
- 3. donnée réellement obtenue ou stockée ;
- 4. transmission réseau établie.
- | Information | Obtention locale | Usage local | Transmission réseau pré-crash établie |
- | ------------------------- | -------------------------- | ------------------------------ | ------------------------------------- |
- | État ADB | oui | bitfield / refus | non |
- | Verified Boot public | chemin établi | contrôle | non |
- | RootOfTrust matériel | oui sur certificat Revolut | contribue à `0x40` | non |
- | Build tags | chemin établi | bit `0x100` si condition vraie | non |
- | Lineage / GrapheneOS | chemin établi | bit `0x80` si condition vraie | non |
- | Statut DexProtector | oui | écran / QR | non |
- | Chaînes diagnostic Intent | oui dans l'UI locale | QR | non établi par `reGj()` |
- La présence d'OkHttp, Retrofit, gRPC, Firebase ou Sentry ne suffit pas à prouver qu'une donnée précise a été transmise. L'absence de preuve de transmission avant le crash ne signifie pas non plus que les SDK n'envoient jamais ces données dans d'autres parcours.
- ## 1.10. Conséquence pratique pour l'utilisateur
- Revolut 10.145 peut faire dépendre l'accès à son application d'une analyse approfondie de l'appareil : configuration système, état matériel de démarrage, ADB, root, ROM, applications et attestation cryptographique. Le reverse engineering démontre aussi qu'un affichage superficiel `green`, `locked` et `release-keys` ne suffit pas lorsque l'attestation TEE/KeyMint révèle un état différent.
- ---
- # 2. Périmètre, méthode et hiérarchie des preuves
- Les analyses consolidées datent principalement des 4 et 5 septembre 2026. Elles reposent sur ADB, logcat, dumpsys, Package Manager, inspection des APK/splits, baksmali, radare2/rabin2, Ghidra, scripts Python hors ligne, Termux intégré à Reins, observations root, parsing de certificats publics/Keystore et émulation locale bornée de fonctions natives avec Unicorn.
- Les constats historiques fondamentaux ont été établis sans patcher l'APK Revolut, sans injecter du code dans son processus, sans MITM réseau et sans modifier ses certificats.
- ### Niveau A - observé au runtime
- - chargement de `libalice.so` puis `libdexprotector.so` ;
- - accès à `ro.debuggable` et `ro.lineage.build.version` ;
- - lancement de `ProtectedRevolutApplication$I` ;
- - écran « environnement non sécurisé » ;
- - code historique `4674 = 0x1242` ;
- - `TerminateException` et `APP CRASH(EXCEPTION)`.
- ### Niveau B - mécanismes réellement implémentés et câblés
- - détecteur root Credolab ;
- - `DeviceInfo.getIsRooted()` ;
- - Fourthline ;
- - inventaire de packages ;
- - Play Integrity/SafetyNet ;
- - AndroidKeyStore/attestation.
- ### Niveau C - capacités statiques sans exécution pré-crash démontrée
- - nombreux flux Onfido/Incode/Twilio ;
- - TensorFlow Lite ;
- - plusieurs chemins localisation/caméra/NFC ;
- - certaines télémétries et transmissions réseau.
- # 3. Environnement matériel et système étudié
- ## 3.1. Appareil
- | Champ | Valeur |
- | -------------------------- | --------------------------------- |
- | Constructeur | Xiaomi |
- | Marque | POCO |
- | Modèle | `22101320G` |
- | Device | `redwood` |
- | SoC | QTI `SM7325` |
- | Android déclaré | 15 |
- | SDK | 35 |
- | Security patch système | `2025-09-01` |
- | Vendor security patch | `2025-06-01` |
- | ABI | `arm64-v8a, armeabi-v7a, armeabi` |
- | Premier niveau API produit | 31 |
- | SELinux | Enforcing |
- | Build public | `user` |
- | Tags publics | `release-keys` |
- Propriétés publiques relevées :
- ```text
- ro.secure=1
- ro.debuggable=0
- ro.adb.secure=1
- ro.boot.verifiedbootstate=green
- ro.boot.flash.locked=1
- ro.boot.vbmeta.device_state=locked
- ro.boot.veritymode=enforcing
- ro.boot.avb_version=1.2
- ```
- ## 3.2. Noyau et root
- Le noyau visible depuis une application non-root est :
- ```text
- Linux localhost 5.4.302-Scarlet-v6.0 ... aarch64 Android
- ```
- Le contexte root observé via Reins/Termux :
- ```text
- uid=0(root)
- context=u:r:ksu:s0
- KernelSU 3.2.5-54-gcfac3be3:KernelSU
- ```
- Éléments observés côté root :
- - `/system/bin/su` présent et fonctionnel ;
- - `/data/adb/ksu` présent ;
- - `/data/adb/modules` présent ;
- - `/data/adb/apatch` absent ;
- - `/data/adb/magisk` absent ;
- - `/sbin/.magisk` absent ;
- - `/su/bin/su` absent ;
- - `/dev/kernelsu` absent au moment du relevé.
- Un véritable processus Android Reins en contexte `untrusted_app` a vu :
- ```text
- VISIBLE /system/bin/su
- NOT_VISIBLE /system/xbin/su
- NOT_VISIBLE /sbin/su
- NOT_VISIBLE /su/bin/su
- NOT_VISIBLE /sbin/.magisk
- NOT_VISIBLE /data/adb/magisk
- NOT_VISIBLE /data/adb/modules
- NOT_VISIBLE /data/adb/ksu
- NOT_VISIBLE /dev/kernelsu
- NOT_VISIBLE /data/adb/apatch
- uname -r 5.4.302-Scarlet-v6.0
- ```
- La visibilité dépend donc du namespace et du contexte du processus. La présence root au niveau système ne se traduit pas nécessairement par un `File.exists()` positif depuis Revolut.
- ## 3.3. Divergence Verified Boot
- Les propriétés Android publiques indiquent `green/locked`, mais `/proc/cmdline` et `/proc/device-tree/chosen/bootargs` contiennent :
- ```text
- androidboot.verifiedbootstate=orange
- ```
- La machine expose donc deux vues différentes :
- - état boot brut : `orange` ;
- - propriétés Android exposées : `green`, `locked`, `enforcing`.
- Des couches de modification système présentes sur l'appareil réécrivent certaines propriétés avec `resetprop`. Cette divergence rend `getprop` insuffisant pour qualifier l'intégrité réelle du terminal.
- Une trace noyau conservée par KernelSU montre :
- ```text
- Init cannot set 'ro.boot.verifiedbootstate' to 'orange': Read-only property was already set
- ```
- Cette ligne prouve une incohérence précoce, mais pas la valeur exacte qui était déjà positionnée.
- ## 3.4. Divergence Android 15 / fingerprint Android 14
- Le système expose :
- ```text
- ro.build.version.release=15
- ro.build.version.sdk=35
- ro.build.id=BP1A.250505.005
- ```
- Mais les fingerprints `build`, `system`, `vendor`, `product` et `system_ext` donnent :
- ```text
- POCO/redwood_global/redwood:14/UKQ1.240624.001/OS2.0.7.0.UMSMIXM:user/release-keys
- ```
- et :
- ```text
- ro.build.description=redwood_global-user 14 UKQ1.240624.001 OS2.0.7.0.UMSMIXM release-keys
- ```
- Les fichiers de propriétés réels révèlent en outre une base `userdebug` Lineage/MatrixX :
- ```text
- ro.system.build.type=userdebug
- ro.build.type=userdebug
- ro.build.display.id=lineage_redwood-userdebug 15 BP1A.250505.005 ... release-keys
- ro.build.flavor=lineage_redwood-userdebug
- ro.lineage.device=redwood
- ro.matrixx.build.version=Matrixx-v11.8.0-Official-redwood-Gapps-202510031305
- ro.matrixx.display.version=Matrixx-15.0-redwood-v11.8.0
- ```
- Cette coexistence de plusieurs identités système est pertinente puisque la protection cherche explicitement certaines propriétés de ROM et de build.
- ---
- # 4. État installé de Revolut 10.145
- ## 4.1. Métadonnées principales
- | Champ | Valeur |
- | ---------------------- | ----------------------------------------- |
- | Package | `com.revolut.revolut` |
- | `versionName` | `10.145` |
- | `versionCode` | `1030145101` |
- | `minSdk` | 28 |
- | `targetSdk` | 36 |
- | `compileSdkVersion` | 37 |
- | ABI principale | `arm64-v8a` |
- | Installateur | `com.android.vending` |
- | UID observé | `10701` |
- | Application | `com.revolut.ProtectedRevolutApplication` |
- | Activité login | `com.revolut.ui.login.pin.LoginActivity` |
- | `extractNativeLibs` | `false` |
- | `usesCleartextTraffic` | `false` |
- | `allowBackup` | `false` |
- OpenGL ES 3.0 est déclaré requis. Les fonctions caméra, NFC, microphone, Bluetooth et autres capacités matérielles observées ne sont pas toutes déclarées obligatoires.
- ## 4.2. APK et splits installés
- Douze APK/splits ont été inventoriés :
- - `base.apk` ;
- - `split_config.arm64_v8a.apk` ;
- - `split_config.fr.apk` ;
- - `split_config.xxhdpi.apk` ;
- - `split_feature_apm_multibanco_sdk_impl.apk` ;
- - `split_feature_apm_multibanco_sdk_impl.config.arm64_v8a.apk` ;
- - `split_feature_apm_multibanco_sdk_impl.config.xxhdpi.apk` ;
- - `split_feature_credit_data_monitoring_sdk.apk` ;
- - `split_feature_in_app_calls_twilio_retail.apk` ;
- - `split_feature_in_app_calls_twilio_retail.config.arm64_v8a.apk` ;
- - `split_feature_incode_sdk.apk` ;
- - `split_feature_incode_sdk.config.arm64_v8a.apk`.
- Le `base.apk` contient 22 DEX ; l'inventaire global des splits en a compté 27.
- ---
- # 5. Reproduction du crash et chronologie du démarrage
- ## 5.1. Lancement normal
- Le lancement de :
- ```text
- com.revolut.revolut/com.revolut.ui.login.pin.LoginActivity
- ```
- est accepté par Android. Plusieurs reproductions ont retourné :
- ```text
- Status: ok
- LaunchState: UNKNOWN (0)
- Activity: com.revolut.revolut/com.revolut.ui.login.pin.LoginActivity
- ```
- Le processus principal disparaît ensuite en quelques dizaines à quelques centaines de millisecondes.
- `ApplicationExitInfo` montre de nombreuses occurrences :
- ```text
- reason=4 (APP CRASH(EXCEPTION))
- ```
- Le crash est enregistré comme :
- ```text
- FATAL EXCEPTION: main
- Process: com.revolut.revolut
- android.app.TerminateException$...
- ```
- La classe `TerminateException` n'existe ni dans les `android.jar` SDK locaux ni dans le `/system/framework/framework.jar` réel du téléphone. Sa chaîne n'apparaît pas non plus en clair dans les DEX Revolut copiés. Elle appartient au comportement produit dynamiquement par la couche protégée.
- ## 5.2. Séquence prouvée
- 1. Android lance `LoginActivity`.
- 2. `ProtectedRevolutApplication.attachBaseContext()` s'exécute.
- 3. Une initialisation charge `libalice.so`.
- 4. `ProtectedRevolutApplication$I.bo()` vérifie si le processus se termine par `:p2235fa67286a712a679e1044`.
- 5. Dans le processus principal, `System.loadLibrary("dexprotector")` charge `libdexprotector.so`.
- 6. Des accès à `ro.debuggable` puis `ro.lineage.build.version` sont observés.
- 7. `ProtectedRevolutApplication.onCreate()` appelle une routine native `c()`.
- 8. Revolut tente d'ouvrir `ProtectedRevolutApplication$I`.
- 9. Android journalise un `Background activity launch blocked`.
- 10. Le thread principal se termine sur `TerminateException`.
- 11. ActivityManager enregistre `APP CRASH(EXCEPTION)`.
- `bo()` n'est donc pas un test d'intégrité : il sert à reconnaître le processus dédié de l'activité d'erreur et à éviter d'y relancer la protection.
- ## 5.3. Revalidation du 4 septembre 2026 à 19:49
- | Heure | Observation |
- | ------------------- | -------------------------------------------------------- |
- | `19:49:32.597` | PID `25140` lancé |
- | `19:49:32.743` | `libalice.so` chargée |
- | `19:49:32.764` | `libdexprotector.so` chargée |
- | `19:49:32.772` | accès refusé à `ro.debuggable` |
- | `19:49:32.777` | accès refusé à `ro.lineage.build.version` |
- | `19:49:32.808-.813` | demande `ProtectedRevolutApplication$I`, `BAL_BLOCK` |
- | `19:49:32.816` | `TerminateException` |
- | `19:49:32.838` | processus mort |
- | `19:49:43.299` | watchdog `keystore2` inactif, sans attribution à Revolut |
- Cette capture n'a pas relu le QR ni son entier. `0x1242` reste le code du lancement historique documenté, pas une nouvelle mesure à 19:49.
- Des reproductions analogues ont été conservées à 12:29, 16:44, 17:58, 21:14, 21:31, 21:48 et 22:25. Toutes confirment l'ordre général :
- ```text
- libalice.so
- -> libdexprotector.so
- -> sondes système
- -> ProtectedRevolutApplication$I
- -> TerminateException
- ```
- Aucun SIGSEGV natif n'est observé comme cause immédiate.
- ---
- # 6. Activité protégée, écran d'erreur et code 4674 / 0x1242
- ## 6.1. Écran réellement observé
- La capture historique affichait :
- > L'application ne peut pas s'exécuter, car l'environnement n'est pas sécurisé et vos données peuvent être en danger.
- Le QR a été décodé hors ligne en :
- ```text
- <identifiant-diagnostic> (anonymisé)
- 4674
- ```
- `4674 = 0x1242`.
- ## 6.2. Classification Java
- `ProtectedRevolutApplication$I.laF(int)` applique :
- ```text
- si code <= 0x1000 -> appareil/application incompatible
- sinon si code & 0x1 != 0 -> émulateur
- sinon si code & 0x10 != 0 -> installation non officielle
- sinon si code & 0x1ee != 0 -> environnement non sécurisé
- sinon -> appareil/application incompatible
- ```
- Pour `0x1242` :
- ```text
- 0x1242 & 0x1 = 0
- 0x1242 & 0x10 = 0
- 0x1242 & 0x1ee = 0x42
- ```
- Le lancement est donc explicitement classé **environnement non sécurisé**, et non émulateur ou installation non officielle.
- ## 6.3. Construction du QR et bridge natif
- La native transmet le statut à un notifier identifié vers `0x82560`, qui passe l'entier à Java/JNI. L'activité protégée le lit dans l'extra :
- ```text
- d6a6588daf2b0a92de41f122c557d510
- ```
- `reGj()` concatène cet entier avec deux extras texte :
- ```text
- 35bb9b08cb6e302c7338829816c2a2a5
- 35e3e802421d5280861b367f9d1e4a01
- ```
- puis encode le résultat en UTF-8 pour générer le QR. Le chemin démontré est local :
- ```text
- statut natif -> JNI/Intent -> activité d'erreur -> texte/QR
- ```
- Cette logique ne démontre pas de transmission réseau.
- ---
- # 7. Architecture de protection observée
- L'application combine plusieurs couches :
- 1. sandbox Android standard ;
- 2. `ProtectedRevolutApplication` ;
- 3. `libalice.so` ;
- 4. DexProtector / `libdexprotector.so` ;
- 5. contrôles natifs Fourthline ;
- 6. SDK anti-fraude Credolab / Incognia ;
- 7. second détecteur root dans le split Multibanco ;
- 8. Play Integrity / SafetyNet ;
- 9. AndroidKeyStore / attestation ;
- 10. décisions métier potentiellement prises côté serveur.
- Le crash immédiat intervient avant le chargement visible de `libfourthline-security.so`. Sa cause immédiate se situe donc dans la phase `ProtectedRevolutApplication` / `libalice.so` / DexProtector.
- ---
- # 8. DexProtector : structure ELF, reconstruction et image native protégée
- ## 8.1. Bibliothèque originale
- `libdexprotector.so` est un ELF64 AArch64, statique, stripped, PIC, NX, full RELRO, compilé avec LLD 17.0.2.
- ```text
- taille : 443222 octets
- SHA-256 : 81bbed87aaa3fb03285d37bd04952dd18b0ba5f33e958e3f866791fa8034aeee
- ```
- Le quatrième `PT_LOAD` protégé :
- ```text
- offset fichier : 0x3638
- vaddr : 0xf638
- filesz : 0x68d16 = 429334
- memsz : 0x68d16
- SHA-256 : c3c29b0d376662e0c15f6133f77d633f53b31b1fdba69a704411f69fe838ca17
- ```
- L'unique `.init_array` pointe vers `0x380`. Cette fonction exécute `prctl(PR_SET_DUMPABLE, 0)`, parcourt les program headers, sélectionne le quatrième `PT_LOAD` et le transmet à `0x243c`.
- ## 8.2. Reconstruction d'une seconde image ELF
- `0x243c` appelle `0x1298` pour reconstruire une image native, puis `0x1684` pour appliquer les relocations. Il traite les tags `DT_INIT_ARRAY`, `DT_FINI_ARRAY`, `DT_INIT_ARRAYSZ`, `DT_FINI_ARRAYSZ`, `DT_PLTRELSZ`, `DT_STRTAB`, `DT_SYMTAB`, `DT_RELA`, `DT_RELASZ`, `DT_STRSZ`, `DT_JMPREL`, `DT_RELRSZ`, `DT_RELR` et `DT_RELRENT`.
- `0x1298` décode un en-tête protégé, réserve la mémoire avec `mmap`, reconstruit jusqu'à quatre segments, utilise `mprotect`, vérifie des checksums 16 bits, peut nommer des VMA avec `prctl(PR_SET_VMA, ...)`, et libère avec `munmap` en cas d'échec. La décompression reproduite hors ligne correspond à un schéma de type LZ4.
- ## 8.3. Dérivation de clé liée au linker
- La fonction `0x920` utilise `r_debug` et `r_brk` du linker Android. Le linker local analysé a le SHA-256 :
- ```text
- a12e5824bbb6a2da45595b46396afce080e5a1c4f6dadccbe2790d513814da5f
- ```
- L'émulation bornée avec Unicorn a produit :
- ```text
- r_brk_bytes=c0035fd600000000
- final_pc=0x54000000
- derived_key=0f567a3629535da09e32c89fe26d159a851f97238b98893954ab9f48d377cf0c
- ```
- En-tête décodé :
- ```text
- 0x000ac000 0x00000000 0x00000040 0x00000008 0x0009d670
- 0x00098000 0x00008000 0x00004000 0x00000004
- ```
- Le flux décodé fait 429330 octets, SHA-256 :
- ```text
- c8491b253f378aca48d8248b6369f3df9fb5d3ffd198174a4b27c6669a40ea98
- ```
- ## 8.4. Segments reconstruits
- | Segment | Offset destination | Taille mémoire | Taille décompressée | Permissions | Checksum | Taille compressée |
- | ------- | -----------------: | -------------: | ------------------: | ----------: | -------: | ----------------: |
- | 0 | `0x0` | 611936 | 611936 | 5 | 381 | 418121 |
- | 1 | `0x99660` | 17224 | 17224 | 3 | 51960 | 5504 |
- | 2 | `0xa1980` | 24720 | 5200 | 3 | 40058 | 4996 |
- | 3 | `0xa8000` | 780 | 780 | 5 | 21269 | 577 |
- Image reconstruite :
- ```text
- taille : 704512 octets
- SHA-256 : ab936e6ccbd4c1ff76fe4fc8869a4d05118e97fb6bea1068743f39521cf245c0
- ```
- Dépendances déclarées : `liblog.so`, `libandroid.so`, `libc.so`.
- ## 8.5. Imports et inventaire profond
- 24 imports dynamiques : `malloc`, `free`, `calloc`, `time`, `AAssetManager_openDir`, `AAssetDir_getNextFileName`, `AAsset_close`, `AAssetManager_open`, `AAsset_getBuffer`, `AAsset_getLength`, `AAssetDir_close`, `realloc`, `pthread_create`, `pthread_detach`, `sigaction`, `pthread_atfork`, `AAssetManager_fromJava`, `__android_log_write`, `arc4random_buf`, `__android_log_print`, `gmtime_r`, `getauxval`, `funopen`, `setvbuf`.
- Inventaire :
- ```text
- 160177 instructions désassemblées
- 5898 appels directs
- 10052 branches directes
- 284 syscalls repérés
- ```
- Principaux syscalls : `close` 40, `exit_group` 9, `fchdir` 8, `fstat` 7, `getpid` 7, `getuid` 6, `ioctl` 18, `kill` 4, `mmap` 11, `mprotect` 11, `munmap` 12, `nanosleep` 11, `newfstatat` 28, `openat` 21, `prctl` 46, `read` 8, `readlinkat` 5, `write` 3.
- # 9. Bitfield d'environnement DexProtector
- L'analyse de l'image native reconstruite identifie une routine de synthèse qui assemble plusieurs indicateurs d'environnement dans un entier de statut. Les correspondances établies sont :
- | Indicateur | Signification établie |
- | ---------- | ------------------------------------------------------------ |
- | `0x1` | catégorie liée à l'émulation |
- | `0x10` | catégorie liée à l'installation non officielle |
- | `0x40` | signal global d'environnement, alimenté notamment par Verified Boot et l'attestation KeyStore |
- | `0x80` | indicateurs de ROM/environnement, notamment Lineage ou GrapheneOS dans les chemins analysés |
- | `0x100` | tags de build `test-keys` ou `dev-keys` |
- | `0x200` | ADB actif |
- | `0x2` | agrégat automatiquement ajouté lorsqu'un des signaux `0x40`, `0x80` ou `0x100` est actif |
- | `0x1000` | marqueur de classe du statut environnement avant transport vers Java |
- Le code historique :
- ```text
- 0x1242 = 0x1000 | 0x200 | 0x40 | 0x2
- ```
- ne contient ni `0x1` ni `0x10`, ce qui concorde avec la classification Java « environnement non sécurisé » plutôt qu'« émulateur » ou « installation non officielle ».
- Les analyses ont également établi que `0x80` et `0x100` étaient absents du code historique. Cela concorde avec la vue publique observée au moment de l'analyse : build `release-keys` et propriétés de ROM ciblées masquées ou absentes.
- Le CFG du wrapper natif confirme que la construction du bitfield précède une chaîne de contrôles supplémentaires, dont le chemin AndroidKeyStore/attestation. Plusieurs branches peuvent donc contribuer au statut final sans qu'une constante `0x1242` soit stockée telle quelle dans la bibliothèque.
- ---
- # 10. Détection ADB - bit 0x200
- Le bit `0x200` est attribué à un prédicat natif de détection ADB.
- Le chemin inspecte notamment :
- - le port ADB TCP ;
- - l'état du service `adbd` ;
- - la configuration USB ;
- - l'état USB contenant `adb`.
- Le code possède également un mécanisme natif de suivi autour de ce contrôle, et pas seulement un test ponctuel.
- Sur le téléphone analysé, les relevés montrent un état ADB actif, notamment :
- ```text
- persist.adb.tcp.port=5555
- init.svc.adbd=running
- init.svc.adb_root=running
- persist.sys.usb.config=adb
- sys.usb.config=adb
- sys.usb.state=adb
- sys.usb.adb.disabled=0
- settings global adb_enabled=1
- ```
- Ces valeurs correspondent aux conditions recherchées par le prédicat. Le `0x200` du statut historique `0x1242` est donc expliqué par un état ADB effectivement présent.
- ---
- # 11. Verified Boot, propriétés système et bit 0x40
- DexProtector possède un chemin natif qui inspecte notamment :
- - `ro.boot.verifiedbootstate` ;
- - `ro.boot.flash.locked` ;
- - `ro.boot.vbmeta.device_state` ;
- - les mappings de propriétés via `/proc/self/maps`.
- Le contrôle ne se limite pas à comparer une chaîne. Il vérifie également la cohérence du `prop_info` correspondant dans la zone de propriétés Android.
- Une copie des property areas du téléphone a été analysée. La vue publique contenait :
- ```text
- ro.boot.verifiedbootstate=green
- ro.boot.flash.locked=1
- ro.boot.vbmeta.device_state=locked
- ```
- Le modèle local de la partie observable du validateur considère cette vue comme cohérente et ne produit pas de signal d'erreur. Cela réduit la probabilité que la seule propriété publique `green` explique le `0x40` historique.
- En parallèle, l'état boot brut exposé par `/proc/cmdline` reste `orange`. Cette divergence confirme qu'il faut distinguer les propriétés Android visibles et l'état matériel réellement attesté.
- Les snapshots du PID Revolut montrent que les zones de propriétés nécessaires sont bien mappées dans le processus. La libc Bionic locale confirme en outre que la résolution normale d'une propriété renvoie le vrai `prop_info` dans son `prop_area`.
- Le statut final prouve que le global associé à `0x40` était actif, mais sa seule valeur finale ne permet pas de désigner le writer responsable. L'analyse KeyStore ci-dessous fournit cependant une correspondance directe avec une donnée réellement présente sous l'UID de Revolut.
- ---
- # 12. AndroidKeyStore, attestation, RootOfTrust et bit 0x40
- ## 12.1. Chemin d'attestation
- L'image DexProtector reconstruite contient un chemin AndroidKeyStore complet qui :
- - interroge le service Keystore ;
- - utilise une clé EC P-256 ;
- - configure un challenge d'attestation de 8 octets ;
- - récupère une chaîne de certificats ;
- - parse l'extension Android Key Attestation ;
- - examine le niveau de sécurité ;
- - examine `RootOfTrust` ;
- - examine `deviceLocked` et `verifiedBootState` ;
- - classe la racine cryptographique de la chaîne ;
- - vérifie l'identité de l'application attestée.
- L'OID recherché est :
- ```text
- 1.3.6.1.4.1.11129.2.1.17
- ```
- c'est-à-dire l'extension standard Android Key Attestation.
- ## 12.2. Clé persistante liée à Revolut
- Une clé persistante est présente dans le namespace Keystore2 correspondant à l'UID Revolut `10701`. Son alias est `<alias-anonymisé>` (anonymisé) et l'analyse statique montre qu'il correspond au schéma d'alias déterministe utilisé par DexProtector pour le processus Revolut.
- Les métadonnées de la clé indiquent :
- ```text
- ALGORITHM=EC
- EC_CURVE=P_256
- ORIGIN=GENERATED
- PURPOSE=SIGN
- DIGEST=SHA_2_256
- KEY_SIZE=256
- security_level=TRUSTED_ENVIRONMENT
- ```
- Le certificat public d'attestation associé contient :
- ```text
- Application ID: com.revolut.revolut
- device_locked=false
- verified_boot_state=2
- root_of_trust_source=teeEnforced
- ```
- Le digest de signature de l'Application ID correspond au certificat de signature des APK Revolut installés :
- ```text
- 9c9be07135e972780282c2e5d27da06ecb8ee3adfc75303917ddf66d6faaefa4
- ```
- Le hash Verified Boot contenu dans l'attestation observée est (valeur anonymisée) :
- ```text
- <hash-verified-boot> (anonymisé)
- ```
- La chaîne publique est reconnue par le classificateur de DexProtector : l'échec ne s'explique donc pas par une simple racine d'attestation inconnue.
- ## 12.3. Attestation indépendante du même appareil
- Une attestation AndroidKeyStore locale effectuée hors Revolut via `app_process` a produit :
- ```text
- generate_key_pair=success
- certificate_chain_length=4
- attestation_extension_present=true
- attestation_security_level=1:TrustedEnvironment
- keymaster_security_level=1:TrustedEnvironment
- root_of_trust_present=true
- root_of_trust_source=teeEnforced
- device_locked=false
- verified_boot_state=2:Unverified
- tee_os_version=150000
- tee_os_patch_level=202509
- tee_vendor_patch_level=20250601
- tee_boot_patch_level=202509
- ```
- La racine terminale observée est la même famille de racine reconnue par DexProtector.
- ## 12.4. Relation avec le bit 0x40
- Le parser DexProtector possède une condition explicite sur `RootOfTrust` : un appareil annoncé comme non verrouillé ou dont le Verified Boot est `Unverified` active un drapeau interne consommé par le chemin qui positionne le signal global `0x40`.
- Le certificat persistant attaché à l'UID de Revolut possède précisément ces deux caractéristiques :
- ```text
- deviceLocked=false
- verifiedBootState=Unverified
- ```
- Il existe donc une correspondance directe entre :
- 1. le champ d'attestation attendu par le code ;
- 2. la valeur réellement présente dans un certificat associé à Revolut ;
- 3. le signal `0x40` présent dans le statut historique.
- Le modèle du chemin de propriétés publiques, lui, ne reproduit pas d'erreur avec la vue `green/locked`. La cause pratique la plus solidement étayée du `0x40` historique est donc l'attestation TEE/KeyMint réellement retournée à Revolut, et non la simple apparence `green/locked` fournie par `getprop`.
- ## 12.5. Keybox et racine publique
- Le téléphone expose un overlay système de keybox certifiée actif. L'analyse n'a conservé que les certificats publics et leurs empreintes ; aucun matériel privé n'a été reporté. La racine publique résolue par cet overlay correspond à une racine reconnue par DexProtector, ce qui renforce la conclusion que le rejet porte sur les champs de `RootOfTrust` plutôt que sur une chaîne inconnue.
- # 13. Fourthline : contrôles root, hook, instrumentation et environnement
- `libfourthline-security.so` est une bibliothèque native AArch64 qui enregistre un `NativeSecurityChecker` via JNI. Son `JNI_OnLoad` récupère `JNIEnv`, cherche `com/fourthline/core/internal/security/NativeSecurityChecker` et enregistre la méthode native correspondante.
- Imports utiles observés :
- - `__system_property_get` ;
- - `popen` ;
- - `access` ;
- - `fopen` ;
- - `opendir` ;
- - `readlink`.
- Les chaînes et contrôles natifs couvrent notamment :
- ### Root classique
- - `/system/bin/su` ;
- - `/system/xbin/su` ;
- - `/sbin/su` ;
- - `/su/bin/su` ;
- - `/data/local/bin/su` ;
- - `/data/local/xbin/su` ;
- - `busybox` ;
- - commandes `which su`.
- ### Magisk / Zygisk / modules
- - chemins Magisk sous `/data/adb` et `/sbin` ;
- - `/data/adb/modules` ;
- - marqueurs Zygisk ;
- - modules LSPosed / Riru.
- ### Hooking et instrumentation
- - Xposed / EdXposed ;
- - LSPosed ;
- - Riru ;
- - Substrate ;
- - Pine / SandHook / Whale ;
- - Frida, `frida-server`, `frida-gadget`, `libfrida`.
- ### État système
- - `ro.debuggable` ;
- - `ro.secure` ;
- - `ro.build.selinux` ;
- - `service.adb.root` ;
- - `/sys/fs/selinux/enforce` ;
- - `/proc/self/status` ;
- - `/proc/self/maps` ;
- - `/proc/self/mounts` ;
- - `/proc/mounts` ;
- - `/proc/%s/cmdline` ;
- - `/proc/self/fd` ;
- - `test-keys`.
- Cette bibliothèque est bien livrée dans l'APK, mais elle n'est pas chargée visiblement avant le crash DexProtector immédiat dans le lancement de référence. Elle constitue donc une couche de contrôle additionnelle plutôt que la cause immédiate démontrée de `0x1242`.
- ---
- # 14. Credolab / Incognia : collecte et détection root réellement câblées
- Le split `split_feature_credit_data_monitoring_sdk.apk` contient notamment :
- - Credolab behavior `4.15.0-1768558695_moduleRelease` ;
- - Credolab Core `4.19.1` ;
- - Incognia.
- ## 14.1. Détecteur root au niveau du code
- Le détecteur n'est pas une simple collection de chaînes mortes. Le désassemblage montre un bloc root qui :
- 1. recherche `su` via une fonction dédiée ;
- 2. utilise aussi `Runtime.exec(["which", "su"])` si nécessaire ;
- 3. recherche plusieurs composants Magisk ;
- 4. teste par `File.exists()` des chemins liés à Magisk, KernelSU, APatch et divers systèmes Superuser historiques ;
- 5. matérialise le résultat en booléen sérialisé.
- La fonction de recherche de binaire parcourt explicitement des répertoires tels que :
- - `/sbin/` ;
- - `/su/bin/` ;
- - `/system/bin/` ;
- - `/system/xbin/` ;
- - `/vendor/bin/` ;
- - `/product/bin/` ;
- - `/system_ext/bin/` ;
- - `/odm/bin/` ;
- - `/apex/com.android.runtime/bin/` ;
- - ainsi que les entrées du `PATH`.
- Le chemin `/system/bin/su` fait donc partie des marqueurs réellement testés.
- ## 14.2. Intégration dans le pipeline de collecte
- Le descripteur associé au champ root couvre Android API 21 à 9999, donc SDK 35. Il est ajouté à la liste réelle de collecte, intégré au CoreModule Credolab et consommable par le moteur du SDK via son callback `extract`.
- Conclusion : le paquet Revolut 10.145 embarque et câble effectivement un détecteur KernelSU/Magisk/APatch via un SDK tiers. Il n'est cependant pas démontré que ce callback soit invoqué avant le `TerminateException` du lancement très précoce, et il n'est pas nécessaire pour expliquer `0x1242`.
- ---
- # 15. Second détecteur root : DeviceInfo.getIsRooted
- Le split `split_feature_apm_multibanco_sdk_impl.apk` contient un second mécanisme indépendant :
- ```text
- sibs/connector/core/callbacks/model/DeviceInfo.getIsRooted()
- ```
- La méthode exécute successivement plusieurs familles de contrôles et retourne `true` dès qu'une famille est positive :
- - recherche de binaires root par `File.exists()` ;
- - recherche de paquets de gestion root avec `PackageManager.getPackageInfo()` ;
- - exécution de `getprop`, puis recherche de `ro.debuggable=[1]` ou `ro.secure=[0]` ;
- - recherche de fichiers Xposed ;
- - recherche de fichiers/répertoires considérés non autorisés ;
- - exécution de `mount` et détection de montages sensibles en `rw` ;
- - nouvelle passe de détection d'applications de gestion root.
- Sur le téléphone étudié, `/system/bin/su` est visible depuis un processus Android `untrusted_app` Reins. Sa visibilité exacte depuis le PID Revolut peut toutefois différer selon le namespace et les mécanismes d'isolation en place.
- ---
- # 16. Inventaire de paquets, QUERY_ALL_PACKAGES et applications ciblées
- Le manifeste demande :
- ```text
- android.permission.QUERY_ALL_PACKAGES
- ```
- Il référence explicitement plusieurs familles :
- - Magisk ;
- - KernelSU et variantes ;
- - SukiSU ;
- - APatch et variantes ;
- - Xposed / EdXposed ;
- - Substrate ;
- - variantes SuperSU / Superuser ;
- - Lucky Patcher ;
- - App Cloner ;
- - plusieurs émulateurs Android ;
- - plusieurs outils de contrôle distant.
- Deux paquets liés à l'écosystème KernelSU ont été observés sur le téléphone :
- ```text
- io.github.a13e300.ksuwebui
- com.kowx712.supermanager
- ```
- Leurs noms exacts n'ont pas été retrouvés comme constantes dans les APK/splits/ELF Revolut inspectés. Le crash actuel ne peut donc pas être attribué factuellement à une comparaison directe avec ces deux noms précis.
- ---
- # 17. Play Integrity, SafetyNet, Keystore et décision serveur
- ## 17.1. Play Integrity embarqué
- Les DEX contiennent notamment des références à :
- - `com.google.android.play.core.integrity` ;
- - `StandardIntegrityManager` ;
- - `IntegrityTokenRequest` ;
- - `StandardIntegrityTokenRequest` ;
- - `PrepareIntegrityTokenRequest` ;
- - `StandardIntegrityTokenProvider` ;
- - `ExpressIntegrityService` ;
- - requêtes et warm-up de token d'intégrité.
- Des références SafetyNet sont également présentes.
- Le code contient aussi des indicateurs ou clés analytics liés au root et aux requêtes d'intégrité, par exemple :
- - `IS_DEVICE_ROOTED_KEY` ;
- - `ROOTED` ;
- - `isRootedDevice` ;
- - `is_rooted_device` ;
- - `IntegrityTokenRequestsRetryAnalyticsEnabled` ;
- - `EnableIntegrityTokenRetryAnalyticsFirebaseExperiment`.
- Revolut dispose donc à la fois de contrôles locaux, de Play Integrity et de télémétrie relative à ces contrôles.
- ## 17.2. Limite de causalité
- Aucun verdict Play Integrity signé spécifique à Revolut n'a été obtenu pendant l'étude. Aucune requête Play Integrity n'est visible comme cause immédiate avant la terminaison historique. Il est donc incorrect d'attribuer le `TerminateException` immédiat à Play Integrity seul.
- La politique serveur exacte ne peut pas être reconstruite depuis le seul client : elle peut dépendre du verdict, de la version de l'application, du compte ou d'autres signaux.
- ## 17.3. StrongBox
- Le code sait manipuler des notions de StrongBox, mais le téléphone n'annonce pas `android.hardware.strongbox_keystore` dans l'inventaire de features. Aucun besoin StrongBox n'est démontré comme condition du crash historique.
- ---
- # 18. Cartographie statique des SDK, DEX, permissions et API sensibles
- ## 18.1. Familles de code détectées
- | Famille | Types détectés |
- | --------------- | -------------: |
- | AppsFlyer | 564 |
- | DexProtector | 16 |
- | Facebook | 16 |
- | Firebase | 215 |
- | Google GMS | 9545 |
- | gRPC | 21 |
- | Incode | 1856 |
- | ML Kit | 40 |
- | OkHttp | 160 |
- | Onfido | 4578 |
- | Retrofit | 617 |
- | Revolut | 134782 |
- | Sentry | 526 |
- | TensorFlow Lite | 134 |
- | Twilio | 210 |
- ## 18.2. Références d'API sensibles
- | Catégorie | Nombre |
- | ------------------------------ | -----: |
- | Accessibilité / presse-papiers | 60 |
- | Biométrie | 384 |
- | Build props | 1 |
- | Caméra / micro / capteurs | 183 |
- | Code dynamique / processus | 22 |
- | Keystore / attestation | 167 |
- | Localisation | 628 |
- | État réseau | 84 |
- | NFC | 29 |
- | Inventaire packages | 46 |
- | Identifiants Settings | 9 |
- | Téléphonie | 65 |
- ## 18.3. Chaînes sensibles comptées
- | Catégorie | Nombre |
- | --------------------------------------- | -----: |
- | Biométrie / NFC / caméra / localisation | 190 |
- | Boot / build / intégrité | 475 |
- | Identifiants appareil | 250 |
- | Keystore / attestation / intégrité | 272 |
- | Exécution native/dynamique | 1 |
- | Réseau / transport | 871 |
- | Inventaire applications | 106 |
- | Play Integrity / SafetyNet | 18 |
- | Root / frameworks | 161 |
- ## 18.4. Appels DEX sensibles comptés
- | Catégorie | Nombre |
- | ------------------------------ | -----: |
- | Accessibilité / presse-papiers | 136 |
- | Biométrie | 209 |
- | Build props | 3 |
- | Caméra / micro / capteurs | 733 |
- | Code dynamique / processus | 34 |
- | Keystore / attestation | 363 |
- | Localisation | 302 |
- | Réseau | 160 |
- | NFC | 42 |
- | Inventaire packages | 212 |
- | Identifiants Settings | 54 |
- | Téléphonie | 88 |
- Ces chiffres mesurent des références statiques. Ils incluent du code tiers et des chemins qui peuvent ne jamais être exécutés dans le scénario de crash étudié.
- # 19. Bibliothèques natives et capacités observées
- ## 19.1. Inventaire ARM64
- 21 bibliothèques natives ont été inventoriées :
- | Bibliothèque | Taille | SHA-256 |
- | --------------------------------- | -------: | ------------------------------------------------------------ |
- | `libNativeBridge.so` | 8250512 | `dbce54e598fcf7ca8f82d2bcde0c2b688e72733652315e9782f9e9ecdd29e95e` |
- | `libalice.so` | 483576 | `a5bf3803653f6ca10f03dcde7ad134613525c95160a9b4c4b8344ec0ecb550bd` |
- | `libandroidx.graphics.path.so` | 10096 | `41e9a793c43a0f4fddb19e33f346bace464f30f888ba7b9eaf96294ea115bfb6` |
- | `libbitmap_effects.so` | 267256 | `d2adaf1b4a2906cd0516db8415df8bb9b1406919e436a07b5d882bab07b01798` |
- | `libcamerakit_memfd_compat.so` | 23704 | `019ce81d6e30e831d3378490c0ecaf3b6f7192050e00aa2afa3e67ad81824f42` |
- | `libdatastore_shared_counter.so` | 7112 | `d3e48717c9aa147e0ab21063ba0e8e0211cabf8bf40b222640829519edbf58e1` |
- | `libdexprotector.so` | 443222 | `81bbed87aaa3fb03285d37bd04952dd18b0ba5f33e958e3f866791fa8034aeee` |
- | `libfourthline-security.so` | 11784 | `abfb8be17ec0ec372acb93910d8452806a8d9baf57ae02f482d18bf27e3f389d` |
- | `libimage_processing_util_jni.so` | 32528 | `0292b063fafccf734472cbb59588e756c2dbca907c72021ba6fbf126385508a2` |
- | `librev_vision_android.so` | 17429056 | `9b31cd09a5af4b0c1c36cb94958149130c782e7965a61b54e7933b44aff95200` |
- | `libsqlcipher.so` | 5186904 | `036c7311139c12f92244aa3c2660e818f586379b7fcc348f4a6b8f9f2eda5ffe` |
- | `libsurface_util_jni.so` | 4896 | `a5c9d1928ea92ec7a94dff8cf666e7739cd734198b9f0ae1d4e28ea3c86516ba` |
- | `libtensorflowlite_jni.so` | 4320528 | `85b97f038170c1c3137ba5e2f70d1435cc2cda5a7b07570e2192a38a0b5bdda8` |
- | `libc++_shared.so` | 1253536 | `97176175c08bbd4af66836d290195797fff6c82e7b6261814fbe955f2f7ea02a` |
- | `libmbway-lib.so` | 7399144 | `e83403453e44f4091290a4af9b225f50ca40e85b542e60c7dee21b9d2f70f9c7` |
- | `libtwilio_voice_android_so.so` | 11446840 | `a7b3bca035ee9b0ea0fda7d18e3a454679cd0d17ceb68a82beab861d8e22d08a` |
- | `libRecogKitAndroid.so` | 1203520 | `45728587b6201c6bced045455af7f02852add076408e332c4a46960fd6d1b8c9` |
- | `liba94abe.so` | 103448 | `ad4cf6086838c2e483f7211552666c2376e5a15cecf4439229718401fc4d54d6` |
- | `libd4a2.so` | 1138616 | `52cc132c340865309d22d585a6b80fc2406fb12184447378beef50627fe55d59` |
- | `libsentry-android.so` | 16072 | `9cf26d69a0741bd2176b8a118aca3ecf9470849a6c437bf383b3034c44800657` |
- | `libsentry.so` | 1219960 | `901b3c5eae3d59722f5d639b172c983b790bc038750070947b79ee2fe184248f` |
- `libalice.so` importe notamment `getuid`, les API de propriétés système, `dlopen`, `dlsym`, `open`, `opendir`, `stat`, `kill`, `sigaction` et `syscall`. Elle contient aussi des chaînes relatives au fingerprint, au numéro de série et à l'attestation de clés. Ces primitives sont générales et ne suffisent pas, seules, à qualifier chaque usage.
- `libsentry.so` contient des capacités de lecture de `/proc/self/maps`, d'unwinding, de `ptrace`, de fingerprint d'événement, de proxy HTTP/HTTPS et de stockage local Sentry. Leur présence ne prouve pas que toutes soient exécutées pendant le crash étudié.
- ---
- # 20. Assets, DEX embarqués et MessageGuardException
- ## 20.1. Assets significatifs
- | Asset | Taille | SHA-256 | Constat |
- | ------------------------------- | -----: | ------------------------------------------------------------ | ----------------------------------------- |
- | `assets/assets.dat` | 348054 | `c0b309d27b99923e04c84786b75d73007ca2e123e397ae085a4b8d3fd66e8463` | forte entropie, pas de signature évidente |
- | `assets/dp_db.mp3` | 736397 | `e9c8c2bd0bdf705f8f3f23bc58e46e0435981cd157c06ec9f248de4431e6b1c4` | forte entropie, pas de MP3 utile |
- | `assets/ict.dat` | 10171 | `84663187f4b4161f1c284da1c0a7ffa4fa751f71f878198b87670dbf2859b81e` | données de confiance/certificats |
- | `res/raw/dexprotector_keep.xml` | 251 | `9a60cdbe78e0354b0eb822db145fd648fbf78b96326650a9f0d135c19b5eb81e` | ressources activité d'erreur |
- Le rôle précis de `assets.dat` et `dp_db.mp3` dans le statut historique n'a pas été démontré.
- ## 20.2. DEX embarqués dans l'image reconstruite
- Deux blobs DEX parsables ont été trouvés : un canari de 300 octets à `0x6a80`, sans méthode, et un DEX de 780 octets à `0xa8000` contenant `com/revolut/MessageGuardException`.
- SHA-256 du second :
- ```text
- 6de6032db6ff0183a3490a196b67c9c555a11c2fa4ba4bb266da7353e5b66768
- ```
- `MessageGuardException` hérite de `RuntimeException`, implémente `Runnable`, remplace sa stack trace par un tableau vide, relance l'exception elle-même dans `run()` et retourne seulement son message dans `toString()`.
- Cette classe démontre une capacité à produire des erreurs volontairement difficiles à diagnostiquer. Elle ne doit pas être confondue avec l'exception réellement observée, `android.app.TerminateException$...`.
- ---
- # 21. Snapshots du processus Revolut et visibilité réelle des traces root
- ## 21.1. Snapshot précoce
- Un processus Revolut capturé avant terminaison présentait :
- ```text
- UID/GID : 10701
- SELinux : u:r:untrusted_app:s0:c189,c258,c512,c768
- exe : /system/bin/app_process64
- TracerPid=0
- Seccomp=2
- Seccomp_filters=1
- CapEff=0
- ```
- Aucune occurrence évidente n'a été trouvée dans `maps`, `mountinfo`, `status`, `cmdline`, `selinux_current` ou `exe` pour des marqueurs tels que `/data/adb`, KernelSU, Magisk, Zygisk, Xposed, Frida, `/system/bin/su` ou le nom du noyau Scarlet.
- Cette absence dans les snapshots textuels n'exclut pas des tests de fichiers à la volée, des appels `uname`, l'analyse des propriétés, l'attestation ou Play Integrity.
- ## 21.2. Série de 16 snapshots
- Sur le PID `27354` :
- - `cmdline=com.revolut.revolut` dès le premier sample ;
- - même UID et contexte SELinux ;
- - 11 à 22 threads ;
- - mappings des splits APK visibles à partir du sample 1 ;
- - aucun marqueur root évident dans les chaînes de `maps` ;
- - les noms `libalice.so` et `libdexprotector.so` n'apparaissent pas dans les chaînes `maps`, malgré leur chargement prouvé par logcat.
- Une bibliothèque chargée depuis un APK peut donc être exécutée sans apparaître sous son nom textuel évident dans `/proc/<pid>/maps`.
- ## 21.3. Namespace et permissions de fichiers
- Depuis une vue root sur `/proc/<pid>/root`, `/data/adb/ksu` et `/data/adb/modules` existent, mais les permissions observées comprennent :
- ```text
- /data 0771 system:system
- /data/adb 0700 root:root
- ```
- Un UID applicatif comme `10701` ne peut normalement pas traverser `/data/adb` directement. Il serait donc incorrect de conclure qu'un simple `File.exists("/data/adb/ksu")` dans Revolut doit nécessairement réussir parce que root voit ce chemin.
- # 22. Profils Android et espaces utilisateurs
- Les espaces utilisateurs observés sont :
- - User 0 : profil principal ;
- - User 10 : Private space ;
- - User 11 : `Revo` ;
- - User 12 : cloneUser.
- État Revolut :
- - User 0 : installé, activité login résolue, crash reproductible ;
- - User 11 : paquet marqué installé mais aucune activité résolue par `cmd package resolve-activity` ;
- - User 10 / User 12 : pas d'installation exploitable observée.
- Le test du profil secondaire n'établit donc ni succès ni échec des contrôles d'intégrité : l'installation User 11 n'était pas lançable normalement.
- ---
- # 23. Matrice de causalité et conclusions de confiance
- ## 23.1. Faits de confiance élevée
- - Revolut 10.145 est correctement fourni pour ARM64 ;
- - le problème n'est pas une incompatibilité ABI simple ;
- - `LoginActivity` démarre ;
- - `libalice.so` puis `libdexprotector.so` sont chargées ;
- - Revolut tente de lire `ro.debuggable` et `ro.lineage.build.version` ;
- - `ProtectedRevolutApplication$I` est une véritable Activity interne ;
- - le processus principal termine avec `TerminateException` ;
- - Android classe la sortie en `APP CRASH(EXCEPTION)` ;
- - l'écran historique sélectionne « environnement non sécurisé » ;
- - le code historique est `4674 = 0x1242` ;
- - `0x1242` contient `0x200`, `0x40`, `0x2` et `0x1000` ;
- - `0x200` correspond à ADB actif ;
- - `0x2` est un agrégat lié à la famille `0x40/0x80/0x100` ;
- - le chemin KeyStore/RootOfTrust peut produire le signal `0x40` ;
- - le certificat persistant du namespace Revolut présente précisément les valeurs RootOfTrust rejetées par ce chemin ;
- - Fourthline contient des contrôles explicites root/hook/instrumentation ;
- - Credolab contient un détecteur root fonctionnel et câblé ;
- - le split Multibanco contient un second détecteur root ;
- - Play Integrity/SafetyNet sont présents ;
- - le manifeste autorise un inventaire large des packages.
- ## 23.2. Explication la plus forte du statut historique
- La combinaison la mieux étayée est :
- ```text
- ADB actif -> 0x200
- RootOfTrust TEE non conforme -> 0x40
- 0x40 actif -> agrégat 0x2
- classe environnement -> 0x1000
- => 0x1242
- => catégorie UI « environnement non sécurisé »
- ```
- L'attestation observée contient :
- ```text
- deviceLocked=false
- verifiedBootState=2:Unverified
- ```
- et le code DexProtector possède un contrôle explicite sur ces champs.
- ## 23.3. Éléments pertinents mais non démontrés comme cause unique
- Ne doivent pas être présentés comme déclencheurs uniques du crash :
- - KernelSU ;
- - `/system/bin/su` ;
- - nom de noyau `Scarlet-v6.0` ;
- - `/data/adb/ksu` ;
- - `/data/adb/modules` ;
- - présence de frameworks Zygisk/LSPosed ;
- - noms particuliers des gestionnaires KernelSU installés ;
- - fingerprint Android 14 sur système Android 15 ;
- - absence de StrongBox ;
- - Play Integrity ;
- - le blocage BAL ;
- - `ro.debuggable` seul ;
- - `ro.lineage.build.version` seul ;
- - Credolab seul ;
- - Fourthline seul.
- Ces éléments peuvent alimenter d'autres couches de décision sans être nécessaires pour expliquer le `0x1242` historique.
- ## 23.4. Matrice résumée
- | Élément | Présent / observé | Cause immédiate établie ? |
- | --------------------------------- | ----------------- | ----------------------------------- |
- | Android 15 / SDK 35 | oui | non |
- | ARM64 | oui | compatible |
- | SELinux Enforcing | oui | non |
- | Build public `user/release-keys` | oui | non |
- | Build réel `userdebug` | oui | non isolément |
- | Verified Boot public `green` | oui | non isolément |
- | Boot brut `orange` | oui | signal pertinent |
- | Noyau custom | oui | non isolément |
- | KernelSU | oui | non isolément |
- | ADB actif | oui | oui pour le bit `0x200` |
- | Attestation `deviceLocked=false` | oui | alimente le chemin `0x40` |
- | Attestation `verifiedBootState=2` | oui | alimente le chemin `0x40` |
- | Play Integrity présent | oui | pas comme cause immédiate démontrée |
- | Fourthline présent | oui | pas chargé avant le crash immédiat |
- | Credolab root detector | oui | pas nécessaire à `0x1242` |
- | `DeviceInfo.getIsRooted()` | oui | pas nécessaire à `0x1242` |
- ---
- # 24. Critères de compatibilité à vérifier sur un autre appareil
- Ce chapitre fournit des critères de diagnostic et de comparaison, pas une procédure de contournement.
- ## 24.1. Exigences déclaratives
- | Élément | Valeur |
- | ----------------------------- | ----------- |
- | Android minimum | API 28 |
- | OpenGL ES | 3.0 requis |
- | ABI de l'installation étudiée | ARM64 |
- | Installateur observé | Google Play |
- ## 24.2. Signaux à mesurer réellement
- Pour comparer un autre appareil ou une autre ROM, les données les plus utiles sont :
- - état de boot brut et propriétés Android exposées ;
- - `deviceLocked` et `verifiedBootState` de l'attestation KeyMint/TEE ;
- - cohérence entre version Android, fingerprint et build ;
- - état ADB réel ;
- - disponibilité et niveau de sécurité AndroidKeyStore ;
- - code d'erreur affiché par Revolut ;
- - classification de l'écran protégé ;
- - logs de chargement des bibliothèques ;
- - `ApplicationExitInfo`.
- Le reverse engineering montre surtout qu'un simple `getprop ro.boot.verifiedbootstate=green` ne suffit pas à conclure à la compatibilité, car DexProtector dispose d'un chemin d'attestation matérielle indépendant des propriétés de surface.
- # 25. Artefacts et scripts d'analyse
- ## 25.1. Artefacts de preuve mentionnés dans le corpus
- Les rapports s'appuient notamment sur les groupes d'artefacts suivants sous `build/revolut-readonly-analysis/` :
- - structure APK et DEX : `apk_structure_summary.json`, `dex_keyword_summary.json`, `dex_xref_summary.json`, `apk_assets_inventory.json`, `asset_profile_summary.json` ;
- - bibliothèques natives : `native_lib_summary.json`, `native_string_scan.json`, `revolut_native_library_inventory.json`, `revolut_native_string_capability_map.json` ;
- - reconstruction DexProtector : `dexprotector_stream_decoded_scan.json`, `dexprotector_segments_parse.json`, `dexprotector_reconstructed_image.bin`, `dexprotector_reconstructed_image_summary.json`, `dexprotector_dynamic_parse.json`, `dexprotector_imports.json`, `dexprotector_string_xrefs.json` ;
- - DEX internes : `messageguard_scan.json`, `dexprotector_embedded_dex_summary.json`, `dexprotector_embedded_dex_code.json`, `dexprotector_embedded_dex_code_summary.json` ;
- - bitfield et chaînes de contrôle : `dexprotector_bit_context.json`, `dexprotector_status_bitfield_callers.json`, `dexprotector_bit_ops.json`, `dexprotector_check_chain.json`, `dexprotector_global_store_sites.json` ;
- - chaînes décodées et imports : `dexprotector_decoded_security_strings.json`, `dexprotector_decoded_security_strings_unicorn.json`, `dexprotector_extra_decoded_strings.json`, `dexprotector_global_pointers.json`, `dexprotector_init_imports.json`, `dexprotector_import_callers.json`, `dexprotector_selected_import_targets.json`, `dexprotector_selected_got_symbols.json`, `dexprotector_selected_static_pointers.json` ;
- - état appareil : `device_security_properties.json`, `device_boot_raw_state.json`, `device_feature_flags.json`, `termux_root_targeted_state.json`, `termux_root_targeted_state_summary.json` ;
- - propriétés Android : `property_area_target_scan.json`, `boot_validator_property_area_model.json`, `proc_property_maps_summary.json`, `proc_bootloader_prop_addresses.json` ;
- - KeyStore/attestation : `native_keystore_keyword_scan.json`, `dexprotector_keystore_string_sites.json`, `dexprotector_0x40_setter_sites.json`, `dexprotector_attestation_oid.json`, `termux_app_process_attestation_diag.json`, `termux_keymaster_metadata.json`, `framework_keymint_enums.json`, `revolut_existing_keystore_cert_summary.json`, `revolut_existing_cert_dp_flag_model.json`, `dexprotector_alias_hypotheses.json`, `dexprotector_builder_strings.json`, `dexprotector_alias_challenge_facts.json`, `revolut_signature_digest_check.json`, `existing_keystore_marker_scan.json` ;
- - capacités globales : `revolut_app_capability_map.json`, `revolut_app_capability_map_summary.json`, `revolut_installed_package_state.json` ;
- - captures contrôlées : `controlled_launch_broad_summary.json`, `controlled_launch_broad_logcat.txt`, snapshots `/proc`, copies ciblées des property areas, frameworks et bibliothèques nécessaires aux vérifications hors ligne ;
- - inventaire natif approfondi : `dexprotector_deep_inventory.json`, `dexprotector_keystore_field_xrefs.json`, `dexprotector_entropy_string.json`.
- Désassemblages ciblés cités :
- - `revolut-readonly-dexprotector-adb-predicate-disasm.txt` ;
- - `revolut-readonly-dexprotector-composite-property-rule-disasm.txt` ;
- - `revolut-readonly-dexprotector-targeted-disasm.txt` ;
- - `revolut-readonly-dexprotector-boot-adb-predicates-disasm.txt` ;
- - `revolut-readonly-dexprotector-boot-helpers-disasm.txt` ;
- - `revolut-readonly-dexprotector-version-globals-disasm.txt` ;
- - `revolut-readonly-dexprotector-keystore-path-disasm.txt`.
- ## 25.2. Helpers d'analyse sous `tool/android`
- Le corpus cite notamment :
- - `revolut-readonly-smali-xrefs.py`, `revolut-readonly-protected-app-methods.py`, `revolut-readonly-root-detector-methods.py` ;
- - `revolut-readonly-dexprotector-elf.py`, `revolut-readonly-dexprotector-embedded-dex-code.py` ;
- - `revolut-readonly-device-props.py`, `revolut-readonly-device-feature-flags.py`, `revolut-readonly-boot-raw-state.py` ;
- - `revolut-readonly-native-cmdline-string-scan.py`, `revolut-readonly-native-keystore-keyword-scan.py` ;
- - `revolut-readonly-dexprotector-keystore-string-sites.py`, `revolut-readonly-dexprotector-0x40-setter-sites.py` ;
- - `revolut-readonly-property-area-scan.py`, `revolut-readonly-boot-validator-model.py`, `revolut-readonly-proc-property-maps.py`, `revolut-readonly-proc-bootloader-prop-addresses.py` ;
- - `revolut-readonly-dexprotector-bit-semantic-disasm.py`, `revolut-readonly-dexprotector-boot-writer-disasm.py`, `revolut-readonly-dexprotector-extra-string-decode.py` ;
- - `revolut-readonly-der-oid-decode.py` ;
- - `revolut-readonly-termux-root-state.py`, `revolut-readonly-termux-root-summary.py`, `revolut-readonly-termux-attestation-app-process.py`, `revolut-readonly-termux-keymaster-metadata.py` ;
- - `revolut-readonly-framework-keymint-enums.py`, `revolut-readonly-revolut-keystore-existing-cert.py`, `revolut-readonly-existing-cert-dp-flag-model.py` ;
- - `revolut-readonly-dexprotector-alias-hypotheses.py`, `revolut-readonly-dexprotector-builder-strings.py`, `revolut-readonly-dexprotector-attestation-builders.py`, `revolut-readonly-dexprotector-attestation-facts-summary.py` ;
- - `revolut-readonly-revolut-signature-digest.py` ;
- - `revolut-readonly-dexprotector-import-targets.py`, `revolut-readonly-dexprotector-init-imports.py`, `revolut-readonly-dexprotector-got-symbols.py`, `revolut-readonly-dexprotector-static-pointers.py` ;
- - `revolut-readonly-dexprotector-entropy-callbacks.py`, `revolut-readonly-dexprotector-entropy-string.py`, `revolut-readonly-dexprotector-random-core-disasm.py` ;
- - `revolut-readonly-app-capability-map.py`, `revolut-readonly-installed-package-state.py`, `revolut-readonly-native-library-inventory.py`, `revolut-readonly-native-string-capability-map.py` ;
- - `revolut-readonly-controlled-launch-broad-map.py`, `revolut-readonly-dexprotector-deep-inventory.py`, `revolut-readonly-dexprotector-keystore-field-xrefs.py` ;
- - `revolut-readonly-write-capability-markdown.py`, `revolut-readonly-dexprotector-write-markdown.py`, `revolut-readonly-existing-keystore-marker-scan.py`, `revolut-readonly-dexprotector-keystore-disasm.py`.
- `TERMUX_EMBEDDED_PLAN.md` décrit principalement l'infrastructure Reins/Termux. Pour cette étude, son apport pertinent est l'existence d'un environnement Unix local, d'un accès root contrôlé et d'outils d'analyse disponibles sur Android. Son architecture de développement propre n'est pas un résultat sur Revolut et n'est donc pas reproduite.
- # 26. Limites méthodologiques et périmètre exclu
- ## 26.1. Capacité statique ≠ exécution
- Une classe, une permission, une chaîne, un import ou une API dans l'APK démontre une capacité ou une dépendance, pas son exécution à chaque lancement.
- ## 26.2. Exécution ≠ transmission réseau
- Même lorsqu'une donnée est obtenue localement, son envoi réseau doit être prouvé séparément. La simple présence d'OkHttp, Retrofit, gRPC, Firebase, AppsFlyer ou Sentry ne suffit pas à attribuer un transfert précis.
- ## 26.3. Logs silencieux
- L'absence de ligne Keystore/KeyMint dans logcat ne prouve pas l'absence d'une transaction. La revalidation de 19:49 confirme l'existence du service Keystore2 mais n'a pas attribué de transaction d'attestation précise à l'UID Revolut dans cette capture.
- ## 26.4. Instrumentation intrusive non utilisée
- La preuve instruction par instruction du passage live dans chaque branche de DexProtector exigerait une instrumentation du processus protégé ou du service Keystore. Cette instrumentation intrusive n'a pas été utilisée dans le corpus de référence.
- ## 26.5. Évolution du contexte d'observation
- Certaines observations tardives ont été faites dans un environnement système dont la vue exposée aux applications avait évolué par rapport au lancement historique `0x1242`. Elles ne doivent pas être utilisées pour réécrire rétroactivement les causes du crash historique. Inversement, un lancement réussi dans un contexte modifié ne supprime pas les capacités statiques de détection toujours présentes dans Revolut 10.145.
- ## 26.7. Corpus lu
- Les sept documents textuels/JSON indexés dans `docs/` ont été lus intégralement :
- - `REVOLUT_ANDROID_INTEROPERABILITY_ANALYSIS.md` ;
- - `REVOLUT_ANDROID_INTEROPERABILITY.md` ;
- - `REVOLUT_ANDROID_READONLY_CAPABILITY_MAP.md` ;
- - `REVOLUT_ANDROID_READONLY_DEXPROTECTOR_MAP.md` ;
- - `REVOLUT_ANDROID_READONLY_INTEROP_ANALYSIS.md` ;
- - `REVOLUT_READONLY_REVALIDATION_2026-09-04_1949.json` ;
- - `TERMUX_EMBEDDED_PLAN.md`.
- Le répertoire contient aussi `docs.zip`. Le workspace le traite comme un fichier binaire et refuse sa lecture directe ; il n'est pas indexé comme document textuel distinct par l'inspection du workspace. La présente consolidation couvre donc l'intégralité du corpus textuel/JSON accessible dans `docs/`.
- ---
- # 27. Résumé final
- Le reverse engineering de Revolut Android 10.145 montre une application fortement protégée et dotée d'une surface d'inspection du terminal très étendue.
- Sur le téléphone étudié, le lancement historique échoue volontairement pendant la phase DexProtector. Le statut capturé est :
- ```text
- 4674 = 0x1242
- ```
- Sa décomposition établie est :
- ```text
- 0x1000 marqueur de classe du statut environnement
- 0x200 ADB actif
- 0x40 signal d'environnement
- 0x2 agrégat automatiquement ajouté à cause de la famille 0x40/0x80/0x100
- ```
- L'écran d'erreur classe ce statut comme :
- ```text
- environnement non sécurisé
- ```
- Le bit `0x200` est relié au contrôle ADB et correspond à l'état réel du téléphone lors de la capture.
- Pour `0x40`, le chemin AndroidKeyStore/attestation est particulièrement probant. Le certificat persistant associé au namespace Revolut contient :
- ```text
- deviceLocked=false
- verifiedBootState=2:Unverified
- ```
- et DexProtector possède un contrôle RootOfTrust sur ces champs. En parallèle, le modèle du chemin de propriétés publiques considère la vue `green/locked` comme cohérente. L'attestation matérielle fournit donc l'explication la plus solide du `0x40` historique.
- Au-delà de cette phase immédiate, Revolut contient plusieurs couches supplémentaires capables de détecter root, KernelSU, Magisk, APatch, Zygisk, Xposed, LSPosed, Frida, état SELinux, montages, packages installés, propriétés de build et autres indicateurs système. Il embarque aussi Play Integrity, SafetyNet, plusieurs SDK de télémétrie et d'anti-fraude, ainsi que de nombreuses capacités relatives à la localisation, aux capteurs, à la téléphonie, aux identifiants, à la biométrie et à l'inventaire applicatif.
- Pour l'utilisateur final, le constat de confidentialité est que Revolut 10.145 dispose d'une capacité technique importante pour profiler le terminal et son environnement, et peut conditionner l'accès à l'application à des caractéristiques matérielles et logicielles profondément internes à l'appareil. Le document distingue volontairement cette capacité de ce qui est effectivement exécuté, obtenu et transmis, afin de ne pas transformer des possibilités statiques en affirmations non démontrées.
Add Comment
Please, Sign In to add comment