burpow
第12节-PE文件格式与Windows装载

第12节-PE文件格式与Windows装载

第 12 节:PE 文件格式与 Windows 装载

所属课程:操作系统自学路线:面向网络安全、逆向工程与漏洞分析
所属周次:第 6 周
课程主题:可执行文件与程序装载
本节目标:理解 Windows 下 PE 可执行文件的基本结构,掌握 DOS Header、PE Header、Section Table、.text、.rdata、.data、.rsrc、Import Table、IAT、DLL 加载等概念,并能用 PE-bear、Detect It Easy、Ghidra、x64dbg 观察 PE 文件。


1. 本节课你要学会什么

学完这一节,你应该能回答下面几个问题:

  1. PE 是什么?
  2. Windows 为什么能识别一个 .exe 或 .dll?
  3. DOS Header 和 MZ 魔数是什么?
  4. PE Header 和 Optional Header 中保存了什么?
  5. Section Table 是什么?
  6. .text、.rdata、.data、.rsrc 分别通常放什么?
  7. Import Table 和 IAT 是什么?
  8. DLL 是如何被加载和调用的?
  9. PE 和 ELF 有哪些相似点和不同点?
  10. 为什么 PE 文件格式对 Windows 逆向、漏洞分析、恶意代码分析非常重要?

本节课的主线是:

1
Windows 程序 -> PE 文件 -> Windows Loader 解析 -> 映射到进程地址空间 -> 加载 DLL -> 修复导入表 -> 从入口点执行

上一节我们学习了 Linux ELF,这一节学习 Windows PE。两者都是可执行文件格式,但设计细节不同。


2. PE 是什么

PE 全称是:

1
Portable Executable

中文常译为:

1
可移植可执行文件格式

Windows 下常见 PE 文件包括:

  • .exe
  • .dll
  • .sys
  • .ocx
  • .scr
  • 某些 .cpl

也就是说,PE 不只包括普通可执行程序。

例如:

1
2
3
4
notepad.exe
kernel32.dll
ntdll.dll
some_driver.sys

它们都可能是 PE 格式。


3. PE 为什么重要

PE 是 Windows 逆向工程的基础。

3.1 对 Windows Loader

Windows Loader 需要根据 PE 文件知道:

  • 这是不是合法 PE 文件
  • 入口点在哪里
  • 需要映射哪些节到内存
  • 每个节的权限是什么
  • 依赖哪些 DLL
  • 导入哪些函数
  • 是否有资源
  • 是否需要重定位
  • 是否启用了安全缓解机制

3.2 对逆向工程

逆向 PE 程序时,你会关注:

  • ImageBase
  • Entry Point
  • Section
  • Import Table
  • IAT
  • Export Table
  • 字符串
  • 资源
  • TLS Callback
  • 是否加壳
  • 是否动态解析 API

3.3 对恶意代码分析

Windows 恶意代码大多是 PE 文件。

分析时常看:

  • 导入了哪些 API
  • 是否有可疑节名
  • 是否节权限异常
  • 是否包含资源 payload
  • 是否加壳
  • 是否动态加载 DLL
  • 是否修改 IAT
  • 是否有反调试 API
  • 是否使用网络、文件、注册表、进程相关 API

4. 准备一个示例程序

可以准备一个简单 Windows C 程序 pe_demo.c:

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
#include <windows.h>
#include <stdio.h>

int global_var = 123;
char global_buf[32] = "hello pe";

void helper() {
MessageBoxA(NULL, global_buf, "PE Demo", MB_OK);
}

int main() {
HANDLE h = CreateFileA(
"pe_demo_output.txt",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);

if (h != INVALID_HANDLE_VALUE) {
DWORD written;
WriteFile(h, "hello file\r\n", 12, &written, NULL);
CloseHandle(h);
}

printf("global_var=%d\n", global_var);
helper();
return 0;
}

如果你使用 MinGW,可以编译:

1
x86_64-w64-mingw32-gcc -g -O0 pe_demo.c -o pe_demo.exe

如果在 Windows 上使用 Visual Studio 或 Developer Command Prompt,可以用对应编译器生成 exe。

如果暂时不能编译,也可以用任意简单 exe,例如自己写的 hello.exe 或系统自带小程序做观察。


5. PE 文件的整体结构

PE 文件大致结构可以简化为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+---------------------------+
| DOS Header |
+---------------------------+
| DOS Stub |
+---------------------------+
| PE Signature |
+---------------------------+
| COFF File Header |
+---------------------------+
| Optional Header |
+---------------------------+
| Section Table |
+---------------------------+
| .text |
| .rdata |
| .data |
| .rsrc |
| .reloc |
+---------------------------+

不同编译器、链接器和加壳器生成的 PE 会有所不同。

但核心结构类似。


6. DOS Header 和 MZ 魔数

PE 文件最开头是 DOS Header。

它的前两个字节通常是:

1
4D 5A

对应 ASCII:

1
MZ

所以很多工具会说:

1
MZ Header

MZ 是 PE 文件的重要魔数。

你可以用十六进制工具查看 exe 文件开头。

例如:

1
00000000: 4D 5A ...

这说明它可能是 PE 文件。

DOS Header 中有一个很重要的字段:

1
e_lfanew

它保存 PE Header 在文件中的偏移。

Windows Loader 会通过它找到真正的 PE 头。


7. DOS Stub 是什么

DOS Header 后面通常有一小段 DOS Stub。

很多 PE 文件中可以看到字符串:

1
This program cannot be run in DOS mode.

这是历史兼容遗留。

现代 Windows 程序一般不依赖 DOS Stub 的业务逻辑。

逆向时看到它不用紧张。

它只是 PE 文件结构中的常见部分。


8. PE Signature

通过 DOS Header 的 e_lfanew 找到 PE Header 后,会看到 PE 签名:

1
50 45 00 00

对应:

1
PE\0\0

这是 PE Header 的标识。

所以一个典型 PE 文件会同时包含:

1
2
MZ
PE\0\0

MZ 在文件开头,PE\0\0 在 e_lfanew 指向的位置。


9. COFF File Header

PE Signature 后面是 COFF File Header。

它包含一些基本文件信息,例如:

  • Machine:目标架构
  • NumberOfSections:节数量
  • TimeDateStamp:时间戳
  • PointerToSymbolTable:符号表指针,现代 PE 中常不重要
  • SizeOfOptionalHeader:Optional Header 大小
  • Characteristics:文件属性

常见 Machine:

值 含义
0x014c x86 32 位
0x8664 x86-64 / AMD64

逆向时,Machine 可以告诉你这是 32 位还是 64 位程序。

这会影响:

  • 寄存器
  • 调用约定
  • 栈布局
  • 调试器选择
  • 反汇编模式

10. Optional Header 并不“可选”

PE 中有一个结构叫:

1
Optional Header

名字叫 Optional,但对可执行文件来说非常重要,基本不是可有可无。

它包含装载所需的关键信息,例如:

  • AddressOfEntryPoint
  • ImageBase
  • SectionAlignment
  • FileAlignment
  • SizeOfImage
  • SizeOfHeaders
  • Subsystem
  • DLLCharacteristics
  • DataDirectory

这些字段决定 Windows 如何把 PE 映射到内存。


11. AddressOfEntryPoint

AddressOfEntryPoint 是程序入口点的 RVA。

RVA 是:

1
Relative Virtual Address

即相对虚拟地址。

它不是文件偏移,也不是绝对运行地址。

如果:

1
2
ImageBase = 0x140000000
AddressOfEntryPoint = 0x1000

那么默认入口虚拟地址大致是:

1
0x140001000

注意:

入口点通常不是 main。

Windows 程序也会先执行运行时启动代码,然后再调用 main / WinMain。


12. ImageBase

ImageBase 是 PE 希望被加载到的首选基址。

例如 64 位程序常见:

1
ImageBase = 0x140000000

DLL 也有自己的 ImageBase。

如果启用了 ASLR,实际加载地址可能不是首选 ImageBase。

Windows Loader 会选择合适地址加载,并根据需要做重定位。

逆向时,你需要区分:

1
2
3
文件中的 RVA
内存中的 VA
文件偏移 Raw Offset

这三个概念非常重要。


13. RVA、VA 和 File Offset

PE 分析中常见三个地址概念。

13.1 RVA

RVA 是相对虚拟地址。

1
RVA = VA - ImageBase

例如:

1
2
3
ImageBase = 0x140000000
VA = 0x140001000
RVA = 0x1000

13.2 VA

VA 是虚拟地址,即程序加载到内存后的地址。

调试器中看到的地址通常是 VA。

例如 x64dbg 中:

1
0000000140001000

13.3 File Offset

File Offset 是文件偏移。

它表示数据在磁盘 PE 文件中的位置。

例如:

1
文件第 0x400 字节处

RVA 和 File Offset 需要通过 Section Table 转换。

逆向工具会帮你做很多转换,但你需要知道它们不是同一个概念。


14. Section Table 是什么

Section Table 描述 PE 文件中各个节的信息。

常见字段:

  • Name
  • VirtualAddress
  • VirtualSize
  • PointerToRawData
  • SizeOfRawData
  • Characteristics

其中:

字段 含义
Name 节名
VirtualAddress 加载到内存后的 RVA
VirtualSize 内存中大小
PointerToRawData 文件中偏移
SizeOfRawData 文件中大小
Characteristics 权限和属性

常见节:

1
2
3
4
5
.text
.rdata
.data
.rsrc
.reloc

不同编译器可能使用不同节名。

加壳程序也可能出现奇怪节名。


15. .text 节

.text 通常存放程序代码。

包括:

  • 函数机器指令
  • 运行时启动代码
  • 编译器生成的辅助代码

它通常具有权限:

1
可读 + 可执行

一般不应该可写。

如果你看到某个 PE 的 .text 节同时可写和可执行,需要提高警惕。

这不一定恶意,但值得分析。


16. .rdata 节

.rdata 通常存放只读数据。

常见内容:

  • 字符串常量
  • 导入相关只读结构
  • RTTI 信息
  • const 数据
  • 某些跳转表

例如:

1
MessageBoxA(NULL, "hello", "title", MB_OK);

字符串 hello 和 title 可能在 .rdata。

逆向时字符串窗口中的很多字符串来自 .rdata。


17. .data 节

.data 通常存放已初始化的全局变量和静态变量。

例如:

1
2
int global_var = 123;
char global_buf[32] = "hello pe";

这些数据需要在文件中保存初始值。

.data 通常权限是:

1
可读 + 可写

通常不可执行。


18. .rsrc 节

.rsrc 是资源节。

Windows 程序可以把资源放在 PE 文件中,例如:

  • 图标
  • 对话框
  • 菜单
  • 字符串表
  • 版本信息
  • 位图
  • 嵌入文件

恶意代码有时也会把 payload 或配置数据藏在资源节里。

所以恶意代码分析中,.rsrc 很重要。

可以用工具查看资源:

  • Resource Hacker
  • PE-bear
  • Detect It Easy
  • CFF Explorer
  • Ghidra

19. .reloc 节

.reloc 是重定位节。

如果 PE 不能加载到首选 ImageBase,Windows Loader 需要修正一些地址。

.reloc 提供重定位信息。

ASLR 依赖程序能够被重定位。

如果 PE 没有重定位信息,地址随机化可能受限。

逆向和漏洞利用中,重定位和 ASLR 关系密切。


20. Data Directory

Optional Header 中有 Data Directory。

它指向 PE 中一些重要表结构。

常见包括:

  • Export Table
  • Import Table
  • Resource Table
  • Exception Table
  • Base Relocation Table
  • TLS Table
  • Load Config Table
  • IAT

你不需要一开始全部掌握,但要知道:

PE 中很多高级结构不是靠节名固定定位,而是通过 Data Directory 指向。

例如 Import Table 的位置由 Data Directory 告诉 Loader。


21. Import Table 是什么

Import Table 保存程序依赖的 DLL 和函数信息。

例如一个程序可能导入:

1
2
3
4
5
6
7
8
KERNEL32.dll
CreateFileA
WriteFile
CloseHandle
USER32.dll
MessageBoxA
MSVCRT.dll
printf

这些导入告诉 Windows Loader:

1
运行这个程序前,需要加载这些 DLL,并解析这些函数地址。

逆向分析中,Import Table 是非常重要的行为线索。

如果程序导入:

1
2
3
4
5
6
7
CreateProcessW
VirtualAlloc
WriteProcessMemory
CreateRemoteThread
RegSetValueExW
InternetOpenW
connect

你可以初步推测它可能具有进程、内存、注册表、网络相关行为。


22. IAT 是什么

IAT 全称:

1
Import Address Table

中文常译为:

1
导入地址表

程序调用外部 DLL 函数时,需要知道函数实际地址。

Windows Loader 加载程序时,会把导入函数的实际地址填入 IAT。

程序后续调用外部 API 时,可能通过 IAT 间接调用。

简化理解:

1
2
Import Table 描述要导入什么
IAT 保存导入函数运行时地址

IAT 对逆向和 Hook 都很重要。


23. IAT 为什么重要

IAT 重要原因:

  1. 能反映程序使用了哪些外部 API
  2. 程序调用外部 API 时可能通过 IAT
  3. 安全软件和分析工具可以监控 IAT
  4. 恶意代码可能修改 IAT 实现 Hook
  5. 加壳程序可能重建 IAT
  6. 脱壳分析常涉及 IAT 修复

例如:

1
2
程序调用 MessageBoxA
实际可能是 call qword ptr [MessageBoxA 的 IAT 项]

这个 IAT 项中保存的是 user32.dll!MessageBoxA 的实际地址。


24. Export Table 是什么

Export Table 保存一个 PE 文件向外提供的函数或符号。

DLL 常有导出表。

例如:

1
2
kernel32.dll 导出 CreateFileW、ReadFile、WriteFile 等函数
user32.dll 导出 MessageBoxA 等函数

EXE 也可以有导出表,但 DLL 更常见。

逆向 DLL 时,Export Table 可以告诉你:

  • 这个 DLL 提供哪些函数
  • 函数名是什么
  • 函数序号是什么
  • 函数 RVA 是多少

25. DLL 加载过程的直觉

Windows 程序启动时,Loader 会:

  1. 映射 EXE 到进程地址空间
  2. 读取 Import Table
  3. 找到依赖的 DLL
  4. 把 DLL 映射到进程地址空间
  5. 解析导入函数地址
  6. 填写 IAT
  7. 处理重定位
  8. 初始化 TLS 等结构
  9. 调用入口点

所以一个 Windows 进程通常不只有 EXE 本身,还会加载很多 DLL。

在 Process Explorer 或 x64dbg 中可以看到模块列表。


26. 静态导入和动态加载

26.1 静态导入

程序在 Import Table 中明确列出依赖 DLL 和函数。

例如:

1
KERNEL32.dll!CreateFileW

这种容易被 PE 工具看到。


26.2 动态加载

程序运行时调用:

1
2
LoadLibraryA/W
GetProcAddress

动态加载 DLL 并解析函数地址。

例如:

1
2
HMODULE h = LoadLibraryA("kernel32.dll");
FARPROC p = GetProcAddress(h, "VirtualAlloc");

这样 VirtualAlloc 可能不会直接出现在 Import Table 中。

恶意代码常用动态加载隐藏敏感 API。


27. TLS Callback 是什么

TLS 全称:

1
Thread Local Storage

PE 中可以有 TLS Callback。

TLS Callback 的特点是:

1
它可能在程序入口点之前执行。

这对逆向很重要。

因为你以为程序从 Entry Point 开始,实际上在入口点之前可能已经执行了 TLS Callback。

恶意代码和壳有时会利用 TLS Callback 做:

  • 反调试
  • 解密代码
  • 初始化隐藏逻辑
  • 检查环境

所以 PE 分析时,如果行为很早发生,要检查 TLS Table。


28. PE 节权限和异常节名

PE Section 有权限属性。

常见权限包括:

  • 可读
  • 可写
  • 可执行

正常情况下:

1
2
3
4
.text   可读 + 可执行
.rdata 可读
.data 可读 + 可写
.rsrc 可读

如果看到:

1
2
3
4
某节可写 + 可执行
节名很奇怪
节熵很高
节大小异常

就要进一步分析。

加壳或恶意样本中可能出现:

1
2
3
4
5
UPX0
UPX1
.aspack
.vmp0
随机节名

这些不一定都恶意,但可能表示压缩、加壳或保护。


29. PE 与 ELF 的对照

主题 ELF PE
常见系统 Linux / Unix-like Windows
魔数 7f 45 4c 46 MZ + PE\0\0
可执行文件 无固定扩展名 常见 .exe
共享库 .so .dll
代码节 .text .text
只读数据 .rodata .rdata
数据节 .data / .bss .data
装载视角 Program Header PE Header + Section Table
动态导入 PLT/GOT、dynsym Import Table、IAT
重定位 relocation sections .reloc
资源 较少内建资源机制 .rsrc 常见

两者思想相似:

1
都是告诉操作系统如何把文件映射到内存并开始执行。

但具体结构和工具不同。


30. PE 和逆向工程

逆向 PE 程序时,可以按这个顺序观察:

  1. 用 Detect It Easy 判断文件类型、架构、是否加壳
  2. 用 PE-bear 查看 Header、Section、Import Table
  3. 用 strings 或工具查看字符串
  4. 用 Ghidra / IDA 查看函数和反编译
  5. 用 x64dbg 动态调试入口点和关键 API
  6. 用 Process Monitor 观察文件、注册表、进程行为
  7. 用 Wireshark 观察网络行为

PE 分析不只是看静态结构,还要结合运行行为。


31. PE 和漏洞分析

Windows 漏洞分析中,PE 信息可以回答:

  • 程序是 32 位还是 64 位
  • 是否启用 ASLR
  • 是否启用 DEP
  • 是否启用 CFG
  • 是否有 SafeSEH / SEHOP
  • 程序基址是多少
  • 哪些模块被加载
  • IAT 中有哪些 API
  • 哪些节可写/可执行
  • 崩溃地址属于哪个模块

例如 x64dbg 中看到崩溃地址:

1
00007FF6A1234567

你需要判断:

1
这个地址属于主程序?某个 DLL?堆?栈?

这和模块加载和 PE 基址有关。


32. PE 和恶意代码分析

恶意代码分析中,PE 是最常见对象之一。

静态分析时常看:

  • 文件哈希
  • 编译时间戳
  • 入口点
  • 节名和节权限
  • 导入表
  • 字符串
  • 资源节
  • 是否加壳
  • TLS Callback

动态分析时常看:

  • 文件行为
  • 注册表行为
  • 网络行为
  • 进程树
  • API 调用
  • 内存分配和权限修改
  • 是否释放或注入 payload

PE 结构提供静态线索,动态工具验证真实行为。


33. Windows 实验:用 Detect It Easy 识别 PE

准备一个 exe,例如 pe_demo.exe。

用 Detect It Easy 打开。

观察:

  • 文件类型是否为 PE
  • 32 位还是 64 位
  • 编译器或链接器信息
  • 是否可能加壳
  • 入口点
  • 节信息

提交时记录:

1
2
3
4
5
1. 文件类型
2. 架构
3. 编译器识别结果
4. 入口点
5. 是否有加壳迹象

34. Windows 实验:用 PE-bear 查看结构

用 PE-bear 打开 pe_demo.exe。

重点查看:

  • DOS Header
  • NT Headers
  • File Header
  • Optional Header
  • Section Headers
  • Import Table
  • IAT
  • Resource

记录:

  • MZ 是否存在
  • PE\0\0 是否存在
  • ImageBase
  • AddressOfEntryPoint
  • Section 数量
  • .text、.rdata、.data、.rsrc 是否存在
  • 导入了哪些 DLL
  • 导入了哪些函数

35. Windows 实验:用 Ghidra 查看导入和字符串

用 Ghidra 打开 pe_demo.exe。

步骤:

  1. Import File
  2. 运行自动分析
  3. 查看 Symbol Tree
  4. 查看 Imports
  5. 查看 Defined Strings
  6. 找 hello pe、pe_demo_output.txt
  7. 查看字符串 XREF
  8. 找到调用 CreateFileA、WriteFile、MessageBoxA 的位置
  9. 查看 Decompiler 伪代码

思考:

  • 导入函数是否能帮助理解行为?
  • 字符串是否能定位关键逻辑?
  • 伪代码是否和原始 C 程序接近?

36. Windows 实验:用 x64dbg 观察入口点和 API

用 x64dbg 打开 pe_demo.exe。

练习:

  1. 运行到系统断点或入口点
  2. 查看模块基址
  3. 查看入口点附近代码
  4. 在 CreateFileA 或 MessageBoxA 下断点
  5. 运行程序
  6. 命中断点后查看参数寄存器
  7. 查看返回值 RAX
  8. 查看栈和内存

重点观察:

  • RIP 当前属于哪个模块
  • 主程序基址是多少
  • API 参数在哪里
  • 文件名字符串在哪里
  • API 调用是否成功

37. Windows 实验:Process Monitor 观察 PE 行为

用 Process Monitor:

  1. 清空事件
  2. 设置过滤器:Process Name is pe_demo.exe
  3. 运行程序
  4. 观察文件事件
  5. 如果有 MessageBox,确认程序行为

重点看:

  • CreateFile
  • WriteFile
  • CloseFile
  • Image Load 事件

记录:

1
2
3
4
1. 程序创建了哪个文件
2. 写入是否成功
3. 加载了哪些 DLL
4. 行为是否和 Import Table 对应

38. 本节重点总结

你需要记住这些核心结论:

  1. PE 是 Windows 常见可执行文件格式,常见于 .exe、.dll、.sys。
  2. PE 文件开头通常有 MZ,并通过 e_lfanew 找到 PE\0\0 签名。
  3. Optional Header 中有入口点、ImageBase、Data Directory 等装载关键信息。
  4. RVA、VA、File Offset 是 PE 分析中的三个重要地址概念。
  5. Section Table 描述 .text、.rdata、.data、.rsrc 等节的位置、大小和权限。
  6. Import Table 描述程序需要哪些 DLL 和函数。
  7. IAT 保存导入函数运行时实际地址,是逆向、Hook、脱壳分析的重要结构。
  8. DLL 加载和导入解析由 Windows Loader 完成。
  9. TLS Callback 可能在入口点之前执行,恶意代码和壳可能利用它。
  10. PE 分析需要结合静态结构和动态行为工具。

39. 本节课后作业

作业 1:PE 基本识别

选择一个简单 exe,用 Detect It Easy 或 PE-bear 查看。

提交内容:

1
2
3
4
5
6
7
1. 文件名
2. 是否为 PE
3. 32 位还是 64 位
4. 是否有 MZ
5. 是否有 PE\0\0
6. 入口点 RVA
7. ImageBase

作业 2:Section Table 分析

用 PE-bear 查看 Section。

提交内容:

1
2
3
4
5
6
7
1. Section 数量
2. 每个 Section 名称
3. .text 的权限
4. .rdata 中可能有什么
5. .data 中可能有什么
6. 是否存在 .rsrc
7. 是否存在异常节名或 RWX 权限

作业 3:Import Table 和 IAT 分析

查看 Import Table。

提交内容:

1
2
3
4
5
1. 导入了哪些 DLL
2. 每个 DLL 中至少 3 个导入函数
3. 哪些 API 暗示文件行为
4. 哪些 API 暗示进程或内存行为
5. Import Table 和 IAT 的区别

作业 4:字符串和 XREF 分析

用 Ghidra 打开 exe。

提交内容:

1
2
3
4
5
1. 发现的关键字符串
2. 字符串位于哪个区域或节
3. 哪个函数引用了该字符串
4. 该函数大致做什么
5. 字符串如何帮助定位关键逻辑

作业 5:动态调试 API 参数

用 x64dbg:

  1. 在一个导入 API 上下断点,例如 CreateFileA/W、MessageBoxA、WriteFile
  2. 运行程序
  3. 查看参数寄存器和返回值

提交内容:

1
2
3
4
5
6
1. 下断点的 API
2. 命中断点时 RIP
3. RCX/RDX/R8/R9 的值
4. 参数指向的字符串或数据
5. RAX 返回值
6. 这个 API 调用说明了什么行为

作业 6:Process Monitor 行为验证

运行程序并用 Process Monitor 观察。

提交内容:

1
2
3
4
5
1. 过滤条件
2. 观察到的文件事件
3. 观察到的 Image Load 事件
4. 行为是否和导入表一致
5. 静态分析和动态分析各自给了什么证据

40. 自测题

题 1

PE 的全称是什么?常见哪些文件扩展名使用 PE 格式?

题 2

MZ 和 PE\0\0 分别是什么?

题 3

e_lfanew 的作用是什么?

题 4

RVA、VA、File Offset 有什么区别?

题 5

.text、.rdata、.data、.rsrc 通常分别存放什么?

题 6

Import Table 和 IAT 有什么区别?

题 7

为什么 TLS Callback 对逆向分析很重要?

题 8

为什么恶意代码可能动态解析 API?

题 9

PE 和 ELF 有哪些相似点?


41. 自测题参考答案

答 1

PE 全称是 Portable Executable。Windows 下常见 .exe、.dll、.sys、.scr、.ocx 等文件可能使用 PE 格式。

答 2

MZ 是 DOS Header 开头的魔数,表示这是典型 PE 文件开头;PE\0\0 是 PE Signature,位于 e_lfanew 指向的位置,用于标识真正的 PE Header。

答 3

e_lfanew 位于 DOS Header 中,用于指向 PE Header 在文件中的偏移。Windows Loader 通过它找到 PE\0\0 和后续 PE 结构。

答 4

RVA 是相对虚拟地址,相对于 ImageBase;VA 是程序加载到内存后的虚拟地址;File Offset 是数据在磁盘文件中的偏移。三者不是同一个概念,需要通过 ImageBase 和 Section Table 转换。

答 5

.text 通常存放代码;.rdata 存放只读数据、字符串和部分导入相关信息;.data 存放已初始化可写全局数据;.rsrc 存放图标、菜单、版本信息、字符串表、嵌入文件等资源。

答 6

Import Table 描述程序需要导入哪些 DLL 和函数;IAT 保存这些导入函数在运行时解析后的实际地址,程序调用外部 API 时可能通过 IAT 间接调用。

答 7

因为 TLS Callback 可能在程序入口点之前执行。恶意代码和加壳程序可能利用它进行反调试、解密、环境检查或隐藏初始化逻辑。

答 8

动态解析 API 可以减少静态导入表中的敏感函数暴露,也能在运行时按需加载 DLL 和函数。恶意代码常用这种方式隐藏行为或增加分析难度。

答 9

PE 和 ELF 都是可执行文件格式,都描述程序如何被加载到内存、入口点在哪里、有哪些代码和数据区域、依赖哪些外部库、如何处理重定位和动态链接等。


42. 下一节预告

下一节课会讲:

1
线程是什么

你会学习:

  • 进程和线程的区别
  • 一个进程内多个线程共享什么
  • 每个线程私有什么
  • 线程栈
  • Linux pthread
  • Windows Thread
  • 为什么恶意代码和系统程序经常创建线程
隐藏
换装
本文作者:burpow
本文链接:https://youthfulnesszxx.github.io/2026/05/28/第12节-PE文件格式与Windows装载/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可