在Dump PE File的section table时候,一开始选用RVA来计算section的地址,以期望能取到Section信息,后来发现不完全正确,应该用PointerToRawData的值。
如果根据自己定义的内存对齐的值,将FileAlignment和SectionAlignment设为相同的对齐方式,这个时候生成的PE文件,RVA和PointerToRawData的值指向同一个地址,此时要取到Section的信息,用RVA也可以,因为值是一样的。但是从意义上来说不完全正确。 一般生成的PE文件,假设FileAlignment = 200 Byte; SectionAlignment = 1000 Byte,此时RVA的值不等于PointerToRawData的值。如果不是由OS的loader装载,也就是说,我要自己dump一个PE File,在自己的code中用的是fopen(),fread()这样的函数将文件读进内存,而他们的作用仅仅是copy,并不像OS的loader将文件载入内存,因此自己要要取Section的信息,应该以后者的值来计算。因为如果是OS的loader载入文件,就会将文件按照Section
Alignment的预设值将文件的各个部分放置内存的各个memory page中。
以下附上Section Header的定义。
Section Header在WinNT.h中的结构定义:
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
1.VirtualAddress:本Section的RVA(相对虚拟地址)。PE装载器将本section映射至内存时会读取本值,因此如果域值是1000h,而PE文件装在地址400000h处,那么本节就被载到401000h。微软把第一个Section 的此域值设为0x1000h。对于OBJ文档,此域没意义,总为0。
2.SizeOfRawData:经过文件对齐处理后Section尺寸,PE装载器提取本域值了解需映射入内存的节字节数。 假设一个文件的文件对齐尺寸是0x200,如果前面的 VirtualSize 域指示本Section的长度是0x388字节,则本域值为0x400,表示本节是0x400字节长。在obj中,这个与表示有编译器指定的真正的section 大小。
3.PointerToRawData:这是本Section基于文件的偏移量,PE装载器通过本域值找到Section数据在文件中的位置。 如果是你自己以内存映射的方式应设了一个PE程序(而不是由操作系统的装载器载入),那么这个域比VirtualAddress更重要。在这种情况下你有一个完全线性的文件映射,那么你就必须根据此值找到本Section的信息,而不是根据VirtualAddress
中的RVA值。
|