Reputation: 1078
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
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