0

我编写了以下非常简单的程序:

#include <Windows.h>
#include <stdio.h>

int wmain(void) {
    DWORD dwProcId = GetCurrentProcessId();
    HANDLE hProc = OpenProcess(0x0400, FALSE, dwProcId);
    wprintf(L"Process handle is %p\n.", hProc);

    return 0;
}

当我在 x64dbg(或任何其他调试器)上打开它时,我可以看到 IAT 位于该.rdata部分的开头,它确实包括我使用的函数,GetCurrentProcessIdandOpenProcess和其他函数。

然而,在接近正文部分的末尾,我看到了这段代码,它似乎也像一个跳转表: 这个表是什么?

我可以看到似乎被称为 IAT 的函数也被导入,但在我阅读的任何 PE 指南中都找不到对该表的任何引用。

这个表是什么,我如何通过 PE 部分或结构以某种方式以编程方式引用它?

4

1 回答 1

0

这个表确实叫跳表。请记住,当您编译代码时,编译器对内存中的外部符号(如 GetCurrentProcessId)的地址一无所知。因此调用的操作码类似于 0xE8 00000000(E8 是调用的操作码,但您可以看到地址为空)。但是,编译器会在目标文件中创建一个符号表,这对链接器(例如,Microsoft 链接器)非常有用。

当您链接代码时,链接器会读取符号表并读取所有外部符号(如 API 调用),然后通常在 .text 部分的末尾创建一个跳转表(如您所拥有的)。跳转表的形式为:

jmp dword ptr ds:[Address of the FirstThunk in IMAGE_IMPORT_DESCRIPTOR]

然后,链接器修改call代码中的所有指令以调用跳转表中的相应条目。

当您将二进制文件加载到内存中时,加载程序(例如,Windows 加载程序)负责在您的导入表中使用适当的值填充 FirstThunk 字段。

通过这种方法以及编译器、链接器和加载器之间的协作,您可以成功地使用外部 API 和函数。您可以阅读这篇文章以更好地了解跳转表。

如何通过 PE 部分或结构以某种方式以编程方式引用它?

我不认为你可以。此表是 .text 部分的一部分,标题中没有关于它的信息。但是,在普通的 PE 文件中(未打包或混淆),您可以反汇编 .text 部分(甚至无需将二进制文件加载到内存中),并以 0xFF25XXXXXXXX 的形式查找所有指令,其中 XXXXXXXX 是其中之一您的 IMPORT_IMAGE_DESCRIPTOR 中的 FirstThunks。

于 2021-10-15T08:25:32.273 回答