


Import Directory
The next index in the data directory, IMAGE_DIRECTORY_ENTRY_IMPORT, is reserved for the import directory of an executable/DLL. The RVA in this data directory entry points to the import directory, which is nothing but a variable-sized array of IMAGE_IMPORT_DESCRIPTORs, one for each imported DLL. The first field in this structure is a union. If the Characteristics field in this union is 0, it indicates the end of the variable-sized import descriptors array. Otherwise, the union is interpreted using the other member, OriginalFirstThunk.
| OriginalFirstThunk | This is an RVA of what Microsoft calls as the Import Lookup Table (ILT). Each entry in the ILT is a 32-bit number. If the MSB of this number is set, it is treated as an import by ordinal. The bits 0 through 30 are treated as the ordinal of the imported function. If the MSB is not set, the number is treated as an RVA to the IMAGE_IMPORT_BY_NAME structure. The first member of this structure is a hint for searching for the imported name in the export directory of the imported DLL. The loader uses this hint as the starting index in the export-names array when it does a binary search while resolving the import reference. The hint is followed by an ASCIIZ name of the import reference. |
The WINNT.H file provides the IMAGE_SNAP_BY_ORDINAL macro to determine whether its an import by ordinal. It also provides the IMAGE_ORDINAL macro to get the ordinal from the 32-bit number in the ILT. The ILT is a variable-sized array. The end of the ILT is marked with a 0.
The other members in the IMAGE_IMPORT_DESCRIPTOR structure are as follows:
| TimeDateStamp | This field is set to 0, unless the imports are bound. Soon, we discuss whats meant by binding the imports of a PE file. |
| ForwarderChain | The field is used only if the imports are bound. |
| Name | RVA of the ASCIIZ string that stores the name of the imported DLL. |
| FirstThunk | RVA of the Import Address Table (IAT). The IAT is another array parallel to the ILT, unless the image is bound. The IAT also has ordinals or pointers to the IMAGE_IMPORT_BY_NAME structures. When the loader resolves the import references, it replaces the entries in the IAT with the actual addresses of the corresponding functions. Astonishingly, that is all it needs to do to achieve dynamic linkingeverything else is already set in place by the linker and import librarian. Lets see how all these components work together to achieve dynamic linking. |
DYNAMIC LINKING WITH PE FILES
Every DLL has an import library that can either be created using an import librarian or may be generated by the linker itself while creating the DLL. The import library has stub functions with names the same as those of the functions exported from the DLL. The import library also has a .idata section containing an import table that has entries for all the functions from the DLL. Each stub function is an indirect jump that refers to the appropriate entry in the IAT in the .idata section. When an executable is linked with the import library, the linker resolves the imported function calls to the stub functions in the import library. The linker also concatanates the .text section from the import library that contains the stub functions with the .text section of the generated executable. The .idata sections and, incidentally, the import directories are also concatenated. The stage is now set for loading. While loading, the entries in the IAT are replaced by the actual function addresses, and thats it. Now when the function is called, the control is transferred to the stub function that performs an indirect jump. As the IAT entry contains the address of the actual function from the DLL, the control is transferred to the required function.
The situation is a bit different if you use the new __declspec(dllimport) directive while prototyping an imported function. In that case, the compiler itself generates an import table. In addition, it generates an indirect call referring to the appropriate location in the generated IAT. This method does away with the overhead of an extra jump.
BINDING IMPORTS FOR A PE FILE
A major portion of loading time is spent on resolving the imports. The loader has to search each imported symbol in the export directory of the imported DLL to find out the virtual address of the symbol. The loading time can be drastically reduced if the IAT contains the actual address of the symbol instead of the name or ordinal. Such a PE file is called as a bound image. The imported symbol addresses are calculated assuming that the imported DLL will be loaded at the preferred base address at the time of loading. The IMAGE_IMPORT_DESCRIPTORs, in a bound PE file, are also modified. The TimeDateStamp field stores the timestamp of the imported DLL. At the time of loading, if this timestamp does not match with that of the DLL, the imports need to be resolved again. Because the IAT is modified and does not contain the symbol names or ordinals, the ILT is used, in this case, to resolve the imports.
The forwarded functions pose another problem with binding. The addresses of the forwarded functions cannot be calculated at bind time, and so these functions have to be resolved at load time. A list of all the forwarded functions for an imported DLL is maintained through the ForwarderChain member in the corresponding IMAGE_IMPORT_DESCRIPTOR. This member stores the index of a forwarded function in the IAT. The IAT entry at this index stores the index of the next forwarded function, and so on, forming a list of forwarded functions. The list is terminated by a –1 entry.
BindImage()
The bind utility that is shipped with Win32 SDK enables binding of PE files. Also, the BindImage and BindImageEx() functions in the IMAGEHLP.DLL provide this functionality.
BOOL BindImage(
LPSTR ImageName,
LPSTR DllPath,
LPSTR SymbolPath
);
PARAMETERS
| ImageName | The filename of the file to be bound. This can contain only a filename, a partial path, or a full path. |
| DllPath | A root path to search for ImageName if the filename contained in ImageName cannot be opened. |
| SymbolPath | A root path to search for the corresponding symbol file. If the symbol file is stored separately, the header of the symbol file is changed to reflect the changes in the PE file. |
RETURN VALUES
If the function succeeds, the return value is TRUE; otherwise, it is FALSE.
BindImageEx()
This function is very similar to BindImage function except it provides more customization such as getting a periodic callback during the progress of binding process.
BOOL BindImageEx(
IN DWORD Flags,
IN LPSTR ImageName,
IN LPSTR DllPath,
IN LPSTR SymbolPath,
IN PIMAGEHLP_STATUS_ROUTINE StatusRoutine
);
PARAMETERS
This function has the following additional parameters:
| Flags | The field controls the behavior of the function. It is set to as an OR of the flag values defined in the IMAGEHLP.H file. The following flag values are defined in the IMAGEHLP.H file: |
| BIND_NO_BOUND_IMPORTS | Do not generate a new import address table. |
| BIND_NO_UPDATE | Do not make any changes to the file. |
| BIND_ALL_IMAGES | Bind all images that are in the call tree for this file. |
| StatusRoutine | Pointer to a status routine. The status routine is called during the progress of the image binding process. |
RETURN VALUES
If the function succeeds, the return value is TRUE; otherwise, it is FALSE.
Calling BindImage is equivalent to calling BindImageEx with Flags as 0 and StatusRoutine as NULL. That is, calling BindImage(ImageName, DllPath, SymbolPath) is equivalent to calling BindImageEx(0, ImageName, DllPath, SymbolPath, NULL).
Resource Directory
The next index in the data directory, IMAGE_DIRECTORY_ENTRY_RESOURCE, refers to the resource directory for a PE file. The resource directory and the resources themselves are generally stored in a section named .rsrc section. The resources are maintained in a tree structure similar to that in a file system. The root directory contains subdirectories. A subdirectory can contain subdirectories or resource data. The subdirectories can be nested to any level. But Windows NT only uses a three-level structure. At each level, the resource directory branches according to certain characteristics of the resources. At the first level, the type of the resourcebitmap, menu, and so onis considered. All the bitmaps are stored under one subtree, all the menus are stored under another subtree, and so on. At the next level, the name of the resource is considered, and the third level classifies the resource according to the language ID. The third-level resource directory points to a leaf node that stores the actual resource data.
A resource directory consists of summary information about the directory followed by the directory entries. Each directory entry has a name or ID that is interpreted as a type ID, a name ID, or a language ID, depending on the level of the directory. A directory entry can point either to the resource data or to a subdirectory that has a similar format.
The format of the resource directory is defined as the IMAGE_RESOURCE_DIRECTORY structure in WINNT.H.
| Characteristics | Currently unused. Set to 0. |
| TimeDateStamp | Date and time when the resource was generated by the resource compiler. |
| MajorVersion, MinorVersion | Can be set by the user. |
| NumberOfNamedEntries | Number of directory entries having string names. These entries immediately follow the directory summary information and are sorted. |
| NumberOfIdEntries | Number of directory entries that use integer IDs as the names. These entries follow the ones having string names. |
This summary information is followed by the directory entries. Each directory has a format as defined by the IMAGE_RESOURCE_DIRECTORY_ENTRY structure in WINNT.H. This structure is composed of two unions. The first union stores the ID of the entry. If the MSB is set, then the lower 31 bits in this field is an RVA of the Unicode string that stores the name of the entry. The Unicode string consists of the length of the string followed by the 16-bit Unicode characters. If the MSB is not set, then the union stores the integer ID of the resource. This first union stores the type ID, the name ID, or the language ID, depending on the level of the directory. The second union, in the IMAGE_RESOURCE_DIRECTORY_ENTRY structure, points either to another resource directory or to the resource data, depending on the MSB. If the bit is set, the lower 31 bits is an RVA of another subdirectory. If the MSB is not set, then its an RVA of the resource data entry that forms a leaf node of the resource directory tree structure. The format of the resource data entry is defined as the IMAGE_RESOURCE_DATA_ENTRY structure in the WINNT.H file and has following members:
| OffsetToData | RVA of the actual resource data. |
| Size | Size of the resource data. |
| CodePage | Code page used to decode code point values within the resource data. Typically, the code page would be the Unicode code page. |
|
Page: 1, 2, 3, 4, 5, 6 |
next page  |
|
|
|
|