PE基础知识(上)

PE文件的格式是一个很重要的基础知识,我希望有一天我的Blog可以适宜很多阶段的人学习,不管是小白还是初学者亦或者是回顾的人。

什么是PE文件

PE(Portable Executable)文件是一种可移植可执行文件格式,是Windows操作系统中应用程序(EXE)、动态链接库(DLL)和驱动程序(SYS)等二进制文件的标准文件格式。PE文件可以包含代码、数据、资源以及操作系统加载器在运行时执行程序所需的信息。

它是基于Unix的COFF(Common Object File Format)而来,用于存储编译后的中间文件。,COFF则是PE的前身,但PE文件并不仅仅是COFF文件,而是将COFF的某些特性扩展并融入了Windows特有的结构。在Windows中,PE文件实际上包含了一个COFF头(在PE Header中被称为“File Header”),因此可以说PE文件部分基于COFF格式。

在Unix和Linux中,COFF逐渐被ELF(Executable and Linkable Format)取代,因为ELF在功能和灵活性方面更强。

在Windows中,COFF演变成了PE(Portable Executable)格式,并得到了进一步扩展,增加了更多与Windows操作系统紧密结合的功能(例如导入/导出表、重定位表等)。

初识

PE-001

我们使用十六进制编辑器 010 Editor打开一个PE文件,就是上图这个样子,当然使用WinHex等工具也是没有任何问题的。我们使用编辑器打开这个文件才可以最清晰根本的感受到这个文件在我们的硬盘中是什么样子的。

img

img

这里我们借用两张非常经典的图,可以清晰的看出我们的PE文件由哪些部分组成,首先可以看出我们可以分为两大块

  • 文件头(Header)
  • 节区(Sections)由很多个组成

在文件头中包含了所有的属性信息以及节区的索引信息,节区中则是我们的程序的数据、导入导出表、指令集等内容。

PE Header

我们将文件头分为五个小部分来说(对应导图):

  • DOS头
  • PE头
  • 可选头
  • 数据目录
  • 节表

DOS头

这是我们PE文件最开始的部分,这部分是为了兼容DOS系统留下来的玩意儿。在Windows NT之前的Windows系统是基于dos操作系统内核, 为了兼容dos系统上可执行文件,Windows NT在设计可执行文件格式时保兼容了之前的格式。

我们把这部分再分成两个部分:

  • DOS头(固定长度)
  • DOS stub 存根(不固定长度)

DOS头的固定长度是64个字节,这是一个非常标准的结构体,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

IMAGE_DOS_HEADER结构体

字段名称 类型 说明
e_magic WORD 魔术数:标识文件类型,固定为 0x5A4D(ASCII 表示为 “MZ”),表示这是一个 DOS 可执行文件。
e_cblp WORD 文件最后一页的字节数:DOS 可执行文件中最后一页的有效字节数,不足 512 字节时用 0 填充。
e_cp WORD 文件总页数:文件的总页数,每页为 512 字节。
e_crlc WORD 重定位表项数:DOS 可执行文件中的重定位表条目数量。
e_cparhdr WORD 段落数目:DOS 头部分所占的段落数量,每个段落为 16 字节(64 字节的 DOS 头通常为 4 个段落)。
e_minalloc WORD 最小附加段数:程序加载时需要的最小附加段数。
e_maxalloc WORD 最大附加段数:程序加载时允许的最大附加段数。
e_ss WORD 初始 SS(栈段)值:程序启动时的栈段基址的偏移量(相对于加载地址)。
e_sp WORD 初始 SP(栈指针)值:程序启动时的栈指针值。
e_csum WORD 校验和:文件的简单校验和,用于检测文件的完整性(通常未使用)。
e_ip WORD 初始 IP(指令指针)值:程序启动时的指令指针值。
e_cs WORD 初始 CS(代码段)值:程序启动时的代码段基址的偏移量(相对于加载地址)。
e_lfarlc WORD 重定位表偏移:文件中重定位表的起始地址(相对于文件起始位置的偏移量)。
e_ovno WORD 覆盖号:指定覆盖文件编号(通常为 0)。
e_res[4] WORD[4] 保留字段:用于未来扩展(通常未使用,填充为 0)。
e_oemid WORD OEM 标识符:表示 OEM 制造商(通常未使用)。
e_oeminfo WORD OEM 信息:与 e_oemid 对应的附加信息(通常未使用)。
e_res2[10] WORD[10] 保留字段:进一步的扩展字段(通常未使用,填充为 0)。
e_lfanew LONG 新 PE 头偏移量:从文件开头到新 PE 头(即 IMAGE_NT_HEADERS)的偏移量。

重要字段解析

  1. **e_magic**:

    • 确认文件是一个 DOS 可执行文件,Windows 系统通过这个字段来识别文件格式。这是我们判断是不是PE文件的一个重要参考信息。
    • “MZ” 是 MS-DOS 的创始人 Mark Zbikowski 的首字母缩写。
  2. **e_lfanew**:

    • 关键字段:标识 PE 头在文件中的偏移量。
    • 当 Windows 发现 e_magic 是合法的 DOS 文件时,会读取 e_lfanew,以定位真正的 PE 头(IMAGE_NT_HEADERS)。(灰常重要!)
    • 对现代 PE 文件来说,这是最重要的连接点。
  3. **e_rese_res2**:

    • 这些保留字段主要用于填充,在现代文件中一般未使用。
  4. DOS stub 存根

    • 紧跟在 DOS 头之后,是一个小程序,主要用于在 MS-DOS 环境下显示消息或运行一些简单的代码。
    • 通常的内容是类似“此程序需要 Windows 环境才能运行”的(英文)提示。

其实DOS Stub是一个16位程序

1
2
3
4
0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68
69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F
74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20
6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00

反编译分析一下:

1
2
push cs
pop ds
  • 作用:将代码段寄存器(CS)的值压入堆栈,然后弹出到数据段寄存器(DS)。
  • 原因:在16位环境下,必须手动设置 DS 指向与 CS 相同的段地址,确保后续数据访问正确。
1
2
3
mov dx, 0Eh
mov ah, 9
int 21h
  • 作用
    • DX 设置为偏移地址 0Eh,该地址指向存储在 .COM 文件中的字符串数据。
    • AH 设置为 9,这表示调用 DOS 的 int 21h 中断服务功能号为 09h(显示字符串)。
    • **int 21h,功能号 09h**:显示以 $ 结尾的字符串。这里的字符串是 "This program cannot be run in DOS mode.\r\n"
  • 结果:在 DOS 模式下运行时,输出该字符串到屏幕。
1
2
mov ax, 4C01h
int 21h
  • 作用
    • AX 设置为 4C01h,其中 4C 是 DOS 的中断功能号,用于终止程序。
    • 01h 是返回代码,表示程序的退出状态。
    • **int 21h,功能号 4Ch**:终止程序并返回控制权给操作系统。

16位 DOS Stub 的完整流程

  1. 设置段寄存器:确保 DS 指向代码段,便于访问字符串数据。
  2. **调用 int 21h 中断,功能号 09h**:显示字符串 "This program cannot be run in DOS mode."
  3. **调用 int 21h 中断,功能号 4Ch**:终止程序并返回状态。

字符串部分

位于 0Eh 偏移处的字符串:

1
"This program cannot be run in DOS mode.\r\n$"
  • **$**:字符串终止符,这是 int 21h 功能号 09h 所需的格式。
  • **0D 0A**:回车换行符,对应 \r\n

int 21h 中断的作用

int 21h 是 MS-DOS 中的核心中断,用于提供多种系统服务功能。不同的功能由 AH 的值决定,例如:

  • **AH = 09h**:显示字符串。
  • **AH = 4Ch**:退出程序并返回状态。

DOS Stub 在运行时调用 int 21h,确保了程序在 MS-DOS 环境中的最低兼容性,允许输出提示并优雅退出。

PE文件头

这是PE文件真正的脑袋,它实际上是在一个更大的文件头内部,也就是NT头。在DOS头的最后一个字段指示了NT头的位置,NT头的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature; //标识符
IMAGE_FILE_HEADER FileHeader;//PE文件头
IMAGE_OPTIONAL_HEADER64 OptionalHeader;//可选头
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

Signature

第一部分标识符也就是IMAGE_NT_HEADERS结构体的第一个字段,其为一个DWORD,占四个字节,固定为50450000,就是ASCII字符的PE。

加载器从 DOS 头的 e_lfanew 偏移跳转到 IMAGE_NT_HEADERS,通过读取 Signature 验证这是一个有效的 PE 文件。

File Header (IMAGE_FILE_HEADER)

第二部分长度为20个字节,包含了一些重要信息,结构定义如下:

1
2
3
4
5
6
7
8
9
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; // 目标平台
WORD NumberOfSections; // 节的数量
DWORD TimeDateStamp; // 时间戳
DWORD PointerToSymbolTable; // 符号表指针(通常为0)
DWORD NumberOfSymbols; // 符号数量(通常为0)
WORD SizeOfOptionalHeader; // 可选头的大小
WORD Characteristics; // 文件特性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
字段名称 类型 说明
Machine WORD 目标平台:描述文件适用于哪种 CPU 架构。常见值包括:
- 0x14c(Intel 386/32位)
- 0x8664(AMD x64/64位)。
NumberOfSections WORD 节的数量:PE 文件中 Section Table(节表)的数量,定义了文件的结构和内容分布(如 .text.data)。
TimeDateStamp DWORD 时间戳:文件创建或最后修改的时间,格式为自 1970 年 1 月 1 日以来的秒数(UNIX 时间戳)。用于版本管理和调试。
PointerToSymbolTable DWORD 符号表指针:指向文件中的符号表位置(通常为 0,现代 PE 文件不使用符号表)。
NumberOfSymbols DWORD 符号数量:符号表中的符号数量(通常为 0,现代编译器不会填充)。
SizeOfOptionalHeader WORD 可选头大小IMAGE_OPTIONAL_HEADER 的大小,通常为 224 字节(32 位)或 240 字节(64 位)。
Characteristics WORD 文件特性:描述 PE 文件的属性,是一组标志的组合。例如:
- 0x0002:可执行文件exe
- 0x2000:DLL 文件
- 0x0100:32 位机代码

可选头 Optional Header (IMAGE_OPTIONAL_HEADER)

IMAGE_OPTIONAL_HEADERIMAGE_NT_HEADERS 的第三部分,虽然名字叫 “Optional”(可选头),实际上对现代 PE 文件是必不可少的。


可选头结构

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
typedef struct _IMAGE_OPTIONAL_HEADER32 {
WORD Magic; // 标识是32位还是64位PE
BYTE MajorLinkerVersion; // 链接器主版本号
BYTE MinorLinkerVersion; // 链接器次版本号
DWORD SizeOfCode; // 代码段大小
DWORD SizeOfInitializedData; // 已初始化数据段大小
DWORD SizeOfUninitializedData;// 未初始化数据段大小
DWORD AddressOfEntryPoint; // 程序入口点(RVA)
DWORD BaseOfCode; // 代码段起始地址(RVA)
DWORD BaseOfData; // 数据段起始地址(仅32位)
DWORD ImageBase; // 程序首选加载地址
DWORD SectionAlignment; // 内存中节对齐粒度
DWORD FileAlignment; // 文件中节对齐粒度
DWORD SizeOfImage; // PE 文件在内存中的总大小
DWORD SizeOfHeaders; // 文件头和节表的大小
DWORD CheckSum; // 文件校验和(通常为 0)
WORD Subsystem; // 子系统类型(如 GUI、控制台)
WORD DllCharacteristics; // DLL 的特性标志
DWORD SizeOfStackReserve; // 预留的栈大小
DWORD SizeOfStackCommit; // 提交的栈大小
DWORD SizeOfHeapReserve; // 预留的堆大小
DWORD SizeOfHeapCommit; // 提交的堆大小
DWORD LoaderFlags; // 加载标志(通常为 0)
DWORD NumberOfRvaAndSizes; // 数据目录的数量
IMAGE_DATA_DIRECTORY DataDirectory[16]; // 数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

还有个懒得Copy了

关键字段解析

  1. **Magic**:

    • 指定文件是 32 位还是 64 位格式:
      • 0x10B:PE32(32 位)。
      • 0x20B:PE32+(64 位)。
  2. **AddressOfEntryPoint**:

    • 程序入口点的相对虚拟地址(RVA),表示执行开始的地址,通常在 .text 节中。
  3. **ImageBase**:

    • 程序在内存中的首选加载地址,也就是这个PE文件要被加载到进程中的哪个地址,exe文件一般是0x00400000,dll文件一般是0x10000000(只是建议值)。如果加载器无法在该地址加载,会通过重定位表调整。
  4. **SizeOfImage**:

    • 程序在内存中加载后的总大小(包括所有节),对齐到 SectionAlignment 的倍数。
  5. **DataDirectory**:

    • 一个数据目录数组,包含重要的信息,比如导入表、导出表、资源表等。

数据目录(IMAGE_DATA_DIRECTORY)

数据目录是 PE 文件可选头(IMAGE_OPTIONAL_HEADER)的最后一部分。它是一个包含 16 个元素的数组,每个元素表示 PE 文件的一部分动态链接信息或元数据的起始地址和大小。

IMAGE_DATA_DIRECTORY 的结构

1
2
3
4
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; // RVA(相对虚拟地址)
DWORD Size; // 数据块的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
字段名称 类型 描述
VirtualAddress DWORD 数据块的相对虚拟地址(RVA),指向该数据块在内存中的位置。
Size DWORD 数据块的大小(以字节为单位),描述该数据块占用的大小。

数据目录的 16 个条目

以下是 IMAGE_NUMBEROF_DIRECTORY_ENTRIES(16个目录)的详细说明及用途:

索引 名称 描述
0 EXPORT Table 导出表:包含此模块向其他模块导出的函数和变量信息(如 DLL 的导出函数)。
1 IMPORT Table 导入表:列出此模块所需的外部模块及其导入的函数或变量信息。
2 RESOURCE Table 资源表:包含模块的资源信息(如图标、字符串、菜单等)。
3 EXCEPTION Table 异常表:记录程序的异常处理信息(如 SEH 结构,主要用于 C++ 和 Windows 内核异常处理)。
4 CERTIFICATE Table 证书表:包含与模块签名验证相关的数字证书信息(用于代码签名)。
5 BASE RELOCATION Table 基址重定位表:当模块加载地址与默认基址不同,需要通过此表调整内存地址。
6 DEBUG Table 调试信息表:包含与调试相关的信息(如符号表、调试器使用的数据)。
7 ARCHITECTURE 架构特定数据:保留字段,通常未使用。
8 GLOBAL POINTER 全局指针:保留字段,通常未使用。
9 TLS Table TLS 表:线程本地存储(Thread Local Storage)的初始化数据。
10 LOAD CONFIGURATION Table 加载配置表:包含与模块加载配置相关的信息(如安全功能、堆栈保护等)。
11 BOUND IMPORT Table 绑定导入表:优化加载时间的导入表,记录了依赖模块的绑定信息及其时间戳。
12 IMPORT Address Table (IAT) 导入地址表:包含实际导入函数的地址(运行时由加载器填充)。
13 DELAY IMPORT Descriptor 延迟导入表:延迟加载模块的导入表(在运行时首次调用函数时加载模块)。
14 COM Descriptor COM 描述符表:描述与 .NET 托管代码相关的信息(CLR 头)。
15 Reserved 保留字段:目前未使用,通常填充为 0。

关键数据目录的详细作用

1. EXPORT Table(导出表)
  • 用于描述模块(通常是 DLL)向外部模块提供的函数和变量。
  • 常见场景:一个 DLL 文件被多个程序调用,其导出表列出了 DLL 提供的 API。
2. IMPORT Table(导入表)
  • 描述当前模块依赖的外部模块以及需要调用的函数。
  • 典型用途:列出依赖的 DLL 及其函数,例如 Kernel32.dll 中的 CreateFile
3. RESOURCE Table(资源表)
  • 包含程序的资源数据,如图标、位图、字符串表、菜单和对话框。
  • 常见场景:程序的用户界面元素往往通过资源表加载。

4. BASE RELOCATION Table(基址重定位表)

  • 当模块未能加载到默认基址时,重定位表帮助调整代码中涉及的内存地址。
  • 典型用途:调整绝对地址指令的操作数。
5. DEBUG Table(调试表)
  • 包含与调试相关的数据,用于帮助调试器识别代码结构。
  • 通常包括调试符号、代码行号等信息。
6. TLS Table(线程本地存储表)
  • 描述线程私有的全局变量。
  • 用途:为每个线程分配独立的存储空间。
7. LOAD CONFIGURATION Table(加载配置表)
  • 包含安全功能信息,例如:
    • 堆栈保护(GS Cookie)。
    • 数据执行保护(DEP)。
    • 结构化异常处理(SEH)过滤器。
8. DELAY IMPORT Descriptor(延迟导入描述符)
  • 支持模块的延迟加载。
  • 应用场景:减少程序启动时的加载开销,仅在首次使用函数时加载依赖模块。
9. COM Descriptor(CLR 头)
  • 主要用于托管代码(.NET 程序),描述与公共语言运行时(CLR)相关的信息。
  • 如果 PE 文件是 .NET 程序,CLR 头会在此描述。

节表(Section Table)

PE 文件中的节(Section)是实际存放数据的地方,例如代码、全局变量、资源等。节表位于 PE 文件头之后,由多个结构体组成,每个结构体描述一个节的信息。


节表结构体定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[8]; // 节名称
union {
DWORD PhysicalAddress; // 物理地址(已弃用)
DWORD VirtualSize; // 节的大小(内存中)
} Misc;
DWORD VirtualAddress; // 内存中的起始地址(RVA)
DWORD SizeOfRawData; // 文件中对齐后的大小
DWORD PointerToRawData; // 文件中的偏移地址
DWORD PointerToRelocations; // 重定位信息表指针(通常为0)
DWORD PointerToLinenumbers; // 行号信息表指针(通常为0)
WORD NumberOfRelocations; // 重定位条目数量(通常为0)
WORD NumberOfLinenumbers; // 行号信息数量(通常为0)
DWORD Characteristics; // 节的属性标志
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

结构体字段解析
字段名称 类型 描述
Name BYTE[8] 节的名称,最多为 8 个字符,常见的节名如:.text(代码段)、.data(数据段)、.rsrc(资源段)等。
Misc.VirtualSize DWORD 节在内存中的实际大小,未对齐。用于运行时的内存分配。
VirtualAddress DWORD 节在内存中的起始地址(RVA,相对虚拟地址),相对于镜像基址。
SizeOfRawData DWORD 节在文件中对齐后的大小,通常大于等于 Misc.VirtualSize
PointerToRawData DWORD 节在文件中的偏移地址。
PointerToRelocations DWORD 指向重定位信息表的偏移地址(对于可执行文件通常为 0)。
PointerToLinenumbers DWORD 指向行号信息表的偏移地址(通常为 0,现代 PE 文件不使用)。
NumberOfRelocations WORD 重定位表中的条目数量(通常为 0,现代 PE 文件不使用)。
NumberOfLinenumbers WORD 行号信息数量(通常为 0,现代 PE 文件不使用)。
Characteristics DWORD 节的属性标志,定义节的权限和特性(如是否可读、可写、可执行)。

关键字段详解
  1. **Name**:

    • 用于标识节的作用或内容。
    • 常见节名称:
      • .text:代码段,存储可执行代码。
      • .data:已初始化的数据段。
      • .bss:未初始化的数据段。
      • .rdata:只读数据段(常量)。
      • .rsrc:资源段,存储应用程序资源(如图标、对话框)。
      • .reloc:重定位表。
  2. **VirtualAddress**:

    • 节的相对虚拟地址(RVA),表示节加载到内存后的位置。
    • 计算方式:镜像基址(ImageBase) + VirtualAddress。
  3. SizeOfRawData 和 **PointerToRawData**:

    • **SizeOfRawData**:节在文件中的对齐后的大小。
    • **PointerToRawData**:节在文件中的起始偏移。
    • 注意:节在文件中的大小可能会比其实际使用的内存大小(VirtualSize)更大。
  4. **Characteristics**:

    • 描述节的属性,常见标志:
      • 0x20000000:包含代码。
      • 0x40000000:包含初始化数据。
      • 0x80000000:包含未初始化数据。
      • 0x02000000:可执行。
      • 0x04000000:可读。
      • 0x08000000:可写。

节表的数量

节表的数量由 PE 文件头(IMAGE_FILE_HEADER)的 NumberOfSections 字段指定。每个节都有一个对应的 IMAGE_SECTION_HEADER 结构体。


节表的作用

节表是 PE 文件的重要部分,它为加载器提供以下信息:

  1. 定位节内容
    • 文件中的偏移(PointerToRawData)指向节的内容。
    • 内存中的地址(VirtualAddress)指向节在内存中的加载位置。
  2. 节的大小和属性
    • 加载器根据 SizeOfRawDataVirtualSize 确定内存分配。
    • 根据 Characteristics 设置节的读写和执行权限。
  3. 指引运行时行为
    • 加载器使用 .reloc 节处理重定位。
    • 代码从 .text 节执行,数据从 .data 节加载,资源从 .rsrc 节访问。

常见 PE 文件节名称 的表格

节名称 用途/描述
.text 代码段:存储可执行代码,是程序运行的核心部分。
.data 已初始化数据段:存储全局变量、已初始化的静态变量等数据。
.bss 未初始化数据段:存储未初始化的全局变量和静态变量,加载时初始化为零。
.rdata 只读数据段:存储只读数据,如常量字符串和调试目录。
.rsrc 资源段:存储资源信息,如图标、对话框、字符串表等。
.reloc 重定位表段:存储重定位信息,当加载地址不同于首选基址时,用于修正内存地址。
.edata 导出表段:存储模块导出的函数和变量信息(如 DLL 的导出函数)。
.idata 导入表段:存储模块所需的外部函数和变量信息(如 DLL 的导入函数)。
.pdata 异常处理段:存储异常处理和运行时函数调度信息,通常用于 SEH(结构化异常处理)。
.debug 调试段:存储调试信息,如符号表、代码行号等,通常供调试器使用。
.tls 线程本地存储段:存储 TLS(Thread Local Storage)初始化数据,为线程分配私有的全局变量。
.crt 运行时支持段:存储 C/C++ 运行时库初始化代码,通常在程序启动和结束时执行。
.sxdata 安全执行数据段:用于存储与 Windows 安全机制相关的数据。
.gfids 全局函数标识段:存储函数指针,用于全局范围内的功能识别(在某些链接器中出现)。
.orpc 对象 RPC(远程过程调用)段:存储与 COM 对象相关的远程调用信息。
.ndata 非标准数据段:存储与某些平台或工具链相关的非标准数据(可能工具链特定)。
.eh_frame 异常处理帧段:存储 C++ 异常处理的帧信息,通常在混合代码中使用。
.symtab 符号表段:存储调试符号表,包含符号名、地址等信息(较少见于现代 PE 文件)。

PE基础知识(上)
https://kyxiaxiang.github.io/2024/11/17/PEFormat/
作者
keyixiaxiang
发布于
2024年11月17日
许可协议