Perché ogni file .exe nasconde ancora un programma DOS (anche su Windows 11)

Ogni eseguibile Windows contiene ancora un header DOS con firma MZ. Non è un residuo inutile: serve a garantire compatibilità, semplificare il parsing e mantenere coerenza nel formato PE. Tutti i dettagli.

Aprire un file eseguibile Windows con un editor esadecimale (si può usare, ad esempio, HxD) rivela un dettaglio che sorprende: ogni .exe, anche i file moderni, inizia con una firma che appartiene a un mondo ormai scomparso. Le prime due lettere sono MZ, seguite da un piccolo programma DOS che stampa il messaggio “This program cannot be run in DOS mode“. Non è un residuo casuale, ma una scelta progettuale che affonda le radici nei primi anni ’80 e che ancora oggi influenza strumenti, loader e perfino alcune tecniche di sicurezza.

Per capire perché questa struttura esiste ancora, bisogna tornare al periodo in cui MS-DOS rappresentava la piattaforma dominante su PC. Gli eseguibili utilizzavano un formato semplice, identificato proprio dalla firma MZ, iniziali di Mark Zbikowski, uno degli ingegneri Microsoft che contribuì alla definizione del layout binario. Quando Windows iniziò a diffondersi, prima come ambiente sopra DOS e poi come sistema autonomo, serviva un modo per mantenere compatibilità senza rompere il funzionamento degli strumenti esistenti. Da qui la soluzione: inserire un programma DOS valido (è noto come DOS stub) all’inizio di ogni eseguibile Windows.

La struttura reale di un eseguibile Windows

La parte iniziale di un file si chiama header: senza header, un eseguibile sarebbe solo una sequenza opaca di byte, priva di significato operativo.

Un header è un blocco iniziale di metadati che descrive il tipo di file, la sua organizzazione interna e le istruzioni necessarie per interpretarlo correttamente. Nel caso degli eseguibili, funge da interfaccia tra il file e il loader del sistema operativo. È ciò che permette a Windows di capire come caricare il programma in memoria, dove iniziare l’esecuzione e quali dipendenze risolvere.

Un file .exe moderno segue il formato Portable Executable, noto come PE. Tuttavia, la parte PE non si trova all’inizio del file: il loader di Windows individua l’header reale tramite un offset specificato dentro la struttura DOS iniziale, chiamata IMAGE_DOS_HEADER. In particolare, il campo e_lfanew indica dove cominciano la firma PE e il resto delle intestazioni. Il codice DOS presente all’inizio dell’eseguibile non viene eseguito da Windows, ma resta formalmente valido.

Il ruolo del DOS stub e perché non è sparito

Il piccolo programma DOS incluso all’inizio di ogni eseguibile evitava comportamenti imprevedibili quando un utente tentava di eseguire un programma Windows sotto DOS puro.

Una precisazione importante è doverosa: il DOS non esiste più in Windows. Le versioni di Windows appartenenti alla famiglia NT (Windows NT 3.1 e successive, quindi anche Windows 10 e Windows 11), non includono un kernel DOS. Il sistema operativo utilizza un’architettura completamente diversa, basata su un kernel ibrido, gestione della memoria protetta e un modello a processi isolati.

In passato esisteva un sottosistema chiamato NTVDM (NT Virtual DOS Machine) che permetteva l’esecuzione di applicazioni DOS a 16 bit su sistemi a 32 bit. Questo componente simulava un ambiente compatibile, ma non era un sistema DOS reale: con l’arrivo dei sistemi a 64 bit, NTVDM è stato rimosso completamente. Oggi, su Windows x64, il codice DOS non può essere eseguito nativamente.

Il sistema operativo Windows moderno non interpreta né esegue codice DOS: non esiste alcun percorso interno che lo utilizzi per avviare programmi e la presenza dello stub non cambia questo fatto.

Il prompt dei comandi non è DOS

Un altro equivoco molto diffuso riguarda il prompt dei comandi: cmd.exe non è DOS. È un’applicazione Win32 che gira sopra il kernel Windows e utilizza le API di sistema. Il comportamento ricorda quello di MS-DOS per ragioni di compatibilità e abitudine, ma “sotto il cofano” il funzionamento è completamente diverso.

Quando si esegue un comando con cmd, il processo è gestito dal sottosistema Win32, non da un interprete DOS. Le chiamate al filesystem, alla memoria e ai processi passano attraverso le API di Windows. In pratica, è una shell che emula alcune convenzioni storiche, ma opera in un ambiente moderno.

Vale lo stesso discorso per PowerShell, che rappresenta un’evoluzione ancora più distante dal modello DOS: basata su .NET, orientata agli oggetti e completamente integrata con il sistema operativo.

Perché lo stub DOS esiste ancora nei file .exe

La presenza del cosiddetto DOS stub all’inizio di ogni eseguibile PE non ha nulla a che vedere con l’esecuzione reale di codice DOS sui sistemi Windows moderni. Si tratta di una scelta progettuale legata alla specifica del formato Portable Executable.

Sebbene possa sorprendere leggere ancora “This program cannot be run in DOS mode” nell’header di ogni eseguibile Windows, lo stub funge da “contenitore” iniziale  allineato alle specifiche di formato, non è un componente davvero eseguito dal sistema operativo. Su Windows moderno quel codice è puntualmente ignorato.

I linker moderni, inclusi quelli di Visual Studio, continuano a inserire automaticamente lo stub all’interno degli eseguibili compilati; esiste anche un’opzione, spesso chiamata /stub, che consente di sostituire quel codice con uno personalizzato.

Qualcuno ha sfruttato tale possibilità per costruire eseguibili ibridi: un singolo file che contiene sia un programma DOS sia uno Windows. In passato tecnologie come i DOS extender permettevano di avviare codice più complesso partendo proprio da questa sezione iniziale.

Lo stesso meccanismo è diventato, di recente, protagonista di una ricerca svolta da una sviluppatrice autonoma – Kamila Szewczyk – che ha realizzato un unico file da 13 KB compatibile con Windows, Linux e browser Web.

Perché il passato continua a influenzare il presente

Mantenere l’header MZ consente quindi di uniformare la lettura dei file eseguibili.

Si potrebbe eliminare completamente il blocco MZ? Tecnicamente sì, ma servirebbe aggiornare specifiche, loader e tool esistenti. Il beneficio reale sarebbe minimo, mentre il rischio di incompatibilità non trascurabile. Microsoft ha sempre privilegiato una compatibilità molto ampia, sia verso il passato sia verso il futuro.

Il risultato è sotto gli occhi di chiunque analizzi un eseguibile moderno: un frammento di codice DOS sopravvive in ogni applicazione Windows, anche sui sistemi a 64 bit. Non serve più allo scopo originale, ma continua ad assicurare stabilità agli strumenti che usiamo ogni giorno, piuttosto che introdurre complessità inutile.

Ti consigliamo anche

Link copiato negli appunti