Il reverse engineering, conosciuto anche come ingegneria inversa, è il processo con cui si analizza in dettaglio la struttura e il funzionamento di un oggetto — fisico, software o hardware — per ricostruirne le specifiche di progettazione e implementazione senza avere accesso alla documentazione originale.

In questo articolo ci concentriamo sul reverse engineering del software: come funziona tecnicamente, quando è legale, come viene usato tanto da chi difende quanto da chi attacca, e come proteggere le applicazioni della tua azienda da analisi non autorizzate.

  1. Reverse engineering: in cosa consiste
  2. Codice sorgente ed eseguibile: le premesse concettuali
  3. Disassemblaggio e decompilazione: come si torna indietro
  4. I limiti della decompilazione
  5. Le fasi del reverse engineering
  6. Ambiti di applicazione del reverse engineering
  7. Cosa dice la legge
  8. Clean room design: la tecnica della parete cinese
  9. Come proteggere il software dal reverse engineering illecito
reverse engineering

Reverse engineering: in cosa consiste

Il termine nasce nell’ambiente ingegneristico: smontare un prodotto finito per capire come è stato costruito. Gli stessi principi si sono estesi a molti campi, dal manifatturiero all’economia, fino ad approdare all’informatica.

Nel software, fare reverse engineering significa partire dal codice binario a basso livello — l’eseguibile che la macchina esegue — e risalire a ritroso fino a ricostruire la logica del codice ad alto livello da cui è nato. È il percorso inverso rispetto al normale sviluppo, che per contrasto viene chiamato forward engineering.

Ma in cosa consiste questo passaggio? Analizziamolo nel dettaglio.

Codice sorgente ed eseguibile: le premesse concettuali

Per capire il meccanismo bisogna tornare alla definizione di programma informatico. Un’applicazione nasce come codice sorgente: testo scritto in un linguaggio di programmazione ad alto livello (come C o C++), leggibile e comprensibile per l’uomo.

La macchina, però, non esegue il codice sorgente. Un compilatore lo analizza — a livello lessicale, sintattico e semantico — e lo traduce in codice oggetto; il linker collega poi il codice oggetto alle funzioni di libreria necessarie, producendo l’eseguibile finale: la traduzione del programma in linguaggio macchina, l’unico formato che il processore è in grado di eseguire.

Un caso a parte sono i linguaggi come Java o C#, che non vengono compilati direttamente in linguaggio macchina ma in bytecode, un formato intermedio eseguito da una macchina virtuale (come la Java Virtual Machine). Il bytecode conserva molte più informazioni del linguaggio macchina e per questo è sensibilmente più facile da decompilare.

Disassemblaggio e decompilazione: come si torna indietro

Per evidenti ragioni di copyright, il codice sorgente di un software proprietario non viene distribuito: chi vuole ricostruirne la logica deve partire dall’eseguibile e procedere a ritroso. Per farlo si usano due famiglie di strumenti, spesso confuse tra loro.

Il disassembler traduce il codice macchina in assembly, il linguaggio che rappresenta le istruzioni del processore in forma mnemonica: ogni opcode binario viene sostituito da un’abbreviazione leggibile e gli indirizzi di memoria possono essere convertiti in identificatori testuali. Il risultato è fedele ma di bassissimo livello: si legge istruzione per istruzione.

Il decompiler fa un passo in più: a partire dall’assembly tenta di ricostruire uno pseudocodice ad alto livello, simile al sorgente originale. È lo strumento che rende il programma davvero comprensibile a un analista, ma il risultato non è mai una copia del codice originale.

I limiti della decompilazione

Il problema principale della decompilazione è la quantità di informazioni perse nella compilazione. Il codice ricostruito non è mai identico al sorgente, ma soltanto isomorfico: ne rappresenta la struttura logica, mentre elementi come i nomi delle variabili, i commenti e le macro vengono eliminati dal compilatore e sono irrecuperabili.

A complicare la lettura contribuiscono le ottimizzazioni del compilatore, che riorganizzano le istruzioni in forme anche molto diverse da come erano state scritte, e il fatto che l’eseguibile non contiene solo codice: al suo interno convivono dati di esecuzione che l’analista deve saper distinguere dalle istruzioni vere e proprie.

Le fasi del reverse engineering

Quello del reverse engineering è un procedimento tutt’altro che semplice nella sua esecuzione materiale. Lasciando da parte gli aspetti più tecnici, possiamo tracciarne uno schema generale:

  • Disassemblaggio dell’eseguibile: il codice binario viene tradotto in assembly e, dove possibile, decompilato in pseudocodice;
  • Analisi statica: il codice ricostruito viene studiato senza eseguirlo, per mapparne struttura, funzioni e flussi di dati;
  • Analisi dinamica: il programma viene eseguito in un ambiente controllato per osservarne il comportamento reale, i dati che tocca e le comunicazioni che genera;
  • Documentazione: organizzazione e funzionamento del programma vengono descritti in specifiche formali;
  • Reingegnerizzazione (eventuale): sulla base delle specifiche, il software viene reimplementato per migliorarne le funzionalità, correggerne i difetti o integrarlo in un ambiente di esecuzione più moderno.

Ambiti di applicazione del reverse engineering

Data la sua versatilità, il reverse engineering è un’arma a doppio taglio per la sicurezza informatica: da un lato serve a irrobustire le applicazioni contro potenziali attacchi, dall’altro è impiegato dagli stessi criminali informatici per studiare e manipolare i software altrui.

Sul fronte della difesa, gli impieghi principali sono:

  • Malware analysis: gli analisti smontano un malware per capirne il funzionamento, identificarne gli indicatori di compromissione e sviluppare contromisure;
  • Ricerca di vulnerabilità: analizzare un applicativo come farebbe un attaccante permette di individuare e correggere le falle prima che vengano sfruttate;
  • Manutenzione di applicazioni legacy: quando il sorgente è andato perduto o il fornitore non esiste più, il reverse engineering consente di correggere bug e migrare il software verso tecnologie attuali;
  • Interoperabilità: comprendere le interfacce di un sistema per far dialogare con esso prodotti di terze parti;
  • Personalizzazione di sistemi embedded e recupero di codici sorgente perduti.

Sul fronte opposto, i criminali informatici usano le stesse tecniche per eliminare le protezioni dei software commerciali (cracking), clonare prodotti proprietari e scoprire vulnerabilità da sfruttare negli attacchi.

Gli attaccanti analizzano il tuo software esattamente così: alla ricerca di falle da sfruttare. Scoprile prima tu, con un’analisi condotta da chi lo fa di mestiere.
Testa le tue applicazioni

Cosa dice la legge

In Italia il software è tutelato dalle norme sul diritto d’autore (legge 633 del 22 aprile 1941) e viene trattato alla stregua di un’opera letteraria. Con il D.Lgs. 518/1992, che ha recepito la direttiva europea sulla tutela giuridica dei programmi per elaboratore (oggi direttiva 2009/24/CE), sono stati introdotti gli articoli 64-bis e seguenti, che regolano specificamente cosa si può fare con un software altrui.

La decompilazione è lecita soltanto a scopo di interoperabilità: quando è indispensabile per far funzionare il proprio programma insieme ad altri sistemi. E anche in quel caso valgono condizioni precise: deve essere effettuata da chi detiene una licenza legittima, deve limitarsi alle sole parti del programma necessarie all’interoperabilità, e le informazioni ottenute non possono essere comunicate a terzi né utilizzate per sviluppare un software sostanzialmente simile all’originale.

Fuori da questo perimetro, decompilare un software proprietario costituisce una violazione del diritto d’autore.

Clean room design: la tecnica della parete cinese

Date le premesse legislative, il clean room design — detto anche tecnica della parete cinese — è il metodo con cui il reverse engineering viene applicato in modo strutturato per non commettere alcuna violazione di copyright.

In linea generale si articola nelle seguenti fasi:

  • individuazione di un ambiente di lavoro controllato;
  • analisi del sistema da reimplementare da parte di un primo team;
  • scrittura delle specifiche funzionali, prive di qualsiasi porzione di codice originale;
  • verifica legale che le specifiche non contengano materiale coperto da copyright;
  • implementazione delle specifiche da parte di un secondo team, completamente separato da quello che ha condotto l’analisi.

La “parete” tra i due team garantisce che il nuovo software nasca dalle specifiche funzionali e non dal codice originale: replica il comportamento, non l’opera protetta.

Come proteggere il software dal reverse engineering illecito

Chi sviluppa software proprietario ha interesse a rendere l’analisi non autorizzata il più difficile e costosa possibile. Le strategie principali agiscono tutte nella stessa direzione: compromettere volutamente la leggibilità del codice per chi tenta di smontarlo.

  • Offuscamento: il codice viene trasformato in fase di build — nomi privi di significato, strutture logiche contorte, istruzioni fittizie — così che, anche una volta decompilato, risulti estremamente difficile da comprendere;
  • Cifratura dell’eseguibile (packing): il programma viene distribuito in forma cifrata o compressa e si decifra solo in memoria al momento dell’esecuzione, impedendo l’analisi statica diretta del binario;
  • Tecniche anti-debugging e anti-tampering: il software rileva se viene eseguito sotto debugger o se il suo codice è stato alterato, e in quel caso interrompe l’esecuzione;
  • Firma digitale del codice: documenta l’integrità e la provenienza dell’applicazione, garantendo che non sia stata contraffatta prima dell’esecuzione;
  • Watermarking: informazioni identificative vengono nascoste nel codice per dimostrare la paternità del software e rilevare eventuali manomissioni.

Nessuna di queste tecniche, da sola, rende un software inattaccabile: l’obiettivo realistico è alzare il costo dell’analisi illecita fino a renderla non conveniente. Per questo la protezione del software va inserita in una strategia di sicurezza complessiva, che comprenda anche il test delle applicazioni dal punto di vista di chi attacca.

Il tuo software resisterebbe all’analisi di un attaccante?

Da oltre 20 anni difendiamo le imprese italiane: oltre 5.000 clienti, oltre un milione di attacchi sventati, un SOC attivo 24 ore su 24 e le certificazioni ISO 9001 e ISO 27001.
Contatta i nostri esperti



    Dichiaro di aver letto e compreso l'Informativa sul trattamento dei dati