Panther Coder
Panther Coder

Reputation: 1078

Why is the MZ DOS Header Signature 0x54AD in PE files?

I have recently started with the PE(Portable Executable) file format, more specifically PE/COFF. I was reading a tutorial by Randy Kath here.

When I was reading through the structure of MZ DOS header, I found that MZ DOS header was verified using the signature in e_magic field. The structure is as follows:

typedef struct _IMAGE_DOS_HEADER {  // DOS .EXE header
    USHORT e_magic;         // Magic number
    USHORT e_cblp;          // Bytes on last page of file
    USHORT e_cp;            // Pages in file
    USHORT e_crlc;          // Relocations
    USHORT e_cparhdr;       // Size of header in paragraphs
    USHORT e_minalloc;      // Minimum extra paragraphs needed
    USHORT e_maxalloc;      // Maximum extra paragraphs needed
    USHORT e_ss;            // Initial (relative) SS value
    USHORT e_sp;            // Initial SP value
    USHORT e_csum;          // Checksum
    USHORT e_ip;            // Initial IP value
    USHORT e_cs;            // Initial (relative) CS value
    USHORT e_lfarlc;        // File address of relocation table
    USHORT e_ovno;          // Overlay number
    USHORT e_res[4];        // Reserved words
    USHORT e_oemid;         // OEM identifier (for e_oeminfo)
    USHORT e_oeminfo;       // OEM information; e_oemid specific
    USHORT e_res2[10];      // Reserved words
    LONG   e_lfanew;        // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

and the tutorial says :

All MS-DOS-compatible executable files set this value to 0x54AD, which represents the ASCII characters MZ.

My question is the same.

The ascii value of M and Z is 77 and 90 respectively, which translates to 4D and 5A in hexadecimal. How does 0x54AD represent MZ?

It may be a silly question. But do help me understand if its too silly.

Thanks.

Upvotes: 3

Views: 6250

Answers (1)

Govind Parmar
Govind Parmar

Reputation: 21532

First off, the source that claims the signature is 0x54AD is wrong; MZ in hex is actually 0x5A4D (for little-endian architectures), as evidenced by the output of this program:

#include <Windows.h> // for the USHORT type
#include <stdio.h>

int main()
{
    USHORT MZ = ('M' | 'Z' << 8);
    printf("0x%.4hX\n", MZ);
    return 0;
}

Output:

0x5A4D

You might still have the question, why does the byte for 'Z' (5A) come first when the signature is actually 'MZ'?

This is to do with endianness, which is the order in which bytes are stored in individual halfwords, words, doublewords, and so on.

Big-endian stores bytes with the most significant byte in the highest memory address, and little-endian is the opposite, storing the most significant byte in the least significant memory address.

The x86 and x64 architectures are little-endian, so the most significant byte in MZ (i.e. the Z) comes first.

Upvotes: 1

Related Questions