Introduction
The MZ format is the executable format of MS-DOS, used from DOS 2.0 in 1983. It is
named after its first two bytes, MZ, the initials of Mark Zbikowski, one of
its designers. An MZ program is 16-bit x86 code that DOS loads into memory, adjusting
its segment addresses to wherever it landed.
Every later Windows program still begins with an MZ header and a small DOS program,
the stub, which prints a message such as “This program cannot be run in DOS mode”. So
several different formats share the .exe extension and the same first two
bytes. This page is the plain DOS one; see all the
.EXE variations. The smaller DOS programs with no header at all are
.com files.
Structure
The file starts with a header of at least 28 bytes, all little-endian 16-bit words. It gives the file’s size in 512-byte pages, the number of relocations, the header’s own size in 16-byte paragraphs, the memory the program needs, and the starting values of the stack and instruction pointers. The relocation table lists the places in the code that hold segment addresses, so DOS can add the load segment to each one. The program itself, the load module, starts right after the header.
0x00e_magicMZ2 bytes0x02e_cblp, e_cp: bytes in the last page, pages in the file4 bytes0x06e_crlc relocations, e_cparhdr header paragraphs4 bytes0x0Ae_minalloc, e_maxalloc: extra memory needed4 bytes0x0Ee_ss, e_sp, e_csum, e_ip, e_cs10 bytes0x18e_lfarlc relocation table offset, e_ovno overlay number4 bytes…relocation table: offset and segment pairs4 bytes each…load module: the program’s code and datavaries
Telling .EXE files apart
MS-DOS, Windows and OS/2 programs all start with MZ. The newer formats add
a 32-bit offset, e_lfanew, at 0x3C, pointing to a second
header. Read the bytes there:
PE\0\0means a Windows PE program.NEmeans a 16-bit Windows NE program.LEmeans a Linear Executable.LXmeans an OS/2 LX program.- Anything else, or an offset past the end of the file, means a plain MS-DOS program.
Windows linkers set the relocation table offset at 0x18 to
0x40 or more, so many tools check that first: a smaller value means the
bytes at 0x3C belong to the DOS program.