加载程序如何从 dll 中找到导出函数的确切位置?

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

我在 PEView 中打开一个二进制文件。在二进制文件的 .rdata 部分下有一个名为 Import Name Table 的 table。 table 向我展示了从不同 DLL 导入的函数,但是 table 中有一个名为 DATA 的字段。该字段具有以下值,您可以在照片中看到它们。例如 GetCurrentProcessID 为 2596。

从Windbg角度看以上信息:

但是当我们的二进制文件完全加载到内存中时,这个值 (2596) 被另一个 VA 改变了,你可以在下面的照片中看到。

但是,我完全看不懂这个值是什么?以及加载程序如何使用提示值从 DLL 中找出导出函数的确切位置?有人可以实际地逐步解释这一点吗(例如,在 windbg 中?)。

一个 PE 文件包含两个导入列表,查找 table 和地址 table (IAT)。这些的 RVA 在 IMAGE_IMPORT_DESCRIPTOR 中。从技术上讲,我相信它只允许有一个 table,如果我没记错的话,旧的 Borland 工具可能会这样做。导入不能只绑定一个 table.

查找 table 条目是指针大小的值,其中包含指向前向的序号或 RVA 或指向提示和函数名称的 RVA。 IAT 条目包含相同的值,或导出函数的 if bound, the actual address

加载 PE 文件时,加载程序将 IAT 中的条目替换为导入函数的真实地址。其他table没变。

loader有4种解析导入函数地址的方式:

  1. 如果导入已绑定,时间戳匹配并且导入的库加载到其首选地址,则加载程序完成而不做任何工作。意思是,在编译时用 .lib 文件中的地址填充的 IAT 与在 run-time.
  2. 处加载的导入库完全匹配
  3. 如果按序号导入,可以直接找到地址,无需搜索名称。
  4. 使用提示。如果提示匹配导出,它会使用此快捷方式而不搜索名称。提示只是一种查看导出名称中特定插槽的方法 table。如果提示不匹配,则继续执行步骤 4。
  5. 搜索导出的名称 table 以查找函数索引。名称 table 已排序,因此加载程序可以执行二进制搜索。

当您看到像 call DWORD PTR [_imp_Xyz] 这样的反汇编时,您正在查看调用导入函数的代码,并且真正的地址是从 IAT 读取的。