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.

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.

Legacy vs V7

Les mesures de temps ont été prises sur la même machine, sur les mêmes binaires.

VBReFormer legacyVBReFormer V7
Décompilation nativereconnaissance de motifsinterprétation abstraite (registres + mémoire + FPU)
Décompilation P-codepartielle, chemin séparécomplète, même étage de structuration que le natif
Profils d'optimisation couverts1 (Fast Code)4, mesurés séparément
Graphe d'appels du document entierabsentimmédiat, sans décompiler
Noms de runtime résolusnon mesuré635 ordinaux
Projets exportés qui recompilent dans VB6non mesuré27 / 108
Épreuves automatiséesnon mesuré3 849
Langues de l'interface111

Les cellules « non mesuré » le sont volontairement : nous ne disposons pas de relevé fiable pour l'ancien moteur sur ces trois points, et un ordre de grandeur présenté comme une mesure serait exactement ce que cet article reproche à un décompilateur.

Un chiffre mérite d'être isolé, parce qu'il mesure V7 contre lui-même : sur le corpus de binaires malmenés à dessein, les emplacements où le moteur écrivait ? faute de pouvoir conclure sont passés de 63 à 20. Ce ne sont pas des erreurs corrigées — c'étaient déjà des aveux honnêtes. Ce sont des aveux devenus inutiles.

Et la ligne qui compte le plus reste la recompilation. 27 projets sur 108 se rouvrent et se recompilent tels quels dans l'IDE. Ce n'est pas un chiffre flatteur, et c'est exactement pour cela que nous le publions : c'est le seul critère qui mesure ce que le client veut vraiment.

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