我正在写一个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 /函数名称的字符串?我需要以某种方式检查那里是否有一个有效的字符串,应该有其他方式,例如一些标志等。

#1 楼

这称为导出转发,您可以在此处进行详细解释:

PE文件格式


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

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


评论


此解决方案不适用于所有DLL。请参阅我的答案,以了解识别远期出口的正确方法。

–user2347953
19年4月10日在14:38

#2 楼

其他两个答案是错误的。
我颠倒了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部分(所有“实际”功能也都位于其中),因此检查“功能”是否与导出目录位于同一部分中将不再起作用。

#3 楼

简短的回答:不,您不必猜测它是一个字符串。

但是首先,要有一些背景:导出转发是合法且有用的功能。不幸的是,有一些文档描述了PE加载程序如何加载导入文件,但是出口转发文档却很难获得,大多数文章只提到了出口转发。

确定您是否需要重新处理导出文件的过程如下:


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


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

如果点后面带有井号,则前向条目按序号而不是名称指向导出,并且井号后面的数字是目标函数的序号。

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

此外,如果要处理绑定的进口商品,则应确保正确对待ForwarderChain,请参阅同一文章的以下内容:


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


有关PE格式(尤其是导入)的更多信息,我建议使用此资源。 >