I'm working on a PE dissector and came across something rather unusual. The names and order of directories in the PE format seem to differ depending on where you look:
From PEReader (perdr):
#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
#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
In PEInfo (corrected to 0-base):
0 Export
1 Import
2 Resource
3 Exception
4 Security
5 Base Reloc
6 Debug
7 Copyright
8 Global Ptr
9 TLS
10 Load Config
11 Bound Import
12 IAT
13 COM
14 Delay Import
15 (reserved)
In CFF Explorer:
0 Export
1 Import
2 Resource
3 Exception
4 Security
5 Relocation
6 Debug
7 Architecture
8 (reserved)
9 TLS
10 Configuration
11 Bound Import
12 IAT
13 Delay Import
14 .NET MetaData
From WINE's winnt.h:
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */
#define IMAGE_DIRECTORY_ENTRY_TLS 9
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11
#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
Here they are as a table:
+------+-------------------+-------------------+-------------------+-------------------+
| Dir# | WINE's winnt.h | PEReader | PEInfo | CFF Explorer |
+------+-------------------+-------------------+-------------------+-------------------+
| 0 | Export | Export | Export | Export |
| 1 | Import | Import | Import | Import |
| 2 | Resource | Resource | Resource | Resource |
| 3 | Exception | Exception | Exception | Exception |
| 4 | Security | Security | Security | Security |
| 5 | Relocation | Relocation | Relocation | Relocation |
| 6 | Debug | Debug | Debug | Debug |
| 7 | Copyright | Architecture | Copyright | Architecture |
| 8 | Global Ptr | Global Ptr | Global Ptr | (reserved) |
| 9 | TLS | TLS | TLS | TLS |
| 10 | Load Config | Load Config | Load Config | Load Config |
| 11 | Bound Import | Bound Import | Bound Import | Bound Import |
| 12 | IAT | IAT | IAT | IAT |
| 13 | Delay Import | Delay Import | COM | Delay Import |
| 14 | COM Descriptor | COM Descriptor | Delay Import | .NET MetaData |
| 15 | - | - | (reserved) | - |
+------+-------------------+-------------------+-------------------+-------------------+
The numbering and order of these seems to not match properly. In both PEReader and winnt.h, entry 14 is COM Descriptor, but in CFF Explorer this shows as .NET MetaData. The COM and Delay Import entries seem to get switched around too.
It seems odd that several of these tools would get this wrong. Which one is correct? Am I missing a newer definition?
As a matter of fact, directory order is fixed, as defined in winnt.h. Even the COM, Delay Import and .NET Metadata have a fixed position in the directory table! Some tools show the directories with their own names and order. The way that is represented has nothing to do with the PE specification.
The PE specs are documented by MS, your best bet is the info they provide in pecoff.doc:
http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx
The last entry is described as CLR Runtime Header, if I remember correctly it used to have a different meaning (that's why some call it COM Descriptor) but is now used to point to the CLR metadata.
The order of the last three is IAT, DelayImport, CLR. Anything else is simply wrong, the directories obviously don't magically shift around.
You don't have to use anything undocumented. The correct one are found in the WinNT.h file that comes with the Windows SDK (once installed, on my machine it's in C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include):
The WINE & PEReader definitions just (correctly I believe) borrow from this .h file.
There is also a mention here: ImageDirectoryEntryToDataEx function