Last updated on October 7, 2023 pm
PE文件结构(二) 节表
回顾
在此之前,我们已经知道PE文件结构前面几部分是由DOS头(通常把DOS stub也算入DOS头中)、NT头,NT头又可以分为Signature、标准PE头、可选PE头,紧接着可选PE头的就是节表。
节表
节表的索引
在解析节表之前,我们首先要知道如何在文件中找到这个节表
根据PE结构图有一个很朴素的思想去找到这个节表在文件中位置,即节表地址 = DOS头大小+Signature大小+标准PE头大小+可选PE头大小即可,然而借助于DOS头中 e_lfanew
字段我们可以直接跳到Signature处,此时变成 e_lfanew
+ Signature大小 +标准PE头大小+可选PE头大小
其中Signature大小是4个字节(PE的标识),标准PE头大小是固定的0x14字节,标准PE头中又有 SizeOfOptionalHeader
字段标识可选头大小,所以节表地址就可以表示为 e_lfanew + 4 + 0x14 + SizeofOptionalHeader
节区数量
既然提到了表,就说明这是一个线性结构,像一个数组一样存储了若干小表的信息,这个小表其实就是一个结构体,也即图中的Image_Section_Table
,自然大小也就是确定的。每一个结构体都包含了对应节区的相关信息,比如节区的名字、大小等。我们现在可以找到节表,但是怎么确定这个节表中有多少个Image_Section_Table
呢
这就又要回想到之前的标准PE头,里面有一个字段NumberOfSections
,顾名思义,就是存储了节表的数量。
那么现在有了节表的起始位置,又有了节区的数量,节表的大小,尽管不知道节表里的结构体都有什么成员,但是最起码现在可以确定每一个结构体的起始终止了
结构体成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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;
|
以一个对比图来说明
左边是文件形式,右边是运行时形式
- Name - 从A开始的8个字节是名字
- Misc - 从A到B的大小,可以不准确
- VirtualAddress - 右图中 ImageBase到A的距离
- SizeOfRawData - 左图中绿色框的大小
- PointerToRawData - 左图中0到A的距离
代码查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include<stdio.h> #include<windows.h>
DWORD Size(FILE* fp){ DWORD size = 0; fseek(fp,0,SEEK_END); size = ftell(fp); fseek(fp,0,SEEK_SET); return size; }
void Section_Info(FILE* fp,char* buffer){ PIMAGE_DOS_HEADER DosHeader = NULL; PIMAGE_NT_HEADERS NTHeader = NULL; PIMAGE_FILE_HEADER FileHeader= NULL; PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL; PIMAGE_SECTION_HEADER SectionHeader = NULL;
DosHeader = (PIMAGE_DOS_HEADER)buffer; NTHeader = (PIMAGE_NT_HEADERS)(buffer + DosHeader->e_lfanew); FileHeader = (PIMAGE_FILE_HEADER)(buffer + DosHeader->e_lfanew + 4); OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(buffer + DosHeader->e_lfanew + 4 +IMAGE_SIZEOF_FILE_HEADER); SectionHeader = (PIMAGE_SECTION_HEADER)(buffer + DosHeader->e_lfanew + 4 +IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);
printf("=================Section PE_INFO=================\n"); for(int i=0;i<FileHeader->NumberOfSections;i++){ printf("The %dth sec\n",i+1); printf("name:%s\n",SectionHeader->Name); printf("VitualAddress:%08x\n", SectionHeader->VirtualAddress); printf("SizeOfRawData:%08x\n", SectionHeader->SizeOfRawData); printf("PointerToRawRata:%08x\n", SectionHeader->PointerToRawData); printf("Characteristic:%X\n", SectionHeader->Characteristics); printf("==================================\n"); SectionHeader = (PIMAGE_SECTION_HEADER)(buffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader + 40 * (i + 1)); } } int main(){ char* buffer;
FILE* fp = NULL; errno_t err_1 = fopen_s(&fp, "YOU PATH TO EXE HERE", "rb"); DWORD size = Size(fp); buffer = (char*)malloc(size); fread(buffer,size,1,fp);
Section_Info(fp,buffer); return 0; }
|