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\0e_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);

字符串 hellotitle 可能在 .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 pepe_demo_output.txt
  7. 查看字符串 XREF
  8. 找到调用 CreateFileAWriteFileMessageBoxA 的位置
  9. 查看 Decompiler 伪代码

思考:

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

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

用 x64dbg 打开 pe_demo.exe

练习:

  1. 运行到系统断点或入口点
  2. 查看模块基址
  3. 查看入口点附近代码
  4. CreateFileAMessageBoxA 下断点
  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/WMessageBoxAWriteFile
  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

MZPE\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 协议进行许可