Cifratura del codice
La funzionalità di cifratura del codice di Babel Obfuscator ti permette di cifrare tutto il tuo codice per proteggerlo dal reverse engineering.
Babel Obfuscator trasforma le istruzioni IL originali del metodo in un nuovo insieme di istruzioni personalizzate, che può includere diverse tecniche di offuscamento e rende più difficile il reverse engineering o la modifica del codice. Una volta costruita, la nuova rappresentazione del codice viene cifrata con l’algoritmo di cifratura scelto (per esempio AES), per renderla ancora più difficile da comprendere o modificare.
In fase di esecuzione, quando l’assembly protetto viene caricato in memoria, la Babel Virtual Machine (BVM) decifra ed esegue il codice protetto. La BVM è un motore di esecuzione leggero incluso nell’assembly offuscato, che fornisce le funzioni necessarie per decifrare il codice, eseguirlo e garantirne il corretto funzionamento.
Distribuisci su host con FIPS abilitato? Poiché la cifratura del codice decifra i corpi dei metodi in fase di esecuzione tramite il provider crittografico della piattaforma, un container in esecuzione su un host con FIPS abilitato e privo di un provider FIPS di OpenSSL certificato può non riuscire ad avviarsi. Vedi Conformità FIPS per la causa e la soluzione.
La cifratura del codice offre una protezione forte contro il reverse engineering e il furto di proprietà intellettuale, ma comporta compromessi in termini di prestazioni e complessità dell’applicazione, quindi non è consigliabile applicarla a tutto il codice. È meglio applicare questa tecnica di offuscamento in modo selettivo alle parti più sensibili del codice, quelle che richiedono protezione, e usare altre tecniche di offuscamento per il resto. In questo modo trovi un equilibrio tra sicurezza e prestazioni.
Prima della cifratura del codice
Dopo la cifratura del codice
La cifratura del codice di Babel è una soluzione interamente gestita. Questo significa che i metodi cifrati non vengono sostituiti da codice nativo destinato a una piattaforma specifica. Questa soluzione basata su metodi gestiti non compromette la natura multipiattaforma di .NET Framework e permette al compilatore Just-In-Time (JIT) di ottimizzare il codice per la CPU di destinazione.
Limiti della cifratura del codice
La cifratura del codice di Babel non è supportata sugli assembly .NET MAUI e Blazor, per i seguenti motivi principali:
Vincoli della piattaforma
• Compilazione ahead-of-time (AOT): le piattaforme come iOS, centrali per .NET MAUI, si basano sulla compilazione AOT. Questo processo compila in anticipo il codice in binari nativi ed elimina la possibilità di generare o modificare dinamicamente il codice in fase di esecuzione, che è essenziale per la cifratura e la decifratura del codice.
Supporto limitato per il namespace System.Reflection.Emit
• Generazione dell’IL limitata: il namespace System.Reflection.Emit, usato per generare dinamicamente l’IL, ha un supporto limitato o assente su piattaforme importanti come iOS e WebAssembly (usato da Blazor). Poiché la cifratura del codice si basa spesso sulla manipolazione dinamica dell’IL, questa limitazione ostacola ulteriormente l’implementazione delle funzionalità di cifratura in MAUI e Blazor.
Restrizioni di sicurezza
• Ambienti sandbox: sia MAUI sia Blazor operano in ambienti in cui le app sono isolate in una sandbox per motivi di sicurezza. Piattaforme come iOS impongono misure di sicurezza rigide, che impediscono qualsiasi modifica del codice in fase di esecuzione per proteggere dall’esecuzione di codice dannoso, e rendono impraticabile la cifratura dinamica.
• Rischio di iniezione di codice: la generazione dinamica del codice necessaria per la cifratura e la decifratura comporta rischi di sicurezza significativi, tra cui possibili vulnerabilità di iniezione di codice. I framework MAUI e Blazor danno priorità alla sicurezza ed evitano questi rischi.
A causa di questi vincoli, .NET MAUI e Blazor non supportano la cifratura del codice e privilegiano pratiche di sviluppo sicure, portabili e coerenti tra le piattaforme.
Metodi che non possono essere cifrati
All’interno di un target supportato la cifratura del codice viene applicata metodo per metodo, e alcuni metodi vengono lasciati automaticamente non cifrati:
• I costruttori di istanza (.ctor) non vengono mai cifrati. È una scelta di progetto: un’istanza deve essere completamente inizializzata attraverso la catena dei costruttori di base prima di essere usata, e questa garanzia non può essere mantenuta se la cifratura del codice sposta il corpo del costruttore. Nota che questo vale solo per i costruttori di istanza: i costruttori statici (.cctor) non sono interessati e vengono cifrati come qualsiasi altro metodo.
• I metodi con una firma non supportata vengono saltati automaticamente. La cifratura del codice sposta il corpo del metodo nella Babel Virtual Machine (BVM) e lo richiama tramite un marshaller uniforme degli argomenti, quindi alcune forme di firma non possono essere espresse e vengono lasciate non cifrate:
- Metodi generici: segnalati come
EM0003. - Tipi restituiti non supportati: un valore restituito
ref(per riferimento), un puntatore, un puntatore a funzione oppure unref struct(tipo simile a un riferimento) comeSpan<T>/ReadOnlySpan<T>. Segnalati comeEM0001. - Parametri puntatore o puntatore a funzione: segnalati come
EM0002. - Parametri
ref struct(tipi simili a un riferimento) comeSpan<T>/ReadOnlySpan<T>: segnalati comeEM0013.
Questi limiti sono intrinseci al runtime .NET: un puntatore o un ref struct non può essere sottoposto a boxing, quindi il marshaller degli argomenti della BVM non può trasportarlo. Tutto il resto è supportato, compresi i parametri ref/out/in (di qualsiasi tipo di elemento, incluse strutture, enumerazioni e tipi riferimento passati per riferimento), i valori restituiti di tipo valore e di istanza generica, la gestione delle eccezioni, gli iteratori e i metodi async. Vedi l’appendice Avvisi ed errori per l’elenco completo dei codici EM.
I metodi esclusi per questi motivi vengono segnalati durante la build e non fanno fallire l’offuscamento: vengono semplicemente emessi non cifrati.
Considerazioni sulle prestazioni
Il corpo di un metodo cifrato viene comunque eseguito come codice compilato dal JIT, quindi il suo lavoro interno procede a una velocità vicina a quella nativa. Ciò che la cifratura del codice aggiunge è un piccolo costo di dispatch per ogni chiamata, sostenuto ogni volta che si entra in un metodo cifrato (gli argomenti vengono passati alla BVM tramite marshalling, e allo stesso modo il risultato al ritorno). Questo overhead è trascurabile per i metodi che svolgono un lavoro reale, ma può diventare preponderante per metodi molto piccoli chiamati in cicli estremamente intensi (milioni di chiamate). Per questo motivo, e per mantenere l’assembly piccolo e veloce, applica la cifratura del codice in modo selettivo ai metodi sensibili che richiedono protezione anziché a tutto il codice, ed evita di cifrare piccoli metodi di supporto chiamati molto spesso su un percorso critico.
Abilitare la cifratura del codice
Babel Obfuscator permette di applicare la cifratura del codice in modo selettivo a metodi specifici, anziché cifrare tutto il codice. In questo modo eviti i problemi di prestazioni che possono derivare dalla cifratura di grandi quantità di codice.
Per indicare quali metodi cifrare puoi usare una regola XML oppure l’attributo Obfuscation. Con una regola XML puoi specificare i nomi dei metodi da cifrare.
<Rule name="encrypt code" feature="msil encryption" exclude="false">
<Target>Methods</Target>
<Pattern>ACME.Algorithms::*</Pattern>
<Description>Encrypt all methods of Algorithm class.</Description>
</Rule>In alternativa puoi usare l’attributo Obfuscation per contrassegnare i singoli metodi da cifrare, impostando il parametro “Feature” su “msil encryption”.
[Obfuscation(Feature = "msil encryption", Exclude = false)]
public void ProcessData()
{
// Encrypted code
}Abilitando la cifratura del codice, i metodi selezionati vengono cifrati durante l’offuscamento.
Riga di comando
babel myapp.exe --msilencryptionAnziché usare regole XML o attributi, puoi passare all’opzione --msilencryption delle espressioni regolari per selezionare i metodi o i tipi in cui abilitare la cifratura del codice. Per esempio, il seguente comando:
babel myapp.exe --msilencryption ACME.LicenseManager::.*configura Babel per cifrare tutti i metodi della classe LicenseManager nel namespace ACME.
Task Babel di MSBuild
<PropertyGroup>
<MsilEncryption>true</MsilEncryption>
</PropertyGroup>
<Babel MsilEncryption="$(MsilEncryption)" />Babel Desktop
Seleziona l’assembly sul canvas del progetto e, nel pannello delle proprietà, abilita MsilEncryption nel gruppo Cifratura codice. Se vuoi, aggiungi un elenco di espressioni regolari per filtrare i namespace o le classi a cui applicare la cifratura del codice. Lascia vuoto l’elenco se hai selezionato i metodi da cifrare con le regole XML o con l’attributo Obfuscation. Vedi Progetti di offuscamento per sapere come lavorare con i progetti in Babel Desktop.
Dopo l’esecuzione, la vista Risultati elenca i metodi cifrati, così puoi verificare che la cifratura del codice sia stata applicata.
Le statistiche della cifratura del codice compaiono anche nel log di output (il pannello Attività in Babel Desktop), che registra ogni fase dell’offuscamento, cifratura del codice compresa.
Encrypt Msil phase, elapsed time 00.579s
Embedded resource: omJYi
size : 13170 bytes
Method statistics:
194/[ 252] resources: 76.98 %
194/[ 252] overall: 76.98 %
Number of encrypted methods: 194Esaminando le statistiche della cifratura del codice nel log di output puoi verificare facilmente se la cifratura è stata applicata al tuo codice e farti un’idea del grado di protezione che offre. Puoi così avere la conferma che il tuo codice sensibile è stato cifrato correttamente e che resta sicuro e resistente all’accesso non autorizzato.