NOTES DE VERSION

Les nouveautés de Babel.

Modifications apportées au moteur, aux outils de gestion des licences et à l’espace de travail Desktop, extraites des notes de version du produit.

Publié le 2 août 2026

Version 11.8.0.0

Babel Obfuscator

Améliorations

  • Hôtes avec FIPS activé — chiffrement AES managé : Ajout d'un déchiffreur AES managé optionnel, sélectionné avec --use encryption=aesmanaged (ou <Use>encryption=aesmanaged</Use> depuis MSBuild). Les assemblies protégés par le chiffrement du code (MSIL), des chaînes, des valeurs/tableaux ou des ressources démarrent désormais sur les hôtes dont le fournisseur cryptographique de la plateforme est inutilisable — en premier lieu les conteneurs Linux dans un état FIPS OpenSSL cassé, où le runtime de déchiffrement injecté levait auparavant une OpenSslCryptographicException à l'intérieur de l'initialiseur de type, avant l'exécution du moindre code utilisateur. L'obfuscateur chiffre toujours avec le fournisseur de la plateforme sur la machine de compilation (saine) et émet le même texte chiffré ; seul le déchiffreur autonome embarqué dans l'assembly change. Pris en charge sur .NET Framework et .NET (Core) ; netstandard et Mono conservent leur comportement actuel. Voir la page de documentation FIPS Compliance. Attention au débit du déchiffreur managé, d'environ 40 Mo/s : évitez de le combiner avec un chiffrement du code en cache=false sur des méthodes du chemin critique.
  • Performances — assemblies volumineux : Réécriture de trois chemins critiques qui dominaient l'obfuscation d'assemblies très volumineux, riches en code et en attributs, avec une sortie vérifiée comme identique octet pour octet à celle de 11.7.0 :
    • Le renommage des attributs personnalisés (RenameTypeAttributes) est désormais indexé au lieu d'être en O(types × attributs). Un assembly riche en attributs de 41 Mo et d'environ 69 000 types (par exemple Microsoft.Graph), dont la phase de renommage n'aboutissait pas auparavant, se termine désormais en 20 s environ.
    • FindCallVertices sur le graphe d'appels est en O(sommets) au lieu de O(sommets × signatures) — 7 à 11 fois plus rapide sur DevExpress.XtraEditors / Spire.Pdf.
    • Le regroupement des membres virtuels dans la phase de renommage est réparti par nom en compartiments (2074 ms → 17 ms sur DevExpress.XtraEditors). De bout en bout, cela réduit d'environ 24 % l'obfuscation complète d'un assembly DevExpress de 7,9 Mo.
  • Détection dynamique du runtime cible : Ajout de la détection dynamique de la version du runtime cible pour les assemblies obfusqués.
  • Exemple de liaison à une clé matérielle : Ajout d'une implémentation de référence multiplateforme exécutable, montrant comment lier une application .NET protégée par le chiffrement du code à une clé de licence matérielle (KEYLOK, SafeNet Sentinel, Wibu CodeMeter, Marx CrypToken, …) de sorte qu'une DLL de clé remplacée ou simulée ne puisse pas contourner la protection.
  • [Nouveau] L'avertissement OB0009 signale un cas de mode démo jusqu'ici impossible à diagnostiquer à partir de la sortie : lorsque des fichiers de mappage sont fournis mais que l'obfuscation inter-assemblies n'est pas sous licence, le mappage est ignoré et les références aux symboles externes renommés conservent leur nom d'origine, si bien que l'assembly n'échouait qu'à l'exécution avec une TypeLoadException. Le cas est désormais signalé lors de la compilation.

Corrections de bugs

  • Avalonia — chiffrement des ressources : Correction du plantage au démarrage des applications Avalonia obfusquées, avec FileNotFoundException sur les actifs avares:// et le XAML, lorsque le chiffrement des ressources était activé. Avalonia stocke la totalité du XAML et des actifs d'un assembly dans un unique blob !AvaloniaResources que son chargeur d'actifs lit directement, en contournant le point d'accroche de déchiffrement injecté par Babel. Ce blob est désormais laissé non chiffré (toutes les autres ressources restent chiffrées), si bien que les applications Avalonia sont pleinement obfuscables avec le chiffrement des ressources activé. WPF n'est pas concerné. Pour livrer une application Avalonia en fichier unique, utilisez l'intégration d'assemblies (et non la fusion).
  • WPF — fusion des dictionnaires de thèmes : Correction de la perte des thèmes de contrôles lors de la fusion d'assemblies contenant tous deux un dictionnaire de ressources BAML au même chemin (généralement themes/generic.baml). Les flux ResourceDictionary de culture neutre qui entrent en collision sont désormais conservés sous des noms uniques et reliés par un dictionnaire synthétisé via MergedDictionaries, ce qui préserve la priorité de résolution de l'assembly principal.
  • MAUI/XAML — primitives de langage x: : Correction du renommeur XAML qui supprimait le préfixe x: des primitives de langage dans x:TypeArguments (par exemple x:Double → Double). Cela faisait planter les versions Release .NET MAUI iOS qui chargent le XAML à l'exécution, avec XamlParseException ("Type Double not found").
  • Renommage — références de type auto-référentes : Correction d'un type renommé qui laissait ses TypeReference auto-référentes (portée du module lui-même) sous l'ancien nom, provoquant une System.TypeLoadException à l'initialisation du type. Des tisseurs d'IL comme ArxOne.MrAdvice — ainsi que les instructions de niveau supérieur C# via le type interne Program — émettent des alias ldtoken qui ne se résolvaient alors plus. La correction des TypeRef du module lui-même s'applique désormais à chaque type renommé.
  • Renommage — réécriture des chaînes PropertyChanged : Correction de la réécriture ldstr post-renommage (qui permet à OnPropertyChanged("PropName") de continuer à fonctionner après le renommage) qui réécrivait à tort des arguments d'API sans rapport indexés par chaîne — recherches de contrôles XAML, clés de dictionnaire, registres personnalisés — sur tout type dérivant d'une base INotifyPropertyChanged. La réécriture est désormais limitée aux consommateurs PropertyChanged reconnus. Signalé sur la 8.7, reproduit sur la 11.7.
  • Flux de contrôle — types hôtes à dépendance externe : Correction de FileNotFoundException intermittentes et aléatoires à l'exécution (par exemple SSIS 0xC0011008), causées par des méthodes d'aiguillage du flux de contrôle et d'aplatissement des switch hébergées dans des types qui entraînent le chargement d'un assembly externe. Le choix du type hôte rejette désormais les types comportant des champs de type valeur (vérifiés récursivement, y compris les arguments génériques et les types valeur imbriqués) ou dont le type de base ou les interfaces sont hors du module ou de la bibliothèque de base, et rejette les types hôtes génériques.
  • Licences — une licence invalide retombait silencieusement en mode démo : Correction du cas d'un fichier de licence fourni explicitement mais non valide pour la version en cours, qui n'était ni honoré ni signalé : l'exécution se poursuivait silencieusement en mode démo, produisant un assembly à durée limitée dépourvu des fonctionnalités sous licence, ce que l'utilisateur découvrait généralement bien plus tard. Une licence fournie explicitement doit désormais être valide pour ce produit et cette version ; sinon Babel s'arrête avec Error: the license provided is not valid for Babel Obfuscator <version>. et sort avec LicensingFailure (1, ou 40 sous --strict-exit) sans produire d'assembly. Une exécution sans aucune licence démarre toujours le mode démo avec son jeu de fonctionnalités réduit, comme auparavant.
  • Licences d'essai sous Linux : Les licences portant une restriction d'essai sur la durée d'exécution ou le nombre d'instances pouvaient échouer à la validation sur les hôtes Linux, y compris pour la tâche NuGet Babel Obfuscator dans des conteneurs Linux. Voir les notes de version de Babel Licensing 11.8.0.0 pour le détail.

Modifications

  • Chaîne d'outils auto-obfusquée : Le paquet NuGet Babel Obfuscator (ainsi que les binaires babel/lic/HardwareId/Babel.Win) sont désormais auto-obfusqués avec l'algorithme AES managé, de sorte que les outils distribués démarrent eux-mêmes sur des hôtes au FIPS cassé.

Babel Licensing

Améliorations

  • Hôtes avec FIPS activé — résilience au démarrage : Babel Licensing survit désormais aux hôtes avec FIPS activé dont le conteneur ne dispose pas d'un fournisseur OpenSSL FIPS certifié (par exemple un hôte RHEL exécutant un conteneur .NET basé sur Ubuntu, dotnet/dotnet-docker#5849), où la validation de licence plantait auparavant avec BabelLicenseException: Internal error — le hachage d'identité d'IsolatedStorage .NET échouant dans SHA1.Create avec error:03000086. Le magasin de licences se replie désormais sur un magasin de fichiers managé lorsque IsolatedStorage ne peut pas s'initialiser, remplace les chiffrements AES/DES de la plateforme dans le magasin de dates chiffré par des chiffrements BouncyCastle compatibles bit à bit (les fichiers de magasin existants restent lisibles dans les deux sens), et se rabat sur un suivi des dates en mémoire lorsqu'aucun stockage n'est utilisable — la validation de licence ne touche donc plus la pile cryptographique du système. Lorsque le service Babel Licensing est obfusqué avec l'algorithme AES managé de Babel Obfuscator (--use encryption=aesmanaged), le service obfusqué démarre lui aussi sur des hôtes au FIPS cassé.
  • Licences d'activation — propagation des fonctionnalités à la validation : L'ajout d'une fonctionnalité à une licence d'activation atteint désormais les clients déjà activés lors de la validation suivante, au lieu d'exiger une désactivation complète suivie d'une réactivation. Les chemins d'activation et de validation construisent et resignent tous deux la licence verrouillée à la machine, à partir de la licence parente (fonctionnalités, champs, restrictions, dates) et de la liaison matérielle, au moyen d'un assistant commun.

Corrections de bugs

  • Authentification gRPC par UserKey : Correction de l'échec de toutes les connexions gRPC par UserKey depuis le durcissement de sécurité de la 11.7.0. GrpcAuthenticator.AuthenticateAsync ignorait son paramètre de nom d'utilisateur et envoyait toujours l'identifiant client capturé par le constructeur, ce qui dirigeait les connexions UserKey vers le chemin de connexion d'identité à deux arguments. Une passerelle optionnelle EnableLegacyUserKeyFallback (désactivée par défaut) permet aux exploitants comptant de nombreuses applications clientes déjà déployées de rétablir la compatibilité sans redéployer, tandis que les nouvelles installations restent sur le chemin corrigé.
  • Clés JSON des charges utiles de webhook : Correction des charges utiles de webhook de licence, de commande et de rapport qui livraient des clés JSON d'une seule lettre (p, q, r, …) lorsque le service de licences est obfusqué avec le renommage des symboles. Les charges utiles utilisent désormais des DTO nommés qui fixent chaque clé via [JsonPropertyName] (camelCase) : le contrat de webhook est donc insensible au renommage des symboles et au chiffrement des chaînes.
  • Licences d'essai — hôtes Linux sans région de mémoire partagée : Correction d'une licence portant une restriction d'essai sur la durée d'exécution ou le nombre d'instances qui échouait à la validation avec Object reference not set to an instance of an object, si bien qu'IsValid renvoyait false alors que la même licence se validait correctement sous Windows et macOS. Signalé sur des conteneurs Linux. Application.StartTime et Application.InstanceCount lisaient la région de mémoire partagée sans condition, alors que celle-ci n'est renseignée que lorsqu'elle peut être ouverte : là où elle ne pouvait pas être créée, les deux membres levaient une exception et TrialRestriction.Validate échouait avec une erreur opaque. La région est désormais traitée comme facultative et les deux valeurs se replient sur des valeurs propres au processus — l'heure de démarrage du processus et le repli existant sur le comptage des processus — au lieu de lever une exception. Une date de création à zéro est traitée de la même manière, car elle ferait sinon paraître écoulée toute durée d'essai. Il ne s'agit pas d'une régression : le comportement était identique en 11.6.0, 11.7.0, 11.7.0.3 et 11.8.0.
  • Linux — liaison de la bibliothèque de sémaphores POSIX : Correction de la cause profonde de l'échec ci-dessus : la région de mémoire partagée ne pouvait jamais être ouverte sur un hôte Linux glibc. Les points d'entrée sem_* qui la protègent étaient importés depuis librt, un nom que le runtime .NET recherche sous les formes librt.so et liblibrt.so mais jamais sous le soname installé librt.so.1 — le lien symbolique sans version est livré avec le paquet de développement, que les images de conteneur n'embarquent pas — si bien que chaque appel échouait à se lier avec une DllNotFoundException. Au-delà de la rupture des restrictions d'essai, cela dégradait silencieusement Application.StartTime et Application.InstanceCount en valeurs propres au processus sur tous les hôtes Linux. L'importation utilise désormais le soname, et un DllImportResolver essaie en outre libpthread.so.0, libc.so.6 et les noms de la libc musl, ce qui couvre glibc avant et après la fusion des sem_* dans la libc en 2.34, ainsi que musl. Le comptage d'instances entre processus et l'heure de démarrage partagée de l'application se comportent désormais sous Linux comme ils l'ont toujours fait sous Windows. Les hôtes Alpine/musl n'étaient pas concernés. SharedMemory.Open signale également une région indisponible au lieu de lever une exception chez l'appelant, de sorte que les hôtes dépourvus de sémaphores nommés continuent de fonctionner grâce au repli par processus.
  • Service Babel Licensing — clé de signature JWT générée automatiquement : Correction de l'échec en 401 de tout appel effectué avec un jeton émis — et donc de l'impossibilité d'activer une licence — lorsque Application:SigningKey était laissé vide. La clé générée aléatoirement au démarrage n'était affectée qu'à une copie détachée de la section de configuration Application, tandis que TokenService résout IOptionsSnapshot<ApplicationSettings> et relie depuis la configuration : les jetons étaient donc signés avec une clé faite d'espaces de remplissage et validés avec la clé générée. Le journal du service rendait ce cas difficile à diagnostiquer, en signalant une authentification réussie juste avant le 401. La clé générée est désormais appliquée via PostConfigure<ApplicationSettings>, de sorte que chaque instance d'options liée signe et valide avec la même clé. Configurer une clé explicite reste le réglage recommandé en production : une clé générée change à chaque redémarrage et n'est pas partagée entre les instances.