Il .NET Framework usa, com'è noto, sulla falsariga di Java, un codice intermedio portabile su tutte le piattaforme ed indipendente dal processore: si tratta del
MSIL, Microsoft Intermediate Language, lì dove Java usa il cosiddetto
bytecode. Da quando è stato rilasciato, hanno assunto grande popolarità i
disassemblatori di codice, sotto forma di eseguibili o DLL, generati con .NET.
Il problema è il seguente: i file intermedi sono contrassegnati con identificatori ed algoritmi dai quali è facile risalire al codice sorgente; inoltre .NET, se da un lato facilita la vita all'installatore fornendo con ogni Assembly una serie di metadati in cui è registrato il comportamento a runtime previsto, dall'altro agevola il lavoro di chi vuole comprendere il codice sorgente, dato che tali metadati sono facilmente leggibili.
Fra i vari
disassemblatori, il più noto è sicuramente
Reflector di
Lutz Roeder, un tool assai popolare e gratuito, con un'usabilissima interfaccia, nel quale basta caricare un file per poterne esplorare il codice sorgente, in una pratica struttura ad albero che riflette quella dei namespace .NET.
La sicurezza (cui si rifà la proprietà intellettuale) è un'eterna guerra fra costruttori di proiettili e di corazze, e pressoché in contemporanea al primo .NET Framework uscirono i primi
offuscatori, i quali sostanzialmente rinominano i simboli utilizzati nel codice Assembly, oltre ad utilizzare altri trucchi volti ad aumentare lo spazio di ricerca del disassemblatore. Il mercato degli offuscatori è fiorente, ma è bene ricordare che la stessa Microsoft fornisce un prodotto del genere, il
dotfuscator, nelle versioni a pagamento di Visual Studio .NET.
Sul tema dell'obfuscation del codice un'introduzione di alto livello al problema può essere reperita
a questo indirizzo, mentre al proprio prodotto MSDN dedica
un'intera serie di articoli. Giusto per chiudere il cerchio, una volta usciti gli offuscatori, era quasi banale che qualcuno prima o poi pensasse a produrre dei
deoffuscatori.
In questa review ne esaminiamo uno,
Dis# della
NETdecompiler, una
one-man-gang company che grava interamente sulle spalle del Dr. Ruslan Kozlov, e che produce praticamente solo Dis#. L'ultima versione, la 2.3.0, del
prodotto può disassemblare codice creato col .NET Framework 2.0, ma per installare il prodotto è necessario avere il .NET Framework
1.1.4322 (che può comunque essere installato side-by-side col 2.0).
Poiché una licenza singola costa
399 dollari (per acquisti multipli si va a trattativa), è opportuno esaminare in primo luogo i vantaggi rispetto ad un tool gratuito come Reflector: possibilità di esaminare il codice sorgente di assembly offuscati o di file PDB, di ricostruire la documentazione XML del codice, di esaminare il contenuto dei file risorse, e di editare il codice decompilato. La stessa NETdecompiler effettua,
a questa pagina, un paragone (devo dire abbastanza obiettivo) fra le funzionalità di Reflector e quelle di Dis#.
Si può richiedere un codice di attivazione da
Help/Request Activation Code, o provare il prodotto con
File/Trial: verranno in tal caso decompilati solo gli "usuali" namespace
ASP, _ASP e My. L'attivazione genera un file .key, che va inviato via e-mail alla NETdecompiler (lo si può fare col comando
Help | Your Feedback); si riceverà un file
Dis#.License.dll, da salvare nella cartella di installazione del prodotto. La procedura di rilascio delle licenze non è automatizzata, ma i tempi di risposta sono comunque rapidi.
Per testare il prodotto il Dr. Kozlov fornisce degli
assembly di esempio; in particolare vengono fornite delle strutture (BigSwitch, SmallSwitch ed enumerazione sequenziale) che il Reflector in effetti non riesce a decompilare correttamente. Per onestà intellettuale ho comunque ripetuto le prove con del codice da me sviluppato, con degli Assembly presi qua e là per la rete, ed ovviamente con del codice offuscato, dopo essermi assicurato che Reflector fallisse nel decompilarli.
Mi è stata fornita una versione di Dis#, che sarà scaricabile dal sito nei prossimi giorni (vi consiglio di tenere d'occhio la
pagina delle news), che permette di vedere agevolmente il codice sorgente sviluppato dall'utente, incluso nel namespace Root. Vi suggerisco un interessante esempio di codice offuscato: provate a decompilare lo stesso Reflector.
Per chi comincia ad usare il prodotto, è disponibile un succinto
Quick Start. L'uso base è comunque dei più semplici: basta caricare l'assembly da
File | Load Assembly. È possibile decompilare una classe o un metodo, o addirittura vedere il codice assembler, e sono disponibili informazioni aggiuntive sull'assembly; una caratteristica di sicura utilità è la possibilità di aprire più documenti alla volta, in schede
tabbed.
Un problema, invece, non indifferente per codice complesso è l'impossibilità di effettuare ricerche: non posso trovare, insomma, tutte le occorrenze della variabile
pippo o del metodo
pluto(). Una mancanza non da poco, che sarà risolta nelle prossime versioni secondo quanto mi ha assicurato il Dr. Kozlov. Infine Dis#, correttamente, permette di modificare i nomi, ma
non i valori delle variabili, né sono a conoscenza di alcun disassemblatore di codice .NET in grado di farlo.
In conclusione, un tool dal costo non indifferente, ma che di sicuro svolge alla perfezione il lavoro che afferma di saper fare. Peccato per la mancanza della funzionalità di ricerca.