The IMAGE_FILE_HEADER structure is introduced in the previous blog. Now we will discuss the complicated structure of "Optional file headers. (For details, refer to the csdn blog from breaksoftware ).
[Cpp]
Typedef struct _ IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
.
.
.
DWORD BaseOfData; // not exist in PE32 +
//
// NT additional fields.
//
DWORD ImageBase;
.
.
.
IMAGE_DATA_DIRECTORY DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, * PIMAGE_OPTIONAL_HEADER32;
Let's take a look at the 64-bit version of the struct www.2cto.com.
[Cpp]
Typedef struct _ IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
.
.
.
DWORD BaseOfCode;
ULONGLONG ImageBase;
.
.
.
IMAGE_DATA_DIRECTORY DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64;
We can see that this 32-bit structure contains two pieces of data: Standard fields and NT additional fields. We can guess that this struct should exist before the first NT operating system, but its content was only under Standard fields (later called Standard domain, later, the NT system added elements under NT additional fields (later called extended domain.
Note that two struct types defined in WinNT. h
[Cpp]
Typedef struct _ IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, * PIMAGE_NT_HEADERS64;
Typedef struct _ IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, * PIMAGE_NT_HEADERS32;
This structure provides the structure layout of the PE File Header, but remember that this is only the layout. Do not assume that the IMAGE_NT_HEADERS32 (64) structure size data is directly copied to the structure object from the PE Header.
[Cpp]
Memcpy (& ImageNTHeader32, lpPEStart, sizeof (IMAGE_NT_HEADERS32); // This is incorrect !!
Why? Because a file may not have complete IMAGE_OPTIONAL_HEADER32 (64) struct object information. The reason is described in "Optional File Header 1". The SizeOfOptionalHeader field in IMAGE_FILE_HEADER specifies the actual length of the "Optional File Header" saved in the file. We should give IMAGE_OPTIONAL_HEADER32 (64) according to this element) object assignment.
Does our file use the IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64 struct? Some people may remember that we introduced the method for judging whether the file is 32-bit or 64-bit in "Optional File Header 1, can we use the result to determine which struct is used? At first, I thought so. Later I found that Microsoft Visual Studio 10.0 \ VC \ lib \ amd64 \ Microsoft on my computer. visualC. STLCLR. the dll file is a 64-bit file, but the IMAGE_OPTIONAL_HEADER32 struct is used !!! Are you surprised! I don't know why Microsoft designed it like this, but I know that it is wrong to determine whether a 64-bit file is used to determine the structure type of the optional file header. How can we determine it?
It is actually marked. Followed by the IMAGE_FILE_HEADER structure, it must be the Magic field of IMAGE_OPTIONAL_HEADER32 (64. If this field is 0x010B, IMAGE_OPTIONAL_HEADER32 (called PE32) is used; if it is 0x020B, IMAGE_OPTIONAL_HEADER32 (called PE32 +) is used ). Remember that PE32 and PE32 + are irrelevant to whether the file is a 32-bit file or a 64-bit file! They are two different concepts! Be sure to distinguish.
[Cpp]
BOOL CGetPEInfo: GetOptionalHeader (){
CHECKOPHEADER ();
GETFILETYPE ();
Size_t unDwordSize = sizeof (DWORD );
Size_t unImgFileHeaderSize = sizeof (IMAGE_FILE_HEADER );
Size_t unImgOpHeaderSize = 0;
LPBYTE lpImgOpHeaderAddr = m_lpPEStart + unDwordSize + unImgFileHeaderSize;
LPVOID lpOpHeaderStart = NULL;
WORD dwOptionHeader = 0;
If (FALSE = SafeCopy (& dwOptionHeader, lpImgOpHeaderAddr, sizeof (WORD ))){
Return FALSE;
}
If (E64Bit = m_eFileType & PE32MAGICNUM = dwOptionHeader ){
// D: \ Microsoft Visual Studio 10.0 \ VC \ lib \ amd64 \ Microsoft. VisualC. STLCLR. dll
// _ ASSERT (FALSE );
}
If (IMAGE_NT_OPTIONAL_HDR32_MAGIC = dwOptionHeader ){
// This format is optional for 64-bit system files.
M_eFileOpType = EOp32;
UnImgOpHeaderSize = sizeof (IMAGE_OPTIONAL_HEADER32 );
LpOpHeaderStart = & m_OptionalHeader32;
}
Else if (IMAGE_NT_OPTIONAL_HDR64_MAGIC = dwOptionHeader ){
M_eFileOpType = EOp32Plus;
UnImgOpHeaderSize = sizeof (IMAGE_OPTIONAL_HEADER64 );
LpOpHeaderStart = & m_OptionalHeader64;
}
Else {
_ ASSERT (FALSE );
Return FALSE;
}
Memset (lpOpHeaderStart, 0, unImgOpHeaderSize );
// Copy the data according to the optional File Header size in the Image File Header
BOOL bSuc = SafeCopy (lpOpHeaderStart, lpImgOpHeaderAddr, m_FileHeader.SizeOfOptionalHeader );
If (bSuc ){
M_dwInfoMask | = OPHEADER;
}
Else {
_ ASSERT (FALSE );
}
If (EOp32 = m_eFileOpType ){
M_dwFileAlignment = m_OptionalHeader32.FileAlignment;
}
Else {
M_dwFileAlignment = m_OptionalHeader64.FileAlignment;
}
Return bSuc;
}
Now we will focus on IMAGE_DATA_DIRECTORY DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]. This array element is described in optional File Header 1, in addition, I also say that the size of the optional File Header depends on the "location" (rather than the number) of the array element. Let me explain it in detail. Let's take a look at Microsoft's statement.
[Cpp]
Typedef struct _ IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY;
# Define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
# Define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
# Define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
# Define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
# Define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
# Define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
# Define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
# Define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
# Define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
# Define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
# Define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
# Define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
# Define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
# Define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
# Define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
# Define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
DataDirectory stores the directory information pointing to "block information", including the offset (except that the IMAGE_DIRECTORY_ENTRY_SECURITY element is relative file offset RA, others are relative virtual first address offset RVA) and the size. If a file contains only three directories, namely, catalog (0), catalog (1), and catalog (5), IMAGE_DIRECTORY_ENTRY_EXCEPTION (2), IMAGE_DIRECTORY_ENTRY_SECURITY (3), and IMAGE_DIRECTORY_ENTRY_SECURITY (4) is filled with 0. Therefore, the size of the optional File Header specified by IMAGE_FILE_HEADER: SizeOfOptionalHeader is the total size of the elements before DataDirectory plus 6 (the last directory IMAGE_DIRECTORY_ENTRY_BASERELOC is located at 5 + 1) * sizeof ). This explains why the size of the optional file header is determined by the directory location rather than the number.
In the next blog, We will detail the meaning of other elements in IMAGE_OPTIONAL_HEADER32 and IMAGE_OPTIONAL_HEADER64.