VBReFormer a vingt ans. Sa première version décompilait déjà du Visual Basic 6 natif à une époque où l'on nous expliquait que « le natif VB6, ça ne se décompile pas ». Depuis, chaque binaire étrange, chaque idiome de compilateur, chaque bizarrerie de MSVBVM60 a fini par entrer dans le produit.

V7 garde cette connaissance et jette tout le reste.

Ce moteur réécrit est aussi celui du décompilateur VB6 en ligne — le même code, dans le navigateur, sans rien installer.

Le moteur est réécrit intégralement, en .NET, à partir de zéro. Pas un portage : une réécriture, où seule la sémantique — dix ans d'observation du runtime VB6 — a été conservée. Et pour la première fois, le natif et le P-code sont traités par le même produit, au même niveau de finition.

Ce qui change vraiment

1. Le natif, enfin traité comme un vrai problème de décompilation

L'ancien moteur travaillait par reconnaissance de motifs : il savait à quoi ressemble le code que génère VB6, et il le rendait. Cela marche magnifiquement — jusqu'au binaire compilé avec un profil d'optimisation inhabituel.

V7 procède autrement. Il interprète abstraitement le code machine : registres, mémoire virtuelle, pile FPU, avec double suivi de la valeur littérale et de l'expression qui l'a produite. Le désassemblage passe par Iced. Le résultat est un arbre d'expressions, pas une chaîne reconnue.

La différence se voit sur les cas difficiles :

  • les quatre profils d'optimisation VB6 (Fast Code, Favor Small Code, No Optimization, Remove Safety Checks) sont couverts et mesurés séparément — et, contre-intuitivement, c'est No Optimization qui est le plus dur
  • les tables de saut d'un Select Case sont suivies, y compris quand le corps d'un Case n'a pas d'arête entrante évidente
  • le modèle Variant est reconstruit (balise, valeur, ByRef) au lieu d'être deviné
  • les UDT sur la pile, les tableaux à bornes, Currency, ParamArray sont reconstruits comme des types, pas comme des octets

2. Le P-code, intégré au même produit

Un binaire VB6 est natif ou P-code, jamais les deux — et jusqu'ici cela voulait dire deux chemins, deux qualités. V7 décompile le P-code de bout en bout : octets → opcodes typés → machine à pile → arbre d'expressions → graphe de flot → structuration → source VB6.

C'est le même étage de structuration qui sert les deux natures. Un Do While … Loop reconstruit depuis du P-code et le même depuis du natif passent par le même code — donc par les mêmes corrections.

3. Les noms

C'est ce qui sépare un décompilateur utilisable d'un vidage d'assembleur. V7 restitue :

  • les membres de Me, les publics, les arguments, les variables Static
  • les appels au runtime MSVBVM60 rendus en idiomes VB (Left(s, 3), pas __vbaStrLeft) — 635 ordinaux répertoriés
  • les appels virtuels (VCall), y compris vers les intrinsèques de VB6.OLB
  • New → le nom de la classe instanciée
  • l'héritage de formulaire (Form → _Form) et les accesseurs de contrôle
  • les bornes et le type d'élément des tableaux, lus des descripteurs de procédure et des IID

Et surtout, V7 dit toujours ce qu'il ne sait pas. Un nom lu du binaire est un fait ; un proc_405630 est un emplacement sans nom. L'inventaire des symboles les compte séparément — sur SETUP1.EXE : 147 noms lus pour 1 182 emplacements synthétisés. Vous savez donc, à chaque ligne, sur quoi vous pouvez vous appuyer.

4. Les types

Un modèle de types complet, avec un treillis, propagé à travers le corps, la signature et les conditions. Les propriétés sont typées par alignement entre Property Get et Property Let. Le type de retour d'un membre de TypeLib est lu de la TypeLib — jamais deviné d'après son nom.

5. Ce que le binaire ne contient pas est écrit

Reference=, les neuf options de compilation, StartMode= : ces informations ne sont dans aucune structure du format VB6. L'ancien produit les déduisait — parfois bien, parfois pas. V7 laisse à leur place une note motivée qui dit pourquoi la valeur manque.

C'est moins joli. C'est vrai.

6. Les tables de référence

Dix ans de rétro-ingénierie de MSVBVM60.DLL et de VB6.EXE, figés dans le produit — aucune n'est dérivée d'un travail tiers :

TableEntrées
Opcodes de la machine P-code1 536
Propriétés de contrôle (31 types)1 212
Constantes intrinsèques VB6711
Exports du runtime MSVBVM60635
Membres de contrôle602
Événements de contrôle46

Elles ne sont ni lues d'un CSV au démarrage, ni téléchargées : elles sont compilées dans l'assembly, indexées, et interrogées en temps constant.

Les outils

Graphe d'appelstrois échelles (document, objet, procédure), filtres appelants / appelés, masquage des nœuds isolés, navigation par descente
Flot de contrôleblocs, arêtes, en-têtes de boucle, arêtes arrière, blocs inatteignables en pointillé — et cinq représentations du contenu : forme, IR, VB6, assembleur, P-code
Explorateur d'objets et de TypeLibrépond à « où est défini ceci ? » quand la réponse est hors du binaire : membres d'OCX tiers, constantes de VBRUN, signatures reconstruites, bibliothèque nommée
Navigateur d'API Win32prototypes, alias, notes — pour compléter ce qu'un Declare a perdu
Inventaire des symbolesnoms lus vs synthétisés, filtrage, renommage global (les sites d'appel des autres modules suivent)
Concepteurla section GUI de chaque formulaire, 1 212 définitions de propriétés de contrôle, 31 types
Vue hexadécimaleavec retour « octets → code »
Ressourcesinventaire, extraction
Correctifs binairesécriture dans l'exécutable analysé
Reconstruction de projet.vbp, .frm, .bas, .cls avec les en-têtes que VB6 exige pour rouvrir
Signets, recherche globale, chercheur de programmes et de bibliothèques

Le banc de mesure

V7 est confronté en permanence à trois jeux de vérité-terrain : un corpus de 148 binaires compilés par nos soins avec leurs 377 fichiers source d'origine, le Setup Toolkit de VB6 (dont Microsoft publie les sources), et un binaire témoin dont nous possédons le code.

Un défaut qui n'est pas confronté à sa source n'est pas un défaut : c'est une hypothèse.

3 849 épreuves automatisées tournent à chaque modification.

Et par-dessus, le seul critère qui décide vraiment si un export sert à quelque chose : le projet reconstruit se recompile-t-il ? Les 149 projets du banc sont réexportés puis passés à VB6.EXE /make. Au 5 septembre 2026 : 119 se recompilent tels quels, soit 80 %.

SETUP1.EXE n'en fait pas partie — il s'arrête sur un Argument not optional à la ligne 119 de frmSetup1.frm. C'est notre témoin le plus public ; le taire n'aurait tenu qu'un après-midi.

Legacy contre V7, sur les mêmes binaires

Les chiffres ci-dessous sont relevés, pas estimés : les deux produits ont tourné sur les mêmes fichiers, et leurs sorties ont été confrontées à la source VB6 d'origine. La colonne « legacy » est celle de VBReFormer 6.4 — la dernière version qui traite les deux témoins de bout en bout.

SETUP1.EXE — 286 Ko, natif, 16 composants, 238 procédures dans la source :

VBReFormer legacyVBReFormer V7
Procédures écrites dans l'export136227
Corps vide alors que la source ne l'est pas10
Lignes de code, tous fichiers7 4648 119
Ouvrir le binaire (format + localisation)—0,05 s
Décompiler les 227 corps—0,64 s (2,8 ms par corps)
De l'octet au projet complet—0,95 s

Un binaire de 9,35 Mo — 165 composants, 1 718 procédures dans la source :

VBReFormer legacyVBReFormer V7
Ouverture → projet écrit≈ 88 s12 s
Procédures écrites dans l'export1 7991 976
Corps vide alors que la source ne l'est pas2290
Procédures dont la structuration aboutit—1 976 / 1 976
Marqueurs d'erreur dans le code rendu1 1290
Signatures rendues As Unknow75 0140

Et le test qui ne se résume pas à un compteur : 24 procédures tirées au sort et lues ligne à ligne contre leur source d'origine. La V7 est plus fidèle dans 22 cas, le legacy dans 2.

Les deux endroits où le legacy gagne encore

Un comparatif qui ne perd nulle part est un comparatif qu'on n'a pas fait. Les deux nôtres :

  • Les blocs isolés. Quand une procédure contient des blocs qu'aucune arête ne relie à l'entrée — cibles de On Error GoTo, GoSub, Resume — la V7 les voit, les sert au graphe de flot, et ne les écrit pas dans le source. Sur le témoin : 1 541 blocs perdus, sur 232 procédures (12 %). Le legacy, lui, n'abandonne rien : son émission linéaire écrit tout, mal structuré mais présent. C'est notre défaut ouvert le plus large

Et le legacy porte encore six fonctions sans équivalent V7 sur le bureau — recherche de texte dans le projet, recherche des bibliothèques importées, recherche de programmes VB sur le disque, vue des ressources, export de l'image d'un formulaire, écran d'options.

Aucun des chiffres de cette section n'est une estimation. Le protocole, les scripts et les 24 procédures lues une à une sont publiés avec le produit.

Ce que V7 refuse de faire

Une liste courte, et elle est délibérée.

  • Pas de With reconstruit. Le compilateur le dissout ; le remettre serait inventer une structure que le binaire ne porte pas. La sortie est pleinement qualifiée (Frame1.Caption)
  • Pas de valeur plausible. Quand une valeur ne peut pas être rendue juste, V7 écrit ?. Un nombre crédible et faux coûte plus cher qu'un marqueur visible
  • Pas de nom inventé pour ce qui n'en a pas. proc_405630 dit la vérité ; un nom joli ne la dirait pas

Disponibilité

VBReFormer Online est en bêta dès aujourd'hui — vb.decompiler.tools — et son socle gratuit va loin : désassemblage complet, P-code complet, structure, ressources, concepteur, .vbp reconstruit, et la source en aperçu réel.

VBReFormer V7 (bureau) suit dans les prochaines semaines. Une licence desktop+cloud ouvre les deux.