打印由 PE(64 位)导入的 DLL

Printing the DLLs imported by a PE (64 bit)

我真的不明白为什么会这样。除此以外,我能够正确解析大多数 PE 格式。我正在尝试打印特定 PE 使用的所有 DLL。

首先我从数据目录中获取 ImportTable:

IMAGE_DATA_DIRECTORY importDir = (IMAGE_DATA_DIRECTORY)peHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];

然后我将它的地址添加到我映射它的地址,即 MapViewOfFile 返回的地址:

PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
        (PIMAGE_IMPORT_DESCRIPTOR)((ULONG *)pe + importDir.VirtualAddress);

    printf("%s\n", (ULONGLONG *)pe + importDescriptor[0].Name);

由于某种原因,它崩溃了,我该如何处理?

你的指针算法是错误的。 (ULONG *)pe + ...(ULONGLONG *)pe + ... 不要做你认为他们做的事。

当您将指针 T* 前进一个整数 N 时,存储在指针中的地址会前进 NT 元素 - 即 N * sizeof(T) 字节 .

当您将 pe 类型转换为 ULONG* 然后向其添加 importDir.VirtualAddress 时,您正在将 pe 中存储的地址推进 sizeof(ULONG) * VirtualAddress字节数,而不是 VirtualAddress 字节数。

同样,当您将 pe 类型转换为 ULONGLONG* 然后向其添加 importDescriptor[0].Name 时,您会将 pe 中的地址推进 sizeof(ULONGLONG) * Name字节数,而不是Name字节数。

在这种情况下,这不是您想要的。 PE 中的虚拟地址是基地址的绝对偏移量,因此您需要将基地址提前 N 字节,而不是 N 字节的倍数,因此用于此类的任何 T*类型转换需要是指向 1 字节数据类型的指针,例如 BYTEchar.

因此,在您的示例中,要将基地址 pe 提高 N 字节 ,请使用 BYTE* 作为类型演员表,例如:

PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
        (PIMAGE_IMPORT_DESCRIPTOR)(((LPBYTE)pe) + importDir.VirtualAddress);
...
printf("%s\n", (char*)(((LPBYTE)pe) + importDescriptor[0].Name));

或者,您可以使用整数运算而不是指针运算,方法是将您的基地址类型转换为整数,例如 ULONG_PTR(指针大小的 ULONG),例如:

PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
        (PIMAGE_IMPORT_DESCRIPTOR)(((ULONG_PTR)pe) + importDir.VirtualAddress);
...
printf("%s\n", (char*)(((ULONG_PTR)pe) + importDescriptor[0].Name));