重定向到其他库的导出

逆向工程 拆卸 C 聚乙烯 可执行
2021-07-02 07:21:31

我正在写一个GetProcAddress函数的模拟当查看导出表时,我在 advapi32.dll 中看到了这样的导出,例如:

.text:4C362BAA aEventregister  db 'EventRegister',0    ; DATA XREF: .text:off_4C35FE10o
.text:4C362BB8                                         ; Exported entry 1290. EventRegister
.text:4C362BB8                 public EventRegister
.text:4C362BB8 EventRegister   db 'ntdll.EtwEventRegister', 0

所以它就像一个重定向到 ntdll 函数。如何处理这些条目以及如何检测它们是否导致另一个库调用?

目前我只是按名称查找函数序号并获取其地址,但对于像这样的导出地址是无效的(地址内有垃圾代码)。

我是否需要只读取ntdll.EtwEventRegister序号地址处的字符串,将其按点分割并获取 dll/函数名称?

如果是这种情况,我如何检测导出地址只是带有此 dll/函数名称的字符串?我需要以某种方式检查那里是否存在有效字符串,应该有其他方式,例如某些标志等。

3个回答

这称为导出转发,您可以在此处进行很好的解释:

PE文件格式

下一个 32 位值“AddressOfFunctions”是导出项目列表的 RVA。它指向一个 'NumberOfFunctions' 32 位值数组,每个值都是导出函数或变量的 RVA。

这个列表有两个怪癖:首先,这样一个导出的 RVA 可能是 0,在这种情况下它是未使用的。其次,如果 RVA 指向包含导出目录的部分,则这是转发导出。转发的导出是指向另一个二进制文件中的导出的指针;如果使用它,则使用另一个二进制文件中的指向导出。如前所述,在这种情况下,RVA 指向导出目录的部分,指向一个以零结尾的字符串,该字符串包含指向的 DLL 的名称和由点分隔的导出名称,如“otherdll.exportname”,或 DLL 的名称和导出序号,如“otherdll.#19”。

其他两个答案是错误的。我反过来说link.exe,它的工作方式是,如果“函数”指向导出目录 ( NTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress <= func_ptr < NTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + NTHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size),则它是一个转发导出(即您会在那里找到一个字符串)。

其他两个答案中的方法曾经有效,因为链接器过去常常将导出目录和前向字符串放入该.data部分,但情况已不再如此。较新的链接器将导出目录和前向字符串放入该.text部分(所有“实际”函数也驻留在该部分中),因此检查“函数”是否与导出目录位于同一部分将不再起作用。

简短回答:不,您不必猜测它是一个字符串。有个“窍门”。

但首先,一些背景:导出转发是一个合法且有用的功能块。有一些文档描述了 PE 加载器如何加载导入,不幸的是导出转发文档有点难以获得,而且大多数文章只提到了导出转发。

确定您是否正在处理导出转发的关键是,这里描述

转发是通过使 AddressOfFunctions 数组中的 RVA 指向包含导出目录的部分来实现的,这是正常导出不应该做的。在该位置,应该有一个格式为“LibraryName.ExportName”的以零结尾的 ASCII 字符串,用于将此导出转发到的适当位置。

如果 AddressOfFunctions 数组中的 RVA 指向exports 部分,则该函数将被转发并且无法位于正在加载的DLL 中。相反,指向的值应该被解释为以空字符结尾的字符串,应该加载另一个模块,并且应该重复加载过程。

如果点后面跟着散列符号,则前向入口指向按序数导出的导出,而不是名称,散列符号后面的数字是目标函数的序数。

请注意,一个 API 在到达之前可能会被多次转发。

此外,如果您正在处理绑定导入,则应确保ForwarderChain正确处理,请参阅同一篇文章中的以下内容:

如果绑定的库/模块将其导出转发到另一个模块,则绑定当然可能是一个问题。在这些情况下,可以绑定非转发的导入,但必须识别转发的值,以便加载程序可以解析它们。这是通过导入描述符的 ForwarderChain 成员完成的。“ForwarderChain”的值是 FirstThunk 和 OriginalFirstThunk 数组的索引。该索引的 OriginalFirstThunk 标识需要解析的导入的 IMAGE_IMPORT_BY_NAME 结构,该索引的 FirstThunk 是需要解析的另一个条目的索引。这种情况一直持续到 FirstThunk 值为 -1,表示不再有要导入的转发值。

要额外阅读有关 PE 格式和特别是导入的内容,我推荐资源。