打印由 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
时,存储在指针中的地址会前进 N
个 T
元素 - 即 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 字节数据类型的指针,例如 BYTE
或 char
.
因此,在您的示例中,要将基地址 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));
我真的不明白为什么会这样。除此以外,我能够正确解析大多数 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
时,存储在指针中的地址会前进 N
个 T
元素 - 即 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 字节数据类型的指针,例如 BYTE
或 char
.
因此,在您的示例中,要将基地址 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));