在this文章中,定义为DWORD VirtualAddress
DWORD PointerToRawData
另外RVA
定义为
和
当前的问题是到达PE文件的import section
。
hFile = CreateFile(..);
hFileMapping = CreateFileMapping(..);
lpFileBase = MapViewOfFile(..);
ImageBase = (PIMAGE_DOS_HEADER)lpFileBase;
PEHeader = (ImageBase + ImageBase->e_lfanew);
现在获取
import table
PIMAGE_OPTIONAL_HEADER PEImageOptionalHeader = &(PEHeader->OptionalHeader);
IMAGE_DATA_DIRECTORY importTable = PEImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
由于
importTable.VirtualAddress
是RVA,为了获得可用的指针,我可以添加图像文件的基础。所以
ImageBase + importTable.virtualAddress
应该可以让我导入部分。 但事实并非如此。为什么? 然后,如果我到达正确的节头(通常为
.idata
)并执行此操作。ImageBase + pointerToSection->PointerToRawData;
上面正确地将我带到
IMAGE_IMPORT_DESCRIPTORS
数组。我知道使用pointerToSection->virtualAddress
而不是上面的PointerToRawData
,将无法正常工作,因为我自己在映射PE文件。现在要获取该项目的
name
,加载的模块取决于该模块,我可以通过再次使用IMAGE_IMPORT_DESCRIPTORS
的name
字段使用指向RVA
的指针。要转换RVA
,我只需要添加ImageBase
即可。 LPSTR libname = (PCHAR)((DWORD)ImageBase+ImageimportDescriptor->Name);
,但是不起作用。为什么要使用?要转换
RVA
,我们只需添加图片的基址。ImageBase+ImageimportDescriptor->Name + pointerToSection->PointerToRawData - pointerToSection->virtualAddress
每次我需要在某个部分中提供一些信息时,我都需要进行此调整
pointerToSection->PointerToRawData - pointerToSection->virtualAddress
为什么需要此调整?
最佳答案
首先,这一行:
PEHeader = (ImageBase + ImageBase->e_lfanew);
是不正确的。
ImageBase
的类型为PIMAGE_DOS_HEADERS
,因此,当您将ImageBase->e_lfanew
添加到DWORD
时,您正在执行pointer arithmetic,即,您要向ImageBase
添加的字节数与(ImageBase->e_lfanew)*sizeof(IMAGE_DOS_HEADERS)
一样多,这不是您想要的字节数。您想要的是将ImageBase->e_lfanew
字节提前到ImageBase
指向的位置。您可以通过执行以下操作来实现:PIMAGE_NT_HEADERS PEheader = (PIMAGE_NT_HEADERS) ((PBYTE)(ImageBase) + dosHeader->e_lfanew);
注意强制转换为
PBYTE
,这使操作逐字节前进。这在处理PE文件时非常常见,因为很多时候您想从指针中前进n个字节,而不是指针所指向的n个数据结构。
在article you refered to中,它甚至在评论中说:
// Ignoring typecasts and pointer conversion issues for clarity...
pNTHeader = dosHeader + dosHeader->e_lfanew;
现在到您关于
VirtualAddress
和PointerToRawData
的问题:由于以下原因,
ImageBase + importTable.virtualAddress
行也不正确:PE加载程序不会像在文件映射中那样连续地在内存中映射所有可执行文件,而是将每个部分映射到其对应的
VirtualAddress
。在后一种情况下,要从RVA获取VA,只需将ImageBase
添加到RVA
即可,因为它在磁盘上的文件是PE加载器在内存中映射内容的表示形式。但是,由于您没有映射PE加载程序将它们映射到的每个部分,因此像您那样将ImageBase
添加到RVA
中是行不通的。您需要一个给定RVA的函数,该函数为您提供与磁盘上文件中的RVA相对应的文件偏移量。要获得VA,您只需要将此文件偏移量添加到指向映射文件的字节指针即可。
只要有RVA(例如导入部分的RVA或名称字符串的RVA或其他名称),为了进行访问,您必须执行以下操作。
PBYTE actualAddress = (PBYTE) (lpFileBase + RVAtoFileOffset(pNTHeader, RVA))
这是函数:I posted it on pastebin,因为我在这里无法正确设置其格式。
它是这样工作的:当您拥有一个RVA时,该RVA必须位于一个节中,因此您遍历所有节的标题(紧接在可选标题之后)并找到RVA所在的节时,可以计算出该RVA在该部分
RVA - VirtualAddress
中的偏移量,并将其添加到该部分的PointerToRawData
中,现在您具有RVA的文件偏移量。如果RVA无效(它不在任何部分中),则该函数返回0。
由于您拥有的是RVA,因此需要执行此操作以访问导入目录或每个导入描述符的名称。
希望我能帮上忙。
关于c++ - IMAGE_SECTION_HEADER的VirtualAddress和PointerToRawData的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45212489/