Home

 
 
 
 
 



 
 
 
 

 
 
 

 
 
 
 
 









Blog2theMax
Il blog del team di Code Architects

Ho già parlato in questo blog di CodeWall.NET, un tool per la protezione degli eseguibili .NET 2.0 dalla decompilazione, a cui io e Vito Plantamura stiamo lavorando da un paio di mesi. Finalmente abbiamo una beta robusta e funzionante, e non vediamo l'ora di metterla online.

Date le finalità del prodotto, non è un mistero il fatto che abbiamo passato la maggior parte del tempo per implementare tutte le tecniche "anti-sprotezione" di nostra conoscenza, incluso alcune davvero esoteriche. E' un vero peccato non poterle descrivere nei dettagli, per motivi che dovrebbero essere evidenti. Comunque, qualche cosa la posso comunque raccontare.

Uno dei punti deboli di praticamente tutti i meccanismi di protezione di questo tipo è che, se un "cracker" trova il modo per sproteggere UN SOLO eseguibile protetto, egli è in grado di scrivere uno script o un tool in grado di sproteggere TUTTI gli eseguibili protetti, la qual cosa sarebbe ovviamente un vero disastro per noi e per i nostri clienti. Per ovviare a questo serissimo problema, ogni copia di CodeWall.NET è unica. Non solo utilizza una chiave differente, ma contiene anche un algoritmo di decifratura leggermente differente. Questo accorginmento rende l'attacco mediante script virtualmente impossibile.

Ecco un'altra tecnica che abbiamo adottato per rendere la protezione più robusta. Le applicazioni protette con CodeWall.NET possono contenere delle stringhe criptate, che saranno riportate in chiaro solo in fase di esecuzione, e solo se l'assembly "gira" sotto CodeWall.NET. Questo significa che se anche qualcuno riuscisse a estrarre un assembly dall'eseguibile protetto, dovrebbe capire come funziona il decrypt delle stringhe e poi decrittare le stringhe una a una. Attenzione, perchè non solo è possibile criptare le stringhe in questo modo: è anche possibile criptare nomi di classi e di metodi, quindi se queste stringhe non sono decrittate correttamente il programma non funzionerebbe affatto.

Ovviamente, il loader di CodeWall.NET è scritto in codice unmanaged, in modo da NON essere decompilabile con Reflector, Anakrino, o ILDASM. Un malintenzionato particolarmente motivato potrebbe usare un disassembler "classico", ma poi gli toccherebbe decifrare migliaia di opcode assembly "nativo", il che non è proprio alla portata di tutti. Purtroppo, pero', l'uso del codice unamanged limita l'utilizzo di CodeWall.NET ai soli eseguibili Win32 (Windows Forms e Console) che girano in modalità full-trust. Non possiamo quindi supportare appliczioni ASP.NET e neanche applicazioni ClickOnce, a meno che questi ultimi non girino appunto in full-trust mode.

Non abbiamo ancora stabilito il prezzo di listino di CodeWall.NET, ma prevediamo che si aggirerà sui 250 dollari (circa 200 euro) e quasi certamente ci sarà uno sconto per il periodo del lancio. A breve speriamo di mettere una versione "trial" disponibile sul sito. Nel frattempo, se avete domande lasciate pure un commento.

1/25/2006 7:12:03 PM (GMT Standard Time, UTC+00:00) #  | Comments [2] | 

Fino a non molti anni fa ero abbastanza refrattario a meccanismi e tool che misurassero in qualche modo le caratteristiche e la leggibilità del codice. Erano i tempi di VB6, quando era davvero difficile scrivere del codice "pulito", non disponendo ad esempio di ereditarietà e di gestione strutturata degli errori. Ma il motivo principale per il mio disinteresse per le metriche del software derivava soprattutto dal fatto che scrivevo codice in quasi totale solitudine, e quando interagivo con altri sviluppatori era a livello binario di componenti e interfacce. Io non andavo a mettere il naso nel loro codice e viceversa.

Le cose sono cambiate da quando esiste Code Architects, dove si lavora in team e spesso occorre uniformare gli stili degli sviluppatori che lavorano sullo stesso progetto. Viene allora naturale voler confrontare, ad esempio, la quantità dei commenti che ciascuno inserisce nel proprio codice, oppure la lunghezza e la complessità "media" dei singoli metodi. Allora ho cominciato ad interessarmi a questo argomento, e uno dei risultati di questo interesse è stato il libro Practical Guidelines and Best Practices for the Microsoft Visual Basic .NET and Visual C# Developer, un titolo chilometrico per una raccolta di 735 regole, il cui scopo è di rendere il codice più leggibile, efficiente, e scalabile possibile. (Per la cronaca, la versione italiana, nella traduzione di Natale Fino, appare con il titolo più "umano" Microsoft .NET Framework: Regole di stile e Best Practice... fine dei consigli per gli acquisti! :-) )

Ovviamente il problema di misurare in qualche modo la complessità del codice esiste da sempre, e molti illustri scienziati hanno definito con esattezza alcuni indici in grado di fornire un valore il più oggettivo possibile per tale complessità. Il significato di alcuni indici è evidente: numero di classi e metodi, numero totale di righe nel programma, numero medio di istruzioni nei metodi, numero medio di metodi per classe, quantità di commenti e percentuale sulle righe totali, ecc. Altre quantità abbastanza interessanti sono la profondità massima dell'inheritance tree delle classi del programma, il numero di classi che derivano da una classe base, il numero di classi esterne da cui l'applicazione dipende, e così via. Sono tutte quantità interessanti, ma che alla fine non forniscono un quadro reale della complessità del programma e della leggibilità del codice - a parte forse la quantità di commenti, che è un indicatore prezioso di quanto facilmente il codice potrà essere manutenuto e aggiornato in futuro.

Tra gli indici più importanti e realmente utili vi è sicuramente l'indice ciclomatico, che indica quanti sono i percorsi possibili all'interno di un metodo. Ad esempio, se un metodo contiene un blocco di istruzioni sequenziali il suo indice ciclomatico è 1; se invece contiene un blocco If o If...Else allora ha un indice ciclomatico pari a 2; se invece contiene un Select Case (VB) o switch (C#) con N blocchi case, allora il suo indice ciclomatico è pari a N se il blocco contiene il blocco Case Else (VB) o default (C#), oppure N+1 se tale blocco non c'è. Il calcolo diventa più complesso quando i blocchi condizionali sono nidificati: un metodo con un blocco If che contiene al suo interno un altro blocco If (con o senza Else) ha un indice ciclomatico pari a 3, perchè sono possibili tre differenti percorsi di esecuzione; se un Select/switch con clausola Case Else/default ha N blocchi Case ciascuno dei quali contiene un blocco If, l'indice ciclomatico sale a N*2, e così via.

L'indice ciclomatico assume una importanza significativa al momento del test del codice. Se un metodo ha indice ciclomatico pari a 3 significa che dovrò preparare almeno tre test per controllare che funzioni bene in tutti i casi. (Ovviamente, in realtà dovrei prepararne un numero maggiore, in quanto occorre di solito controllare le condizioni al limite.) Chi utilizza la metodologia Test Drive Development (TDD) e lavora con NUnit o simile, dovrebbe essere molto sensibile a questo tema, che si preannuncia ancora più importante con il rilascio di Team System, che integrerà questi strumenti all'interno di Visual Studio.

Incidentalmente, l'indice ciclomatico è legato anche al refactoring. Infatti, un metodo con un alto indice ciclomatico dovrebbe essere rifattorizzato per suddividerlo in metodi più semplici. In generale il refactoring è sempre vantaggioso se migliora la leggibilità del codice, ma lo è anche di più se suddividendo un metodo lungo in metodi più semplici si riesce anche a ridurre l'indice ciclomatico complessivo (e quindi il numero di test da effettuare).

Un altro indice abbastanza importante, almeno per il mio stile di codifica, è il numero di exit point di un metodo. Maggiore è questo valore, maggiore è lo sforzo necessario per testare e modificare il codice nel metodo. Idealmente, infatti, tutti i metodi dovrebbero avere un solo exit point, in modo da poter facilmente inserire, se serve, una istruzione per il tracing. Un altro motivo per conoscere questo valore è che in futuro potrei voler modificare il valore di ritorno prima di uscire dal metodo, ad esempio per assicurarmi che la stringa restituita sia in minuscolo, che un numero sia positivo, o che un oggetto non sia Nothing/null.

Quando finalmente si è convinti che avere tutte queste informazioni sul proprio codice non è proprio una perdita di tempo, ci si deve scontrare con la realtà. Nel mondo .NET non esistono molti tool in grado di fornire queste informazioni. Ci sono molti prodotti commerciali, qualche freeware e qualche progetto open source, ma non sono riuscito a trovare un unico prodotto che faccia al caso mio, soprattutto per VB.NET (in C# le cose vanno meglio, come al solito). Ecco quello che ho trovato finora con una ricerca via Google. In molti casi si tratta di prodotti che fanno anche altro (tipicamente, refactoring) oltre a calcolare metriche. Il costo in dollari si riferisce alla versione single-user.

Ecco alcuni tool che lavorano direttamente a livello di Intermediate Language (IL):

vil (freeware): http://www.1bot.com/
NDepend (open source): http://smacchia.chez.tiscali.fr/NDepend.html
Reflector.CodeMetrics (free Reflector add-in): http://projectdistributor.net/Projects/Project.aspx?projectId=42

Questi invece lavorano sui sorgenti C# (alcuni anche con Java):
 
devMetrics ($75): http://www.anticipatingminds.com/Content/Products/devMetrics/devMetrics.aspx
C# Refactory ($99): http://www.xtreme-simplicity.net/index.cfm?pageID=3&htmlpage=CSharpRefactory.html
RSM ($199): http://msquaredtechnologies.com/m2rsm/index.htm
C#-Metrics ($250): http://www.semanticdesigns.com/Products/Metrics/CSharpMetrics.html
dotEasy (open source, alpha version): http://www.doteasy.addr.com/
Source Monitor (freeware): http://www.campwoodsw.com/index.html

Questi sono gli unici che analizzano i sorgenti VB.NET:

Project Analyzer ($199): http://www.aivosto.com/project/project.html
Essential Project Manager (prezzo non precisato): http://www.powersoftware.com/epm/

Il problema dei tool che lavorano direttamente sugli assembly compilati (anzichè sui sorgenti) è che non possono calcolare esattamente le metriche che riguardano la leggibilità del codice, ad es. la quantità di commenti e il numero di statement per metodo. Ma soprattutto, il problema è che i compilatori VB e C# producono un codice IL con un numero maggiore di confronti e salti di quelli presenti nel sorgente, quindi l'indice ciclomatico calcolato da questi tool è sempre superiore a quello reale. Tutti questi tool supportano gli indici più comuni, anche se non mi pare - a leggere la documentazione - che ce ne sia uno che mostri il numero di exit point di un metodo. La maggior parte sono tool a riga di comando, quindi non hanno una bellissima interfaccia utente ma hanno il vantaggio di poter essere integrati nel proprio processo di build.

Alla fine, ho pensato che scrivere un tool in grado di calcolare gli indici che realmente mi interessano non dovrebbe essere troppo complicato, almeno se si ha una sufficiente padronanza delle regular expression. Quindi ho deciso di mettermi al lavoro sul un piccolo tool tutto mio. Se tutto va bene, tra qualche giorno posto sul blog i miei risultati.

Nel frattempo, se avete dimestichezza con strumenti del genere - sia tra quelli citati sopra che altri che non ho trovato nelle mie ricerche - lasciate pure un commento, please!

7/28/2005 11:16:47 AM (GMT Daylight Time, UTC+01:00) #  | Comments [0] | 
 
Feed di Blog2theMax
RSS 2.0 | Atom 0.2
Cerca nel blog
Archivio
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910
Categorie

Powered by: newtelligence dasBlog 1.7.5016.2

 ©2004-2005 Code Architects S.r.l. - All rights reserved  Sign In