为什么PE需要Original First Thunk(OFT)?

Why PE need Original First Thunk(OFT)?

有"First Thunk"(FT),loader执行后用正确的地址覆盖

但是PE什么时候用OFT呢?

PE还需要吗?

如果导入已绑定但导入的 .DLL 不匹配,则需要原始第一个 thunk。

在 Windows 的全新未打补丁版本中,基础 .DLL(ntdll、kernel32、user32 等)中所有函数的所有地址都是已知的。以shell32为例,它链接到kernel32!CreateProcess,而CreateProcess的真实地址可以直接存储在shell32中。这称为 import binding 并让加载程序跳过查找导入函数的所有地址的步骤。

如果导入的 .DLL 尚未加载到其首选地址,或者 .DLL 已更改(安全更新等),这将不起作用。如果发生这种情况,加载程序必须查找函数 "the normal way" 并且必须使用原始的第一个 thunk 数组,因为这是唯一存储函数名称 RVA 的地方。

如果不使用导入绑定,那么原始的第一个 thunk 数组是可选的,可能不存在。

ASLR 可能使此优化无关紧要。

这里给大家总结了很多。当您加载库时,例如 Milad.dll 然后尝试从 MPrint 调用函数,windows 操作系统的动态加载器必须解析 MPrint 函数的地址然后调用它. OS 如何解析该函数​​的地址?

Windows 经历了一些非常复杂的事情,我想用简单的语言告诉你这些步骤。 windowsOS动态加载器解析函数在DLL中的地址需要检查Import NameTable(INT),Import OrdinalTable(IOT)和Import Address Table(IAT)table。这些table 由Export 目录中的一个PE 结构的AddressOfNames、AddressOfNamesOrdinal 和AddressOfFunction 成员指向。

在LoadLibrary的帮助下OS加载Milad.dll到目标进程的地址space后,它将用它们的RVA填充INT,IOT和IAT table使用 GetProcAddress 并进行一些计算的进程的目标地址 space。

进程结构中有一个Import Directory数组,有OriginalFirstThunk、TimeDateStamp、ForwarderChain、Name、FirstThunk,这些成员指向一些重要的地址。

    导入目录 (Image_Import_Data) 中的
  1. Name 指向的名称 进程试图调用的 DLL,在这个例子中这个 DLL 是 Milad.dll.
  2. OriginalFirstThunk 指向包含名称的导入名称 Table Milad.Dll 导出的函数的数量。 table 中的函数 有一个唯一的索引,加载器获取该索引并转到下一个 步骤并使用该索引引用 Import Ordinal Table 并采用 Import Ordinal 索引中的值 Table 这是另一个整数值。
  3. FirstThunk是另一个指向IAT的重要成员。在里面 上一步动态加载器通过 IOT 获取整数值。这个 value 是一个索引号,动态加载程序使用该值引用 IAT。 在这个table中,索引值中有一个动态地址 装载机来自 INT-IOT。当动态加载程序完成这些步骤后 找出函数的正确地址,它把那个地址 为 MPrint 功能导入地址 Table。所以进程可以调用 该函数及其地址。

这是对复杂内容的简单解释,加载程序通过 Image_Import_Data 中的名称、OFT(INT) 和 FT(IAT) 成员来解析 DLL 中函数的地址。

我们要知道当PE文件加载到内存中时,PE加载器会查看IMAGE_THUNK_DATAs和IMAGE_IMPORT_BY_NAMEs并确定导入函数的地址。然后它将 FirstThunk 指向的数组中的 IMAGE_THUNK_DATAs 替换为函数的真实地址。因此当PE文件准备就绪时运行。 OriginalFirstThunk 指向的 RVA 数组保持不变,因此如果需要查找导入函数的名称,PE 加载程序仍然可以找到它们。