加载器是否在加载时通​​过检查相应的导出表或在运行时填充 .exe 的 IAT 表?

逆向工程 视窗 x86 修补 补丁反转 x86-64
2021-07-01 11:22:11

我遇到了这个问题:

我们可以使用 IAT 挂钩或内联挂钩来挂钩 Nt 或 Zw 函数吗?

这让我想知道,由于某种原因,我们的目标 PE 在虚拟内存中的 IAT 中没有某些函数,就像上面的问题是 Zw/NtQuerySystemInformation(我仍然不确定为什么这不包含在 IAT 中) ),那么在这种情况下,如果我们想挂钩IAT,是否可以挂钩kernel32.dll或ntdll.dll的导出表并这样做呢?因为我认为这个功能至少必须在那里

所以这让我回到了这个问题,当加载器通过检查导出表将 PE 加载到内存中时,或者当我们的程序使用它时,加载器是否会填充我们的 IAT?因为如果是第一种情况,那么我认为没有办法挂钩导出表吗?

还有谁知道为什么像 ZwQuerySystemInformation 这样的函数没有包含在 IAT 中,但是像 Sleep 和 GetProcAddress 这样的东西呢?

2个回答

PE loader什么时候填IAT?

IAT 在加载时由 PE 加载器 [1] 更新,这称为加载时动态链接,而不是运行时动态链接,在LoadLibrary/GetProcAddress必要时。

挂钩未包含在导入地址表中的 API

实际上有几种方法可以做到这一点,导出地址表挂钩就是其中之一。但是,您的钩子必须在目标应用程序查找您要钩子的 API 之前安装。

在 IAT 中包含 Nt/Zw API

还有谁知道为什么像 ZwQuerySystemInformation 这样的函数没有包含在 IAT 中,但是像 Sleep 和 GetProcAddress 这样的东西呢?

ZwQuerySystemInformation未包含在 IAT 中的唯一原因是您没有告诉链接器为您执行此操作。您需要链接到 ntdll 导入库(在 VS2017 中默认可用),或者您可以构建自己的库。

在我安装mingwclang安装的系统上,我能够从 [2] 中获取代码,删除任何GetProcAddress/LoadLibrary调用并构建它。这给出:

#include <stdio.h>
#include <windows.h>
#include <winternl.h>

int main(void) {
    
    /* load the ntdll.dll */
    PVOID Info;
    /* create the string in the right format */
    UNICODE_STRING filename;
    RtlInitUnicodeString(&filename, L"C:\\temp.txt");

    /* initialize OBJECT_ATTRIBUTES */
    OBJECT_ATTRIBUTES obja;
    InitializeObjectAttributes(&obja, &filename, OBJ_CASE_INSENSITIVE, NULL, NULL);

    /* call NtOpenFile */
    IO_STATUS_BLOCK iostatusblock;
    HANDLE file = NULL;
    NTSTATUS stat = NtOpenFile(&file, FILE_WRITE_DATA, &obja, NULL, NULL, NULL);
    if(NT_SUCCESS(stat)) {
        printf("File successfully opened.\n");
    }
    else {
        printf("File could not be opened.\n");
    }

    getchar();
    return 0;
}

要构建,我使用:

clang -target x86_64-w64-windows-gnu toto.c -o toto.exe -lntdll

然后,IDA Free 7.0允许我们看到它NtOpenFile已成功包含在 IAT 中:

IAT 中的 NTDLL API

参考

[1]:Rootkit 军械库,Bill Blunder,第 11 章,第 480 页

[2]:直接调用NTDLL函数,https ://resources.infosecinstitute.com/calling-ntdll-functions-directly

像睡眠这样的 API 被记录在 sdk 中提供了一个头文件,一个链接库是由 sdk 提供的(windows.h,kernel32.lib)

像 Zwxxx 这样的 api 是内部或高级用户 api,它们或未记录或半记录或记录在内核模式下使用
这些 api 不能被认为是向前兼容或向后兼容的

因此,如果您使用它们,则使用它们的人必须小心谨慎

所以它们被设计为使用加载库动态调用,获取过程地址,将返回转换为类型定义的函数指针。

它们不驻留在 IAT 中或加载程序无法解析它们