PE

来源:互联网 发布:赛车模拟游戏机知乎 编辑:程序博客网 时间:2024/03/29 23:36

在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值。


所以:

映射入内存地址的时候要查VirtualAddress,而查找section在文件中的位置,要查PointerToRawData

所以,诸如 

dwDis = m_pSectionHeader[i]->VirtualAddress - m_pSectionHeader[i]->PointerToRawData;

return dwRVA - dwDis; 
 的意义就是:

先查出在内存中相对section的地址 dwRVA - m_pSectionHeader[i]->VirtualAddress,然后这个相对section的地址跟文件中相对的地址是一样的,再加上

文件中section的地址,得到的就是在文件中的偏移地址

原创粉丝点击