Search code examples
windowsdllwindbgportable-executabledll-injection

How loader find exact location of an exported function from a dll?


I open a binary in the PEView. There is a table which is called Import Name Table under .rdata section of the binary. This table show me imported functions from different DLLs but there is a field in this table which is called DATA. This field has following values which you can see them in the photo. for example 2596 for GetCurrentProcessID.

enter image description here

View of the above information from Windbg perspective:

enter image description here

But when our binary get loaded in the memory completely, this value (2596) changed with another VA which you can see in the following photo.

enter image description here

However, I couldn't understand what this value is at all? and also How hint value is used by loader to find out exact location of an exported function from a DLL? Could some explain this step by step practically (for example, in windbg?).


Solution

  • A PE file contains two lists of imports, the lookup table and the address table (IAT). The RVAs to these are in IMAGE_IMPORT_DESCRIPTOR. Technically I believe it is allowed to only have a single table, older Borland tools might do this if I remember correctly. The imports cannot be bound with only one table.

    The lookup table entries are pointer sized values that contains the ordinal or a RVA to a forward or a RVA to the hint and function name. The IAT entries contain the same values, or if bound, the actual address of the exported function.

    When the PE file is loaded the loader replaces the entries in the IAT with the real address of the imported function. The other table is not changed.

    The loader has 4 ways of resolving the imported function addresses:

    1. If the imports are bound, the timestamp matches and the imported library loaded at its preferred address, the loader is finished without doing any work. Meaning, the IAT that was filled at compile time with addresses from the .lib file perfectly matches the imported library that was loaded at run-time.
    2. If importing by ordinal it can find the address directly without searching for names.
    3. Using the hint. If the hint matches the export, it uses this shortcut without searching the names. The hint is simply a way to look at a specific slot in the exported names table. If the hint does not match, it continues to step 4.
    4. Search the exported names table to find the functions index. The names table is sorted so the loader can perform a binary search.

    When you see disassembly like call DWORD PTR [_imp_Xyz] you are looking at code that calls an imported function and the real address is read from the IAT.