PE解析器的编写(三)——区块表的解析

来源:互联网 发布:乐乐抢红包软件 编辑:程序博客网 时间:2024/06/14 17:17

PE文件中所有节的属性都被定义在节表中,节表由一系列的IMAGE_SECTION_HEADER结构排列而成,每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的。
具有相同属性的数据被安排到同一个区块中。
区块表的结构为IMAGE_SECTION_HEADER,在PE文件中存在一个该结构的数组,用来保存各个区块的信息,这个数组的大小在PE头的结构 IMAGE_NT_HEADERS 的成员NumberOfSections描述。
区块表结构IMAGE_SECTION_HEADER结构如下:

typedef struct _IMAGE_SECTION_HEADER {       BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称,如“.text”        //IMAGE_SIZEOF_SHORT_NAME=8        union         {                DWORD PhysicalAddress;      // 物理地址                DWORD VirtualSize;          // 真实长度,这两个值是一个联合结构,可以使用其中的任何一个,一般是取后一个        } Misc;        DWORD VirtualAddress;               // 节区的 RVA 地址                DWORD SizeOfRawData;                // 在文件中对齐后的尺寸             DWORD PointerToRawData;             // 在文件中的偏移量                DWORD PointerToRelocations;         // 在OBJ文件中使用,重定位的偏移          DWORD PointerToLinenumbers;         // 行号表的偏移(供调试使用地)        WORD NumberOfRelocations;           // 在OBJ文件中使用,重定位项数目        WORD NumberOfLinenumbers;           // 行号表中行号的数目        DWORD Characteristics;              // 节属性如可读,可写,可执行等} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

在程序中我们主要列出了,区块名称、RVA、在进行内存对齐后的尺寸,在磁盘中的大小,在文件中的偏移,节属性。
在界面中,定义了一个listctrl来显示这些信息。
在CPeFileInfo类中定义了一个vector m_SectionTable;专门用来存储区块表的属性信息。获取这个信息。
在这个类中与区块表有关的函数主要有两个:
GetSectionHeader : 用来获取指向表的指针
InitSectionTable:初始化上面定义的结构
下面来一一说明这两个函数

PIMAGE_SECTION_HEADER CPeFileInfo::GetSectionHeader(){    PIMAGE_FILE_HEADER pFileHeader = GetFileHeader();    PIMAGE_SECTION_HEADER pSectionHeader = NULL;    if (NULL == pFileHeader)    {        return NULL;    }    PIMAGE_OPTIONAL_HEADER pOptionHeader = GetOptionalHeader();    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)(pOptionHeader) + pFileHeader->SizeOfOptionalHeader);    return pSectionHeader;//  PIMAGE_NT_HEADERS pNtHeader = GetNtHeaders();//  return (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader + sizeof(IMAGE_NT_HEADERS));}

在PE文件中区块表的属性信息是紧密排列在PE头结构后面的,所以我们只要知道OptionHeader结构的指针,然后加上这个结构的大小就可以获取到区块表的地址,上面的代码也是这样做的,首先获取了FileHeader的指针,这个结构中的SizeOfOptionalHeader定义了OptionHeader这个结构的大小,我们利用FileHeader + SizeOfOptionalHeader这样就偏移到了区块表所在的位置。
或者更简单的方式是利用PE文件头的地址 + 文件头的大小也一样可以获取到区块表的地址

void CPeFileInfo::InitSectionTable(){    if (!m_SectionTable.empty())    {        return ;    }    PIMAGE_SECTION_HEADER pSectionHeader = GetSectionHeader();    PIMAGE_FILE_HEADER pFileHeader = GetFileHeader();    if (NULL != pSectionHeader && NULL != pFileHeader)    {        DWORD dwCountOfSection = pFileHeader->NumberOfSections;        int nCount = 0;        while (nCount < dwCountOfSection)        {            IMAGE_SECTION_HEADER ImageSec = pSectionHeader[nCount];            m_SectionTable.push_back(ImageSec);            nCount++;        }    }}

后面就是循环遍历将所有信息写入m_SectionTable这个动态数组中。在这份代码中我们首先利用FileHeader的NumberOfSections成员获取区块表的个数,然后在循环中以这个个数作为条件,以此往后寻址,将信息写入到对应的数组中,最后在输出的时候只需要根据需求输出我们感兴趣的内容即可

0 0
原创粉丝点击