Ridenominazione XAML
Le applicazioni Windows Presentation Foundation (WPF) e, più di recente, MAUI usano il linguaggio di markup dichiarativo XAML e BAML (XAML compilato) per consentire ai designer visuali di creare direttamente gli elementi dell’interfaccia utente.
Babel Obfuscator può analizzare le risorse XAML e BAML e rinominare tutti i membri a cui fanno riferimento, aumentando la percentuale di simboli offuscati e rendendo il codice XAML più difficile da leggere. Inoltre Babel può unire più file di assembly che contengono risorse XAML o BAML in un unico file di assembly, migliorando l’organizzazione e semplificando la distribuzione dell’applicazione.
La ridenominazione dei simboli XAML e BAML si abilita con l’opzione --xaml dalla riga di comando. Questa opzione ha parametri facoltativi aggiuntivi, che puoi usare per rafforzare l’offuscamento XAML (BAML).
Riga di comando
babel.exe myapp.exe --xamlTask Babel di MSBuild
<PropertyGroup>
<ObfuscateXaml>true</ObfuscateXaml>
</PropertyGroup>
<Babel ObfuscateXaml="$(ObfuscateXaml)" />Babel Obfuscator prevede alcune impostazioni XAML avanzate per configurare ulteriormente il processo di offuscamento XAML, tramite coppie chiave-valore passate dopo l’opzione --xaml.
Le coppie chiave-valore disponibili sono:
keys
In XAML, una risorsa statica è una risorsa definita in fase di progettazione a cui possono fare riferimento altre parti dell’applicazione, come i controlli o gli stili. La risorsa è identificata da un nome di chiave, usato per farvi riferimento dal codice XAML.
Quando l’opzione è abilitata, Babel Obfuscator rinomina le chiavi delle risorse statiche nel codice XAML/BAML. Questo può aumentare il grado di offuscamento del codice e rendere più difficile per gli attaccanti capire lo scopo originale di una risorsa.
res
Quando è abilitata, permette a Babel di offuscare i nomi delle risorse XAML/BAML. I nomi delle risorse usate nel codice XAML/BAML, come immagini o stringhe, vengono quindi rinominati per nasconderne lo scopo originale. Per gli attaccanti può così diventare più difficile capire la struttura e la funzione del codice XAML/BAML, a vantaggio della sicurezza complessiva della tua applicazione.
strip
Questa opzione rimuove le informazioni di riga e gli spazi vuoti dal codice XAML/BAML offuscato. Per gli attaccanti può diventare più difficile risalire al codice originale, perché vengono eliminate informazioni di debug che potrebbero aiutare a ricostruire il codice sorgente. La rimozione delle informazioni di riga e degli spazi vuoti può anche ridurre la dimensione del file XAML/BAML offuscato, rendendolo più efficiente e più veloce da caricare.
manual
Per impostazione predefinita, Babel Obfuscator offusca automaticamente tutti i membri pubblici a cui il codice XAML o BAML fa riferimento. Quando serve un controllo più preciso, puoi abilitare l’opzione manual. In questo modo specifichi manualmente quali membri pubblici devono essere offuscati, con le regole rapide o con i file di regole XML. Ottieni un controllo maggiore sul processo di offuscamento, ma devi dedicare più lavoro alla configurazione.
babel.exe myapp.exe --xaml keys=on --xaml res=on --xaml strip=on<PropertyGroup>
<ObfuscateXaml>keys=true;strip=true;manual=false;res=true;true</ObfuscateXaml>
</PropertyGroup>
<Babel ObfuscateXaml="$(ObfuscateXaml)" />Allineare i valori letterali stringa ai membri rinominati associati a XAML
Quando un assembly WPF viene compilato, il compilatore di norma incorpora ogni pagina XAML come BAML (la forma binaria di XAML) nelle risorse dell’assembly. Durante la fase di lettura Babel esamina questo BAML e, per ogni dichiarazione x:Name, tenta di associare il nome al corrispondente campo sottostante del code-behind nel tipo dell’elemento radice. Un campo per cui l’associazione riesce viene trattato come associato a XAML per il resto dell’esecuzione dell’offuscamento.
Quando un membro associato a XAML viene rinominato, Babel esegue un ulteriore passo di allineamento sul tipo che lo dichiara. Percorre il corpo di ogni metodo del tipo e riscrive ogni valore letterale stringa uguale al nome originale del membro, sostituendolo con il nuovo nome. Il confronto è una semplice uguaglianza di stringhe sul testo del valore letterale, e la riscrittura si applica a tutti questi valori letterali del tipo, a prescindere da come vengono poi usati. Gli unici valori letterali esclusi dalla riscrittura sono quelli passati a System.Resources.ResourceManager e i punti di chiamata esclusi esplicitamente da regole di ridenominazione fornite dall’utente.
Lo scopo è far sì che, dopo la ridenominazione, nel code-behind continuino a funzionare le ricerche per nome che WPF esegue in fase di esecuzione. Schemi come this.FindName("tabPreise"), metodi helper personalizzati come GetControlByName<T>(string name) o qualsiasi altro codice che risolve un membro o un elemento con nome tramite il nome in forma di stringa che aveva nel sorgente continuano a funzionare, perché i valori letterali sono stati mantenuti allineati al campo rinominato. Poiché la corrispondenza è strutturale e non basata su attributi, l’allineamento include automaticamente gli helper definiti dall’utente, senza richiedere un attributo di adesione esplicita sull’helper.
Per esempio, dato il seguente code-behind:
private TabItem tabPreise { get; set; }
void Wire()
{
var tab = GetControlByName<TabItem>("tabPreise");
// ...
}Dopo che Babel ha offuscato l’assembly, il campo è rinominato e il valore letterale che lo nomina è allineato al nuovo nome:
private TabItem cm { get; set; }
void Wire()
{
var tab = GetControlByName<TabItem>("cm");
// ...
}L’allineamento scatta solo quando l’associazione BAML descritta sopra riesce. Se il tipo dell’elemento BAML non può essere risolto (di solito perché l’assembly che lo definisce non è nel percorso di ricerca di Babel e il resolver emette l’avviso W00013 per quell’assembly), l’associazione fallisce senza segnalazioni e il membro non viene contrassegnato come associato a XAML. La ridenominazione del campo in sé non dipende dal contrassegno XAML, quindi il campo riceve comunque il nuovo nome; i valori letterali che nominano il campo originale restano però invariati, e l’assembly offuscato contiene IL incoerente. Ogni ricerca per nome in fase di esecuzione che si basava su quei valori letterali fallisce.
I rimedi sono due, in quest’ordine:
-
Considera W00013 bloccante per la build nei progetti che contengono BAML incorporato. Aggiungi al percorso di ricerca di Babel, con l’opzione
--addsearch, le cartelle che contengono ogni assembly referenziato che definisce tipi di elementi XAML, così il resolver BAML può associare ogni tipo di elemento. Con tutti i tipi di elemento risolti, il passo di allineamento funziona come previsto. -
Quando invece vuoi mantenere il nome originale (per esempio quando file
.xamlautonomi vengono distribuiti insieme all’assembly e fanno riferimento al campo con il suo nome originale), escludi il campo dalla ridenominazione con una regola XML bloccata:
<Rule name="keep-xname-tabPreise"
feature="renaming" exclude="true" locked="true">
<Target>Fields,Properties,Methods</Target>
<Pattern>MyNamespace.MyForm::tabPreise</Pattern>
<Pattern>MyNamespace.MyForm::get_tabPreise</Pattern>
<Pattern>MyNamespace.MyForm::set_tabPreise</Pattern>
</Rule>Con il nome del campo invariato, il passo di allineamento non ha nulla da riscrivere e l’assembly resta coerente sia con il BAML sia con eventuali file XAML separati che fanno riferimento a tabPreise.
Per un quadro più ampio di quando W00013 è solo informativo e quando invece corrisponde a un cambiamento reale nell’output offuscato, vedi W00013 nel percorso di associazione BAML nel riferimento della riga di comando.