Archivio storico · Reverse engineering · Spiegazione dettagliata

Lezione 6: cifratura, camuffamento e dati nascosti

Che cosa insegna la lezione su XOR, decifratori camuffati, crittografia a chiave pubblica e steganografia, e dove il testo va corretto.

In breve

La sesta lezione ripassa il lavoro delle lezioni 3-5 con un esercizio su un gioco avventura, poi passa alla cifratura nelle protezioni: lo XOR, le routine di decifrazione camuffate, chiavi grandi, brevetti, PGP, programmi DOS con estensore a 32 bit e dati nascosti nelle immagini.

Spiego i concetti e correggo alcune imprecisioni del testo. Non rispondo alle domande dell'esercizio, perché chiedono di inventare modifiche per aggirare una protezione, e non descrivo come costruire routine camuffate o generatori di codice che cambia forma.

1. L'esercizio sul gioco

Il testo ripropone una protezione «da manuale»: il programma non chiede una parola da ricordare, ma un numero che l'acquirente legittimo trova su una pagina del manuale. L'utente sceglie con il mouse un numero fra cinque, per un oggetto estratto a caso.

Nel listato la struttura è facile da riconoscere:

Questa è un'ottima lezione di progettazione, perché mostra tre debolezze comuni: la risposta giusta è conservata nel programma, esiste un unico punto in cui si decide l'esito e l'esito viene comunicato al resto del programma con un valore semplice.

Le cinque domande

Le domande chiedono dove siano le risposte, che cosa succeda sostituendo singole istruzioni e di trovare almeno sette modifiche alternative. Le lascio senza risposta: l'ultima richiede espressamente di produrre varianti di aggiramento. Le prime due parti sono invece intuibili dal listato: la tabella è indirizzata con un indice moltiplicato per due, perché ogni risposta occupa due byte.

2. Lo XOR: la cifratura più semplice

Lo XOR combina due bit e restituisce 1 solo se sono diversi. Applicandolo due volte con la stessa chiave si torna al dato originale. Il testo lo mostra con un esempio corretto: FF XOR A1 dà 5E, e 5E XOR A1 dà di nuovo FF.

Una routine di cifratura è quindi anche la sua decifrazione: legge ogni byte, lo combina con il valore e lo riscrive. Il listato del testo usa un confronto con «minore o uguale» alla fine del ciclo; così processa un byte in più rispetto alla dimensione dichiarata. È un classico errore di confine.

La chiave può essere fissa oppure scelta a caso. Per la seconda strada il testo usa la lettura dell'ora e prende i centesimi di secondo. Scarta il valore 0, perché lo XOR con 0 lascia i dati invariati.

Perché è debole

Il punto cruciale del testo è che la parte di codice che decifra non può essere cifrata a sua volta. La chiave, o il modo di ricavarla, compare quindi in chiaro nel programma. Una chiave di un solo byte ha inoltre appena 256 valori possibili: si possono provare tutti. Lo XOR serve a impedire una lettura casuale, non a proteggere da un analista determinato.

3. Decifratori camuffati e codice «spazzatura»

L'autore riconosce che la tecnica nasce nel mondo dei virus informatici: i programmi dannosi cambiavano l'aspetto della propria routine di decifrazione per sfuggire ai rilevatori basati su firme. Le protezioni commerciali hanno adottato idee simili.

Il testo descrive, a livello di principio, tre elementi:

Non fornisco una guida per costruire queste routine. Descrivo invece perché il metodo ha un limite strutturale. Per essere eseguito, il codice cifrato deve prima diventare codice comprensibile in memoria. Chi osserva la memoria vede quel momento, qualunque forma abbia la routine che lo prepara. È anche il motivo per cui i prodotti di sicurezza moderni non si affidano soltanto alle firme: osservano il comportamento o eseguono il codice in un ambiente controllato.

Un trucco di indirizzamento

L'esempio finale mostra un indirizzo ottenuto sommando due numeri: 0xBFAA più 0x4066 dà 0x10010, ma in un registro a 16 bit il risultato si «riavvolge» e diventa 0x0010. Il punto di partenza reale non compare quindi in una forma ovvia. Il calcolo del testo è corretto; la parentesi chiusa in modo errato nella riga di esempio è un refuso.

4. Chiavi grandi: la parte più forte e meno precisa

Il testo dice che si possono rompere anche cifrature molto grandi fattorizzando in numeri primi con un crivello quadratico distribuito su centinaia di computer. Il passaggio mescola unità diverse: parla prima di chiavi di 129 o 250 cifre, poi di una chiave di 250 bit. Una chiave di 250 bit equivale a circa 75 cifre decimali (250 × 0,301), non a 250. La differenza è enorme, perché la difficoltà della fattorizzazione cresce molto rapidamente con la dimensione. L'affermazione generale «si può rompere tutto» non è dimostrata nel documento.

I riferimenti bibliografici indicati (crittoanalisi differenziale, test di primalità, pseudoprimi) sono lavori accademici reali o plausibili, ma non ne ho verificato i dettagli. Il testo li attribuisce a «svizzeri capaci di rompere tutto»: gli autori citati sono noti soprattutto per aver progettato un algoritmo di cifratura, non per «rompere ogni cosa». Anche l'algoritmo IDEA è oggi indicato come da non usare per cifrare nuovi dati nello standard OpenPGP corrente.

5. Brevetti sulla cifratura dei programmi

Il documento elenca quattro brevetti americani su processori che eseguono programmi cifrati, calcolatori con istruzioni mescolate, doppie aree di programma e un sistema di verifica basato su XOR. Le descrizioni sono riassunti del testo e non le ho confrontate con i brevetti originali.

L'idea comune è legare l'esecuzione a una chiave o a un componente specifico del computer. Funziona se il componente protetto non è accessibile a chi controlla la macchina; se tutto avviene nel software, il problema riappare: la chiave deve trovarsi da qualche parte.

6. PGP: l'affermazione da leggere con più attenzione

Come funziona, in breve

Nei sistemi a chiave pubblica ogni utente ha una chiave di cifratura pubblica e una di decifrazione segreta. La sicurezza dipende dalla difficoltà di ricavare la seconda dalla prima: nell'RSA, dalla fattorizzazione del numero n nei suoi due fattori primi. La formula riportata dal testo, con il minimo comune multiplo di p−1 e q−1, è una forma corretta della relazione tra i due esponenti. Nella pratica OpenPGP cifra il messaggio con un algoritmo simmetrico e protegge la chiave di sessione con la chiave pubblica.

La stima di «109 anni» per fattorizzare un numero di 200 cifre proviene da letteratura molto più vecchia e non va usata come valutazione attuale.

L'attacco a MD5

Il testo afferma che PGP dipende da MD5 e che esiste un attacco «di pochi minuti» per costruire due messaggi con lo stesso riassunto. La descrizione parla di variabili di concatenamento scelte dall'attaccante e di un solo blocco. Questo differisce da una collisione sull'algoritmo completo con il suo valore iniziale standard, ed è la ragione per cui non basta a dedurre che le firme PGP dell'epoca fossero falsificabili.

La conclusione di fondo del testo, però, è corretta come avvertimento: MD5 non è più accettabile quando si richiede resistenza alle collisioni, per esempio nelle firme digitali. Lo standard OpenPGP attuale, RFC 9580, richiede una suite di algoritmi moderni che comprende SHA2-256.

L'autore dichiara anche di avere un computer dedicato che attacca PGP ventiquattr'ore su ventiquattro. È un'affermazione personale, senza risultati verificabili. Non riporto alcun procedimento operativo.

7. Programmi DOS con estensore a 32 bit

La sezione è dichiarata provvisoria: l'autore rimanda a un contributo che non ha ricevuto. Il suggerimento generale è trovare la funzione principale di un programma scritto in C risalendo dal punto di uscita verso DOS fino alla chiamata che avvia il corpo del programma. Poi si pone un punto di arresto e si prosegue con il debugger.

C'è una correzione tecnica. Il testo dice che il byte CC si comporta come l'interruzione 1; in realtà CC è l'istruzione di breakpoint, che genera l'interruzione 3, mentre l'interruzione 1 ha il codice F1. L'uso pratico descritto, sostituire un byte con CC per fermarsi nel debugger, è però coerente con questa funzione.

La parte sul linguaggio è un'opinione: secondo l'autore il C sarebbe lo strumento ideale per i cracker e altri linguaggi sarebbero sprechi. È una preferenza dell'epoca, non un fatto.

8. Password nascoste nelle immagini

L'ultima tecnica è la steganografia: nascondere dati in un altro contenuto. Se ogni pixel usa più bit per il colore, il bit meno significativo cambia l'aspetto in modo impercettibile. Sfruttando quel bit in molti pixel si può incorporare un messaggio, una password o un file. Il testo dice che un algoritmo semplice può poi riportare quei bit alle parti del programma che li usano.

La spiegazione è corretta come principio. Va solo ricordato che non c'è un limite ovvio alla quantità nascosta e che il costo è la perdita di fedeltà dell'immagine in caso di compressione con perdita: se il file viene ricompresso, i bit nascosti possono andare persi. Come difesa, il metodo ha un valore modesto: chi analizza il programma osserverà dove i dati vengono letti e usati.

9. Che cosa distinguere

Il finale ripete l'invito a scrivere all'autore, tramite un indirizzo anonimo, per ottenere le lezioni mancanti. Non ho modo di verificare se quel canale fosse ancora attivo o sicuro.

10. Lezioni per chi progetta software

Glossario

XOR
Operazione bit a bit che restituisce 1 quando i due bit sono diversi.
Polimorfismo
Capacità di una routine di cambiare aspetto senza cambiare funzione.
Fattorizzazione
Scomposizione di un numero nei suoi fattori primi.
Funzione di hash
Funzione che riduce un messaggio a un riassunto di lunghezza fissa.
Collisione
Coppia di messaggi diversi con lo stesso riassunto.
Steganografia
Tecnica che nasconde l'esistenza stessa di un messaggio dentro un altro contenuto.

Fonti e verifiche

Il testo è stato incollato dall'utente in un unico blocco e non è presente come file allegato. Ho controllato XOR, somma a 16 bit e conversione tra bit e cifre. Per MD5, OpenPGP e il codice CC ho consultato RFC 6151, RFC 9580 e un riferimento sull'istruzione INT3. Non ho eseguito programmi né applicato modifiche.

Leggi il documento originale: ORC_6.DOC