Versione 11.8.0.0
Babel Obfuscator
Miglioramenti
- Host con FIPS abilitato — cifratura AES gestita: Aggiunto un decryptor AES gestito, opzionale, selezionabile con
--use encryption=aesmanaged(oppure<Use>encryption=aesmanaged</Use>da MSBuild). Gli assembly protetti con cifratura del codice (MSIL), delle stringhe, dei valori/array o delle risorse ora si avviano anche su host in cui il provider crittografico di piattaforma è inutilizzabile — tipicamente i container Linux con uno stato FIPS di OpenSSL compromesso, dove il runtime di decifratura iniettato lanciava unaOpenSslCryptographicExceptiondentro l'inizializzatore di tipo prima ancora che venisse eseguito codice utente. L'offuscatore continua a cifrare con il provider di piattaforma sulla macchina di build (funzionante) e produce lo stesso testo cifrato; cambia soltanto il decryptor autonomo trasportato nell'assembly. Supportato su .NET Framework e .NET (Core); netstandard e Mono mantengono il comportamento attuale. Vedi la pagina di documentazione FIPS Compliance. Attenzione al throughput del decryptor gestito, circa 40 MB/s: evita di combinarlo con la cifratura codicecache=falsesu metodi in percorsi critici. - Prestazioni — assembly di grandi dimensioni: Riscritti tre percorsi critici che dominavano l'offuscamento di assembly molto grandi, ricchi di codice e attributi, con output verificato byte per byte identico alla 11.7.0:
- La ridenominazione degli attributi personalizzati (
RenameTypeAttributes) è ora indicizzata invece di essere O(tipi × attributi). Un assembly ricco di attributi da 41 MB e circa 69.000 tipi (ad esempio Microsoft.Graph) che prima non completava la fase di ridenominazione ora la conclude in circa 20 s. FindCallVerticessul grafo delle chiamate è O(vertici) invece di O(vertici × firme) — da 7 a 11 volte più veloce su DevExpress.XtraEditors / Spire.Pdf.- Il raggruppamento dei membri virtuali nella fase di ridenominazione è suddiviso in bucket per nome (da 2074 ms a 17 ms su DevExpress.XtraEditors). Nel complesso, l'offuscamento con tutte le funzionalità attive di un assembly DevExpress da 7,9 MB è più rapido del 24% circa.
- La ridenominazione degli attributi personalizzati (
- Rilevamento dinamico del runtime di destinazione: Aggiunto il rilevamento dinamico della versione del runtime di destinazione per gli assembly offuscati.
- Esempio di binding a dongle hardware: Aggiunta un'implementazione di riferimento multipiattaforma ed eseguibile che mostra come legare un'applicazione .NET protetta con cifratura codice a un dongle hardware di licenza (KEYLOK, SafeNet Sentinel, Wibu CodeMeter, Marx CrypToken, …), in modo che una DLL del dongle sostituita o simulata non possa aggirare la protezione.
- [Novità] L'avviso OB0009 segnala un caso di modalità demo che dall'output era impossibile diagnosticare: quando vengono forniti file di mappa ma l'offuscamento cross assembly non è coperto da licenza, la mappa viene ignorata e i riferimenti ai simboli esterni rinominati mantengono i nomi originali, per cui l'assembly falliva solo a runtime con una
TypeLoadException. Ora la situazione viene segnalata al momento della build.
Correzioni di bug
- Avalonia — cifratura risorse: Risolto il crash all'avvio delle applicazioni Avalonia offuscate, con
FileNotFoundExceptionsu assetavares://e XAML quando la cifratura risorse era attiva. Avalonia conserva tutto lo XAML e tutti gli asset di un assembly in un unico blob!AvaloniaResourcesche il suo asset loader legge direttamente, aggirando l'hook di decifratura iniettato da Babel. Quel blob ora viene lasciato non cifrato (tutte le altre risorse restano cifrate), così le applicazioni Avalonia sono pienamente offuscabili con la cifratura risorse attiva. WPF non è interessato. Per distribuire un'applicazione Avalonia a file singolo, usa l'incorporamento degli assembly (non l'unione). - WPF — unione dei dizionari dei temi: Risolta la perdita dei temi dei controlli quando si uniscono assembly che contengono entrambi un dizionario di risorse BAML allo stesso percorso (tipicamente
themes/generic.baml). Gli streamResourceDictionarya cultura neutra in conflitto vengono ora conservati con nomi univoci e collegati attraverso un dizionario sintetizzato tramiteMergedDictionaries, mantenendo la precedenza di risoluzione dell'assembly principale. - MAUI/XAML — primitive del linguaggio
x:: Risolto il comportamento del renamer XAML che rimuoveva il prefissox:dalle primitive del linguaggio inx:TypeArguments(ad esempiox:Double→Double). Questo faceva crashare le build Release di .NET MAUI per iOS che caricano lo XAML a runtime, conXamlParseException ("Type Double not found"). - Ridenominazione — riferimenti a tipi autoreferenziali: Risolto il caso di un tipo rinominato che lasciava
TypeReferenceautoreferenziali (con scope sul proprio modulo) con il vecchio nome, causandoSystem.TypeLoadExceptionall'inizializzazione del tipo. I weaver IL come ArxOne.MrAdvice — e le istruzioni di primo livello in C# tramite il tipo internoProgram— emettono aliasldtokenche poi non si risolvevano. La correzione dei TypeRef sul modulo stesso viene ora eseguita per ogni tipo rinominato. - Ridenominazione — riscrittura delle stringhe PropertyChanged: Risolto il comportamento della riscrittura di
ldstrsuccessiva alla ridenominazione (quella che mantiene funzionanteOnPropertyChanged("PropName")dopo la ridenominazione), che riscriveva erroneamente argomenti di API basate su stringhe del tutto estranei — ricerche di controlli XAML, chiavi di dizionario, registri personalizzati — su qualsiasi tipo derivato da una classe baseINotifyPropertyChanged. La riscrittura è ora limitata ai sink PropertyChanged riconosciuti. Segnalato sulla 8.7, riprodotto sulla 11.7. - Flusso di controllo — tipi host con dipendenze esterne: Risolta la
FileNotFoundExceptiona runtime, intermittente e casuale (ad esempio l'errore SSIS0xC0011008), causata dal fatto che i metodi di dispatch del flusso di controllo e quelli di supporto all'appiattimento degli switch venivano ospitati in tipi che al caricamento tiravano dentro un assembly esterno. La selezione del tipo host ora scarta i tipi con campi di tipo valore (verificati ricorsivamente, inclusi argomenti generici e tipi valore annidati) o con tipi base/interfacce esterni al modulo o alla libreria di base, e scarta i tipi host generici. - Licensing — una licenza non valida ricadeva silenziosamente in modalità demo: Risolto il caso di un file di licenza fornito esplicitamente ma non valido per la versione in esecuzione, che non veniva né onorato né segnalato: l'esecuzione proseguiva silenziosamente in modalità demo, producendo un assembly a tempo e privo delle funzionalità coperte da licenza, cosa che l'utente scopriva di solito molto più tardi. Una licenza fornita esplicitamente deve ora essere valida per questo prodotto e per questa versione, altrimenti Babel si ferma con
Error: the license provided is not valid for Babel Obfuscator <version>.ed esce conLicensingFailure(1, oppure40con--strict-exit) senza produrre alcun assembly. L'esecuzione senza alcuna licenza avvia ancora la modalità demo con l'insieme ridotto di funzionalità, come prima. - Licenze di prova su Linux: Le licenze che portano una restrizione di prova basata sul tempo di esecuzione o sul numero di istanze potevano non superare la validazione su host Linux, incluso il task NuGet di Babel Obfuscator nei container Linux. Per i dettagli vedi le note di rilascio di Babel Licensing 11.8.0.0.
Modifiche
- Toolchain di auto-offuscamento: Il pacchetto NuGet di Babel Obfuscator (e i binari babel/lic/HardwareId/Babel.Win) sono ora auto-offuscati con l'algoritmo AES gestito, così gli strumenti distribuiti si avviano anche su host con FIPS compromesso.
Babel Licensing
Miglioramenti
- Host con FIPS abilitato — resilienza all'avvio: Babel Licensing ora funziona anche su host con FIPS abilitato il cui container non dispone di un provider OpenSSL FIPS certificato (per esempio un host RHEL che esegue un container .NET basato su Ubuntu, dotnet/dotnet-docker#5849), dove la validazione della licenza prima si interrompeva con
BabelLicenseException: Internal error— l'hashing dell'identità diIsolatedStoragein .NET che falliva inSHA1.Createconerror:03000086. L'archivio delle licenze ora ricade su un archivio su file gestito quando IsolatedStorage non riesce a inizializzarsi, sostituisce i cifrari AES/DES di piattaforma nell'archivio cifrato delle date con cifrari BouncyCastle compatibili bit a bit (i file di archivio esistenti restano leggibili in entrambe le direzioni) e degrada al tracciamento delle date in memoria quando nessun archivio è utilizzabile — così la validazione della licenza non tocca più lo stack crittografico del sistema operativo. Quando il Servizio Babel Licensing è offuscato con l'algoritmo AES gestito di Babel Obfuscator (--use encryption=aesmanaged), anche il servizio offuscato si avvia su host con FIPS compromesso. - Licenze di attivazione — propagazione delle funzionalità in fase di validazione: Aggiungere una funzionalità a una licenza di attivazione ora raggiunge i client già attivati alla validazione successiva, invece di richiedere una disattivazione e riattivazione completa. Sia il percorso di attivazione sia quello di validazione costruiscono e rifirmano la licenza node-locked per macchina a partire dalla licenza padre (funzionalità, campi, restrizioni, date) più il binding hardware, attraverso un helper condiviso.
Correzioni di bug
- Autenticazione gRPC con UserKey: Risolto il fallimento di tutti i login gRPC con UserKey dopo l'irrobustimento di sicurezza della 11.7.0.
GrpcAuthenticator.AuthenticateAsyncignorava il parametro username e inviava sempre l'id client catturato dal costruttore, instradando i login UserKey sul percorso di login per identità a due argomenti. Un ponte opzionaleEnableLegacyUserKeyFallback(disattivato per impostazione predefinita) consente agli operatori con molte applicazioni client già distribuite di ripristinare la compatibilità senza ridistribuirle, mentre le nuove installazioni restano sul percorso corretto. - Chiavi JSON dei payload dei webhook: Risolto il problema per cui i payload webhook di licenze, ordini e report consegnavano chiavi JSON di una sola lettera (
p,q,r, …) quando il Servizio di licensing è offuscato con la ridenominazione dei simboli. I payload usano ora DTO dedicati che fissano ogni chiave con[JsonPropertyName](camelCase), così il contratto dei webhook è immune alla ridenominazione dei simboli e alla cifratura stringhe. - Licenze di prova — host Linux senza regione di memoria condivisa: Risolto il caso di una licenza con restrizione di prova basata sul tempo di esecuzione o sul numero di istanze che falliva la validazione con
Object reference not set to an instance of an object, per cuiIsValidrestituivafalsementre la stessa licenza veniva validata correttamente su Windows e macOS. Segnalato su container Linux.Application.StartTimeeApplication.InstanceCountleggevano la regione di memoria condivisa incondizionatamente, ma la regione viene popolata solo quando può essere aperta, quindi dove non poteva essere creata entrambi i membri lanciavano un'eccezione eTrialRestriction.Validatefalliva con un errore opaco. La regione è ora trattata come opzionale e i due valori degradano a valori per processo — l'orario di avvio del processo e il conteggio dei processi già previsto come fallback — invece di lanciare eccezioni. Un orario di creazione azzerato viene trattato allo stesso modo, perché altrimenti farebbe sembrare già esaurito il tempo di ogni esecuzione di prova. Non è una regressione: il comportamento era identico nelle versioni 11.6.0, 11.7.0, 11.7.0.3 e 11.8.0. - Linux — binding alla libreria dei semafori POSIX: Risolta la causa a monte del problema precedente: la regione di memoria condivisa non poteva mai essere aperta su un host Linux con glibc. I punti di ingresso
sem_*che la proteggono venivano importati dalibrt, un nome che il runtime .NET cerca comelibrt.soeliblibrt.soma mai come il soname installatolibrt.so.1— il collegamento simbolico senza versione fa parte del pacchetto di sviluppo, che le immagini dei container non includono — quindi ogni chiamata falliva il binding con unaDllNotFoundException. Oltre a rompere le restrizioni di prova, questo degradava silenziosamenteApplication.StartTimeeApplication.InstanceCounta valori per processo su tutti gli host Linux. L'importazione usa ora il soname e unDllImportResolverprova inoltrelibpthread.so.0,libc.so.6e i nomi della libc musl, coprendo glibc prima e dopo l'unificazione dellesem_*in libc avvenuta con la 2.34, oltre a musl. Il conteggio delle istanze tra processi e l'orario di avvio condiviso dell'applicazione si comportano ora su Linux come hanno sempre fatto su Windows. Gli host Alpine/musl non erano interessati. AncheSharedMemory.Openora segnala una regione non disponibile invece di lanciare un'eccezione al chiamante, così gli host privi di semafori con nome continuano a funzionare grazie al fallback per processo. - Servizio Babel Licensing — chiave di firma JWT generata automaticamente: Risolto il fallimento con
401di ogni chiamata effettuata con un token emesso — e quindi l'impossibilità di attivare qualsiasi licenza — quandoApplication:SigningKeyveniva lasciata vuota. La chiave generata casualmente all'avvio veniva assegnata solo a una copia scollegata della sezione di configurazioneApplication, mentreTokenServicerisolveIOptionsSnapshot<ApplicationSettings>e rilegge dalla configurazione, quindi i token venivano firmati con una chiave fatta di spazi di riempimento e validati con quella generata. Il log del servizio rendeva difficile diagnosticare il problema, perché riportava un'autenticazione riuscita subito prima del401. La chiave generata viene ora applicata tramitePostConfigure<ApplicationSettings>, così ogni istanza delle opzioni firma e valida con la stessa chiave. Configurare una chiave esplicita resta l'impostazione consigliata in produzione: una chiave generata cambia a ogni riavvio e non è condivisa tra le istanze.

