Malva.RE Decompiles VB5/VB6 with VBReFormer Gen 2

Malware Research 6 min read

Visual Basic 5 and 6 executables have not left the triage queue. They are small, easy to produce with a builder, and a plain strings extractor gives a misleading picture of them: addresses, passwords and @Placeholder markers mixed together, with no indication of what the program actually uses.

Malva.RE now supports these executables. The report presents the project reconstructed by VBReFormer Gen 2 (7.x), readable procedure by procedure, and, for the DarkCloud family, an exfiltration configuration established from the code. The DarkCloud 4.9 case serves as the example; its complete technical analysis is published separately.

What the report shows

A project, not a list of strings. For a VB5/VB6 executable, the sample tree contains a [VB6 project] entry: the project file, the form or forms with their properties and event handlers, the modules, the resources and the export notes. Those notes flag what the reconstruction did not recover, rather than replacing it with a plausible value. Every module opens in the code reader; you can start from a form event and follow the calls down to the routines that prepare and send the data.

For DarkCloud, a configuration read in the code. When the Hunt_DarkCloud_Stealer_Variants rule, published by Evelyne Diaz Araque at Stairwell (rule and context), identifies a VB5/VB6 executable, the report presents the exfiltration transports the program contains and tells those this build enables apart from those it leaves disabled. For the active branch, the parameters are given with their role: recipient, server, account, password, port, SSL setting, authentication mode. For the disabled branches, builder markers stay markers, not network indicators. The staging directory is kept in symbolic form, with its environment variables.

What matters to the analyst is traceability: every value points back to the procedure and the argument that use it and, when the reconstructed code is not enough, to the disassembly that corroborates it. A value displayed without its context is a claim; a value tied to an instruction is verifiable.

Why a dedicated decompiler

Classic VB5/VB6, VBA and VB.NET share part of their syntax, not their execution format.

TechnologyWhat there is to analyzeIn Malva.RE
VBAProject embedded in an Office document, macro streams, Office-specific compiled representationvbaDna: VBA decompilation and VBA Stomping detection
VB.NET.NET assembly, CLR metadata, IL codeOutside the scope of this article
Native VB5/VB6x86 PE, VB metadata, machine instructions, MSVBVM60 runtime conventionsVBReFormer Gen 2 (7.x) — the case in this article
P-code VB5/VB6VB metadata and instructions for the VB virtual machineVBReFormer Gen 2 (7.x) — outside the case in this article

In a native VB6 program, the meaning of the x86 instructions depends to a large extent on the runtime’s conventions: BSTR strings carrying their length, VARIANT values carrying their type, late-bound COM calls whose primitive does not say which object or property is targeted. Matching instructions against the project structures and the runtime conventions is what turns a disassembly into readable procedures. The output remains a reconstruction: procedure names such as proc_46CD10 are for navigation, they are not the original names. The technical analysis details these difficulties and what VBReFormer Gen 2 (7.x) brings to overcome them.

The analyst journey

  1. Identify. The file is recognized as a VB5/VB6 executable; if it matches the DarkCloud rule, the configuration reading is added to the decompilation.
  2. Open the sources. Under [VB6 project], forms and modules are read in the report; resources stay resources, the export notes remain readable separately.
  3. Follow the program. From the form’s load event to the initialization, then to the collection routines and the sending dispatcher.
  4. Read the configuration. The transports, their state in this build, the values of the active branch and the unreplaced markers of the others.
  5. Verify. Every conclusion points back to a procedure, an argument or an instruction; an undetermined value stays undetermined.

DarkCloud 4.9, in brief

The sample studied, SHA-256 367383cfaa2ffc1404ba4ac1364a96992d78e036a0a67c994fbd6686f636474e, is a 460 KiB x86 PE compiled as native VB6, which identifies itself through the internal string Agent: DARKCLOUD V4.9. The Stairwell rule finds 14 $s* indicators out of 14 in it, against a threshold of 6 on that branch. It was never executed: decompilation, YARA checking and configuration reading operated on its bytes only.

VBReFormer Gen 2 (7.x) produced an export of 11 files, eight of which are code views: five application modules, one form and two generated helpers.

The configuration is read in an exfiltration dispatcher with four branches whose conditions are constant: 0 = -1 for FTP, HTTP and Telegram, -1 = -1 for SMTP. In this build, only the SMTP transport is enabled: server mail[.]mokasco[.]com quoted in defanged form, port 587, SSL setting false, authentication smtpauthenticate=1, i.e. cdoBasic. The three other branches exist in the code but only receive markers, @GateUrl, @StrBotToken, @ChatID: they are not network IOCs. The staging directory is %AppData%\Microsoft\Windows\Templates\%COMPUTERNAME%-%USERNAME%, kept with its variables.

That dispatcher is publicly browsable: Module7.proc_46CD10 in the VBReFormer demonstration. The Form1 form lets you start from the entry point. SMTP authentication illustrates the approach: the reconstructed code flags an unrecovered __vbaLateCallSt call, and it is the reading of the VARIANT in the malware’s x86 instructions that establishes the value 1.

The Malva.RE report for the sample shows the reconstructed project and the configuration as they appear to the analyst.

DarkCloud exfiltration dispatcher decompiled by VBReFormer: disabled FTP branch, enabled SMTP branch, credentials masked

The dispatcher in the VBReFormer Online demonstration, lines 15 to 30: the constant condition 0 = -1 neutralizes the FTP branch, -1 = -1 enables the SMTP branch. Retouched capture: credential-bearing variables renamed, values replaced with <masqué>, host defanged.

The SMTP accounts, recipient and password, present in clear text in the file, are masked in this publication. The host name is a value from the file: it says nothing about the server’s current status and does not attribute the malware to the organization whose name it carries. The false SSL setting describes a configuration, not an observation of traffic.

What this support does not promise

Decompilation is a reconstruction, with its diagnostics. Original local names and comments are not in the executable; some expressions or calls can remain partial and are flagged as such. This case documents a native VB6 program: P-code belongs to the same tool, but not to this study.

The malware code is never executed. No connection to the extracted server, no trial of the credentials, no message sending were performed; the conclusions describe the code and its static configuration.

This case is neither a benchmark nor a comparison with other tools or other generations of VBReFormer. A clear-text configuration in this build does not mean every DarkCloud version stores its parameters that way, and a YARA match remains a starting point that the code has to corroborate.

Compressed executables first go through Malva.RE’s unpacking stages, such as static UPX unpacking.

Going further

Try Malva.RE on a real malware sample

Understand malware structure and behavior without execution

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

Tags: VBReFormer VBReFormer Gen 2 VB5 VB6 Visual Basic 6 Decompilation DarkCloud Malva.RE
// Built in Savoie

Designed and built in Savoie by Yneos

Malva.RE is published by Yneos, a French cybersecurity and secure software development company based at Savoie Technolac (Le Bourget-du-Lac, France).

Discover Yneos →

// Malva.RE

Try Malva.RE on a real malware sample

Understand malware structure and behavior without execution

Try for free

Free plan: public reports

Request a demo →