不,ForwarderChain in Import directory 与此无关。
当加载程序从一些 PE 导入解析 kernel32.DecodePointer - 它认为它指向 kernel32.dll的 inside IMAGE_EXPORT_DIRECTORY 的某个地址> - 这就是所谓的转发导出。在这种情况下,加载程序理解 kernel32.DecodePointer 不是指向代码,而是指向 somedll.somefunction 或 somedll.#someordinal 形式的 string结果加载器尝试加载 somedll 并按名称搜索 somefunction 或按序号搜索 someordinal。这个搜索如何查看可以(如果前向导出是)递归的。当我们终于得到函数地址 not inside IMAGE_EXPORT_DIRECTORY 时它停止了 - 这个地址将被存储在 IAT 或进程失败 - 我们在这个 dll 中找不到 dll/或导出.
注意这里的分隔符(在 dll 和 function 名称之间 - 不是 ! 而是 .)有趣的问题 - 如果 somedll 以自己的名字包含. - 比如说my.x64.dll。旧版本的 Windows 不正确的进程名称像这样 (my.x64.dll.somefunc) 因为它在字符串中搜索 first . strchr - 所以会搜索 @ my dll 中的 987654340@ 并失败。但现在这是固定的 - 加载程序使用strrchr - 他在字符串中搜索最后一个.。
因此,我们无法每年指定完整的 dll 名称和扩展名 -
#pragma comment(linker, "/export:fn=kernel32.dll.DecodePointer");
GetProcAddress((HMODULE)&__ImageBase, "fn");
在 xp 上说失败。但是现在-确切地说是win10,可能是win8.1(需要检查)这是正确的并且可以工作-xp将在kernel32中搜索dll.DecodePointer,而win10在kernel32.dll中搜索DecodePointer。也从这里指出,早期我们不能在没有.dll 扩展名的情况下将导出转发到模块,现在 - 没有这样的限制。 (加载程序默认附加 .DLL 后缀到加载的库名称,如果它不包含. - 所以当调用LoadLibrary("my") - 实际上将打开并加载"my.DLL",但对于@ 987654354@ 或 "my.x64" 后缀 .DLL 将不会被附加(. char in name))
所以,如果返回您的具体示例 - kernel32.DecodePointer 指向 kernel32.dll 的 IMAGE_EXPORT_DIRECTORY 内部的内容。加载器通过这个地址读取字符串 - NTDLL.RtlDecodePointer - 在这个字符串上调用strrchr(或strchr旧版本)以查找.,最后加载NTDLL -> NTDLL.DLL(添加后缀是因为名称中没有 .)并搜索 RtlDecodePointer - 找到地址,但它不在 ntdll.dll 的 IMAGE_EXPORT_DIRECTORY 内 - 所以这是代码地址。这里进程停止,RtlDecodePointer 的地址存储在初始 PE IAT 中。
您需要重复加载程序步骤。但是现代操作系统中存在一个问题 - 许多字符串以API-MS-* dll 名称开头。这不是真正的 dll,而是 The API Set Schema - 未记录且可变的方式,加载程序如何解析这些名称