Why PE need Original First Thunk(OFT)?

The original first thunk is needed if the imports are bound but the imported .DLL does not match.

On a fresh unpatched version of Windows, all addresses of all functions in the base .DLLs (ntdll, kernel32, user32 etc) are known. Take shell32 for example, it links to kernel32!CreateProcess and the true address of CreateProcess can be stored directly in shell32. This is called import binding and lets the loader skip the step where it looks up all the addresses of the imported functions.

This does not work if the imported .DLL has not been loaded at its preferred address nor if the .DLL has changed (security update etc). If this happens then the loader has to look up the functions "the normal way" and the original first thunk array has to be used because that is the only place where the RVAs of the function names are stored.

If import binding is not used then the original first thunk array is optional and might not be present.

ASLR has probably made this optimization irrelevant.


Let me summarize a lot of things for you here. When you load a Library, for example, Milad.dll and then try to call a function from that like MPrint, dynamic loader of the windows operating system has to resolve the address of the MPrint function and then call it. How can OS resolve the address of that function?

Windows go through some really complicated stuff which I want to tell you those steps with a simple tongue. The dynamic loader of windows OS to resolve the address of the function in DLLs has to check Import Name Table (INT), Import Ordinal Table (IOT) and Import Address Table (IAT) table. These table pointed by AddressOfNames, AddressOfNamesOrdinal and AddressOfFunction member in Export directory a PE structure.

After OS load Milad.dll in address space of target process with help of LoadLibrary, it's going to fill INT, IOT and IAT table with their RVA in target address space of the process with GetProcAddress and doing some calculation.

There is an array of Import Directory in the process structure that has OriginalFirstThunk, TimeDateStamp, ForwarderChain, Name, FirstThunk which these members point to some important addresses.

  1. Name in Import Directory (Image_Import_Data) pointed to the name of the DLL which process tries to call, in this example this DLL is Milad.dll.
  2. OriginalFirstThunk pointed to Import Name Table which includes Names of functions that exported by the Milad.Dll. Functions in this table have a unique index which loader takes that index and go to the next step and reference to Import Ordinal Table with that index and takes the value which there is into that index of Import Ordinal Table which It's another integer value.
  3. FirstThunk is another important member which point to IAT. in the previous step dynamic loader takes an integer value via IOT. this value is an index number which dynamic loader refer to IAT with that value. In this table, there is an address in index value which dynamic loader gets from INT-IOT. After these steps when dynamic loader finds out the correct address of the function, it puts that address to Import Address Table for MPrint function. So the process can call that function with its address.

This is a simple explanation for complicated stuff which loader does to resolve the address of the functions in DLLs via Name, OFT(INT) and FT(IAT) members in Image_Import_Data.


We need to know that when the PE file is loaded into memory, the PE loader will look at the IMAGE_THUNK_DATAs and IMAGE_IMPORT_BY_NAMEs and determine the addresses of the import functions. Then it replaces the IMAGE_THUNK_DATAs in the array pointed to by FirstThunk with the real addresses of the functions. Thus when the PE file is ready to run. The array of RVAs pointed to by OriginalFirstThunk remains unchanged so that if the need arises to find the names of import functions, the PE loader can still find them.