2.4 PE structure: detailed analysis of section table

Section Table (Section Table) is a very important data structure in executable files in Windows PE/COFF format. It records the position and size information of each code segment, data segment, resource segment, redirection table, etc. in the file. It is an important basis for the operating system to map and initialize each segment according to the section table when loading a file. Each record in the section table is called IMAGE_SECTION_HEADER, which records various attribute information of a segment and information such as its position and size in the file, and a file can be IMAGE_SECTION_HEADERcomposed of multiple.

When executing a PE file, Windows does not read the entire file into memory at the beginning. The PE loader only establishes the mapping relationship between the virtual address and the PE file during loading, and only actually executes it into a certain memory page. This page will be submitted from the disk to the memory only when an instruction is issued or the data in the page is accessed. This mechanism greatly saves memory resources, so that the file loading speed has little relationship with the file size.

The Windows loader does not perform any processing when loading the DOS part PE file header part and the section table part. When loading the section area, it will perform different processing according to the different attributes of the section. Generally, the following aspects need to be processed:

Attributes of the section area: a section is a combination of data with the same attribute. When a section is loaded into memory, the memory page corresponding to the same section will be given the same page attribute. Windows system sets the memory attribute in units of pages It is carried out, so the unit of the section in memory must be at least the size of a page. For X86, this value is 4KB (1000h), and for X64, this value is 8KB (2000h). The program stored in the disk It will not be aligned to 4KB, but only when it is loaded into memory by the PE loader, the PE loader will automatically fill in the 4KB fragmentary data.

Offset of the section area: The starting address of the section is aligned according to the value of the FileAhgnment field of the structure in the disk file IMAGE_OPTIONAL_HEADER, but when loaded into memory, it is aligned according to the value of the SectionAlignment field in the same structure. The values ​​of both may be different, so the offset relative to the file header after a section is loaded into memory may be different from the offset in the disk file.

Section size: Due to the different alignment units of the disk image and the memory image, the image on the disk will automatically expand in length after being loaded into memory, but it is not necessary for the uninitialized data segment (.data?) Reserve space for it in the disk file, as long as the executable file is loaded into the memory and dynamically allocate space for it, so the length of the section containing uninitialized data is defined as 0 in the disk, only after the PE loader runs Only then can we dynamically open up space for them.

Sections that are not mapped: Some sections contain data that are only used when loading. When the file is loaded, they will not be submitted to physical memory, such as relocation sections. The data in this section is for the file. It is transparent to the executable code, it is only used by the Windows loader, and the executable code does not access them at all, so these sections exist in the disk file and will not be mapped into memory.

Generally speaking, when a PE file is compiled and generated, there will be .text,.datasuch basic section tables by default, and each section table is IMAGE_SECTION_HEADERarranged by a structure, each structure is used to describe a section, and the section table is always stored In the place immediately after the PE file header, that is, the offset from the PE file header 00f8h, you can view the definition of the section table structure for the definition in each section;

typedef struct _IMAGE_SECTION_HEADER
{
    
    
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
    
    
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;           // 节区尺寸
    } Misc;
    DWORD   VirtualAddress;                // 节区RVA
    DWORD   SizeOfRawData;                 // 在文件中对齐后的尺寸
    DWORD   PointerToRawData;              // 在文件中的偏移
    DWORD   PointerToRelocations;          // 在OBJ文件中使用
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;               // 节区属性字段
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

Detailed analysis of IMAGE_SECTION_HEADEReach field in:

  • Name: Segment name, which is an 8-byte ASCIIstring. If the length is less than 8 bytes, use 0s to fill it in.

  • VirtualSize: Virtual size, identifies the size occupied in memory, not to be PhysicalSizeconfused with (physical size).

  • VirtualAddress: Virtual address, which identifies the address of the corresponding segment header in memory and is related to the actual loaded location.

  • SizeOfRawData: Physical size, indicating the occupied size of this segment in the PE file. If it is not enough for the file alignment unit, it will be filled.

  • PointerToRawData: Physical address, identifying the offset position of the segment in the file.

  • PointerToRelocations: The offset position of the redirection table.

  • PointerToLinenumbers: The offset position of the line number table.

  • NumberOfRelocations: Number of redirection tables.

  • NumberOfLinenumbers: Number of line number tables.

  • Characteristics: identifies various attribute information of this segment, including the following common attributes:

    • IMAGE_SCN_MEM_READ: readable;
    • IMAGE_SCN_MEM_WRITE: writable;
    • IMAGE_SCN_MEM_EXECUTE: executable;
    • IMAGE_SCN_CNT_CODE: code segment;
    • IMAGE_SCN_CNT_INITIALIZED_DATA: The data segment has been initialized;
    • IMAGE_SCN_CNT_UNINITIALIZED_DATA: Uninitialized data segment;
    • IMAGE_SCN_LNK_INFO: Contains additional information.

It is basically the same as the enumeration method of the data directory table, and the enumeration of the data directory table is not too difficult. The reader only needs to NtHeader->FileHeader.NumberOfSectionsobtain the current number of sections, and obtain the pointers in these sections in turn through a loop, and set The pointer is converted into PIMAGE_SECTION_HEADERa structure and can be obtained by looping the output in sequence;

int main(int argc, char * argv[])
{
    
    
    BOOL PE = IsPeFile(OpenPeFile("c://pe/x86.exe"), 0);

    if (PE == TRUE)
    {
    
    
        printf("编号\t 节区名称\t虚拟偏移\t虚拟大小\t实际偏移\t实际大小\t节区属性\n");

        for (DWORD each = 0; each < NtHeader->FileHeader.NumberOfSections; each++, pSection++)
        {
    
    
            printf("%d\t %-9s\t 0x%.8X \t 0x%.8X \t 0x%.8X \t 0x%.8X \t 0x%.8X \n",
                each + 1, pSection->Name, pSection->VirtualAddress, pSection->Misc.VirtualSize,
                pSection->PointerToRawData, pSection->SizeOfRawData, pSection->Characteristics);
        }
    }
    else
    {
    
    
        printf("非标准程序 \n");
    }

    system("pause");
    return 0;
}

Run the above program to output the section table information existing in the current program. The output effect is as shown in the figure below;

Guess you like

Origin blog.csdn.net/lyshark_csdn/article/details/132687571