- Joined
- 11 yrs. 8 mth. 23 days
- Messages
- 5,010
- Reaction score
- 11,818
- Wallet
- 13,191$
- [email protected]
The Import Directory: Part 1
Dejan Lukan April 24, 2013
We know that when the operating system loads the executable, it will scan through its IAT table to locate the DLLs and functions the executable is using. This is done because the OS must map the required DLLs into the executable’s address space.
To be more precise, IAT is the table that contains references between the function names and their virtual addresses, which are exported from different loaded modules. Each executable or DLL library contains a PE header, which has all the information that the executable needs for the operating system to start successfully, including the IAT table. To understand where the IAT table is located, we must first talk about the PE header.
Now we’re ready to explore the actual IAT of the process. Let’s first present the program we’ll be using to do that:
When we compile the program, another createfilee.exe executable will be created. We can start the createfilee.exe program and let it run. It will stop the execution on the getchar() function call, which will wait until we press certain keystroke. After that, start the WinDbg debugger and attach it to the process like this:
Now we’ll use the !dh command to print the PE header elements that we need. Let’s first print all the options of the !dh command, which we can see below. If we pass the -a parameter to the !dh command, we’ll be printing everything to the console window. If we use the -f parameter, we’ll print only the file headers and with -s we’ll print only the section headers.
In our case, we’ll use the -f parameter because we need to dump the file headers. The output below was generated by the “!dh 00400000 -f” command:
The output of that command can be seen below (the whole table is presented even though it might be rather long), just so we can observe all the entries in that table:
First, we can see a number of entries from the kernel32.dll library and later there are entries from the msvcr100d.dll library. All the entries that we’re directly using in our C++ code have been marked in bold font.
We’ve just figured out the library names used by the executable, and all the function names plus their virtual addresses in memory. Let’s also print all the loaded modules with the lmi command. The output of that command can be seen below:
The two libraries kernel32.dll and msvcr100d.dll have been bolded to be easily found. Notice that their base addresses are 0×10200000 and 0x7c800000, which correlates with all the functions in the IAT table. All those function pointers are correct, because the OS filled the IAT table with correct function pointers when the executable was loaded.
The Import Directory
The import function is the function that’s not located in the current module, but is imported from some other module, usually from several. The information about the function must be kept in the import directory of the current module because when the operating system loads the executable and memory and starts it, it must also load all the dependent libraries in the process’s memory space, so that the program can call those functions.
The import table contains IMAGE_IMPORT_DESCRIPTOR structures, which has the following members:
Each IMAGE_IMPORT_DESCRIPTOR element structure in the import directory contains information about a DLL the current module needs in order to reference its symbols and call its functions. The array will always contain another terminating structure, which has its members initialized to zero.
At the beginning of the IMAGE_IMPORT_DESCRIPTOR, we can see a union data structure being used. Union variables occupy the same memory and are normally used to specify that certain variable can have different variable types. In our case, both variables, the Characteristics and OriginalFirstThunk, have the same variable type DWORD, so the union declaration is only used to make an alias for both of those members.
Remember that the union declaration occupies only 4 bytes in our case (which is the size of the DWORD type) and not 8 bytes; this is how the union declarations work. Because of this, the size of IMAGE_IMPORT_DESCRIPTOR data structure is 20 bytes: 4 bytes for the union declaration and 16 bytes for the TimeDateStamp, ForwarderChain, Name and FirstThunk elements.
We haven’t yet mentioned what the elements of the structure actually mean. This is why we’re describing them below:
OriginalFirstThunk: this element contains the RVA to the IMAGE_THUNK_DATA structure, which we can see below:
We can see that the IMAGE_THUNK_DATA structure is a union structure, which is 4-bytes in size. When we come to this structure, we must remember that a function can be imported by name or by ordinal. In the case of a latter, the Ordinal field of the union in IMAGE_THUNK_DATA structure will have the most significant, but set to 1 and the ordinal number can be extracted from the least significant bits.
The structure actually contains a pointer to the array of RVAs that point to the IMAGE_IMPORT_BY_NAME structures, terminated by 0. Let’s look at how the IMAGE_IMPORT_BY_NAME structure look, which can be seen below:
There are two elements inside the structure:
Hint: this field is not of particular importance.
Name: contains the name of the import function; the field is actually a variable-sized pointer to the string.
Keep in mind that the OriginalFirstThunk will contain as many elements as is the number of imported functions for a particular library. Each imported function name represents one element in the array.
TimeDateStamp
ForwarderChain
Name: contains the RVA address where the name of the library is saved.
FirstThunk: contains the RVA to the array of IMAGE_THUNK_DATA structures, like the OriginalFirstThunk above. Both arrays contain the same number of elements. The OriginalFirstThunk is an array of names of imported functions, also called the ILT. The FirstThunk is an array of addresses of imported functions, also called the IAT.The OriginalFirstThunk uses the AddressOfData element of the IMAGE_THUNK_DATA structure, which points to another structure that contains the Name element of the library. The FirstThunk uses the Function element of the IMAGE_THUNK_DATA structure, which points to the address of the imported function. When the executable is loaded, the loader must traverse the OriginalFirstThunk array to find all the imported function names the executable is using. Then it must calculate the addresses of the functions and populate the FirstThunk array, so that the functions can be called whenever needed.
Conclusion
To conclude, the Import Table contains one entry for each DLL we’re importing from. Each entry contains Import Lookup Table (ILT) and Import Address Table (IAT) pointers [7]. If we would like to go over the whole PE file structure, there’s a great picture available at , which was provided by the OpenRCE team.
References:
[1] Import Address Table, accessible at .
[2] Dynamic-link library, accessible at .
[3] CreateFile function, accessible at .
[4] Linker Options, accessible at .
[5] PE File Structure, accessible at .
[6] Tutorial 6: Import Table, accessible at .
[7] What’s the difference between “Import Table address” and “Import Address Table address” in Date Directories of PE?, accessible at .
sursa:
Dejan Lukan April 24, 2013
We know that when the operating system loads the executable, it will scan through its IAT table to locate the DLLs and functions the executable is using. This is done because the OS must map the required DLLs into the executable’s address space.
To be more precise, IAT is the table that contains references between the function names and their virtual addresses, which are exported from different loaded modules. Each executable or DLL library contains a PE header, which has all the information that the executable needs for the operating system to start successfully, including the IAT table. To understand where the IAT table is located, we must first talk about the PE header.
Now we’re ready to explore the actual IAT of the process. Let’s first present the program we’ll be using to do that:
When we compile the program, another createfilee.exe executable will be created. We can start the createfilee.exe program and let it run. It will stop the execution on the getchar() function call, which will wait until we press certain keystroke. After that, start the WinDbg debugger and attach it to the process like this:

Now we’ll use the !dh command to print the PE header elements that we need. Let’s first print all the options of the !dh command, which we can see below. If we pass the -a parameter to the !dh command, we’ll be printing everything to the console window. If we use the -f parameter, we’ll print only the file headers and with -s we’ll print only the section headers.

In our case, we’ll use the -f parameter because we need to dump the file headers. The output below was generated by the “!dh 00400000 -f” command:
The output of that command can be seen below (the whole table is presented even though it might be rather long), just so we can observe all the entries in that table:
First, we can see a number of entries from the kernel32.dll library and later there are entries from the msvcr100d.dll library. All the entries that we’re directly using in our C++ code have been marked in bold font.
We’ve just figured out the library names used by the executable, and all the function names plus their virtual addresses in memory. Let’s also print all the loaded modules with the lmi command. The output of that command can be seen below:
The two libraries kernel32.dll and msvcr100d.dll have been bolded to be easily found. Notice that their base addresses are 0×10200000 and 0x7c800000, which correlates with all the functions in the IAT table. All those function pointers are correct, because the OS filled the IAT table with correct function pointers when the executable was loaded.
The Import Directory
The import function is the function that’s not located in the current module, but is imported from some other module, usually from several. The information about the function must be kept in the import directory of the current module because when the operating system loads the executable and memory and starts it, it must also load all the dependent libraries in the process’s memory space, so that the program can call those functions.
The import table contains IMAGE_IMPORT_DESCRIPTOR structures, which has the following members:

Each IMAGE_IMPORT_DESCRIPTOR element structure in the import directory contains information about a DLL the current module needs in order to reference its symbols and call its functions. The array will always contain another terminating structure, which has its members initialized to zero.
At the beginning of the IMAGE_IMPORT_DESCRIPTOR, we can see a union data structure being used. Union variables occupy the same memory and are normally used to specify that certain variable can have different variable types. In our case, both variables, the Characteristics and OriginalFirstThunk, have the same variable type DWORD, so the union declaration is only used to make an alias for both of those members.
Remember that the union declaration occupies only 4 bytes in our case (which is the size of the DWORD type) and not 8 bytes; this is how the union declarations work. Because of this, the size of IMAGE_IMPORT_DESCRIPTOR data structure is 20 bytes: 4 bytes for the union declaration and 16 bytes for the TimeDateStamp, ForwarderChain, Name and FirstThunk elements.
We haven’t yet mentioned what the elements of the structure actually mean. This is why we’re describing them below:
OriginalFirstThunk: this element contains the RVA to the IMAGE_THUNK_DATA structure, which we can see below:

We can see that the IMAGE_THUNK_DATA structure is a union structure, which is 4-bytes in size. When we come to this structure, we must remember that a function can be imported by name or by ordinal. In the case of a latter, the Ordinal field of the union in IMAGE_THUNK_DATA structure will have the most significant, but set to 1 and the ordinal number can be extracted from the least significant bits.
The structure actually contains a pointer to the array of RVAs that point to the IMAGE_IMPORT_BY_NAME structures, terminated by 0. Let’s look at how the IMAGE_IMPORT_BY_NAME structure look, which can be seen below:

There are two elements inside the structure:
Hint: this field is not of particular importance.
Name: contains the name of the import function; the field is actually a variable-sized pointer to the string.
Keep in mind that the OriginalFirstThunk will contain as many elements as is the number of imported functions for a particular library. Each imported function name represents one element in the array.
TimeDateStamp
ForwarderChain
Name: contains the RVA address where the name of the library is saved.
FirstThunk: contains the RVA to the array of IMAGE_THUNK_DATA structures, like the OriginalFirstThunk above. Both arrays contain the same number of elements. The OriginalFirstThunk is an array of names of imported functions, also called the ILT. The FirstThunk is an array of addresses of imported functions, also called the IAT.The OriginalFirstThunk uses the AddressOfData element of the IMAGE_THUNK_DATA structure, which points to another structure that contains the Name element of the library. The FirstThunk uses the Function element of the IMAGE_THUNK_DATA structure, which points to the address of the imported function. When the executable is loaded, the loader must traverse the OriginalFirstThunk array to find all the imported function names the executable is using. Then it must calculate the addresses of the functions and populate the FirstThunk array, so that the functions can be called whenever needed.
Conclusion
To conclude, the Import Table contains one entry for each DLL we’re importing from. Each entry contains Import Lookup Table (ILT) and Import Address Table (IAT) pointers [7]. If we would like to go over the whole PE file structure, there’s a great picture available at , which was provided by the OpenRCE team.
References:
[1] Import Address Table, accessible at .
[2] Dynamic-link library, accessible at .
[3] CreateFile function, accessible at .
[4] Linker Options, accessible at .
[5] PE File Structure, accessible at .
[6] Tutorial 6: Import Table, accessible at .
[7] What’s the difference between “Import Table address” and “Import Address Table address” in Date Directories of PE?, accessible at .
sursa: