Skip to content

一、PE (Portable Executable) 文件结构

PE (Portable Executable) 是 Windows 操作系统下的可执行文件格式标准,用于 EXE、DLL、SYS、OCX 等文件类型。

1.基本组成部分

(1)DOS 头部和 DOS Stub

  • DOS Header (IMAGE_DOS_HEADER)
    • 标志位:e_magic (0x4D5A "MZ") # 小端方案
    • e_lfanew 字段指向 PE 头部的偏移量
  • DOS Stub
    • 简单的 DOS 程序,通常显示 "This program cannot be run in DOS mode"

(2)PE 文件头

  • PE Signature ("PE\0\0")
  • COFF 文件头 (IMAGE_FILE_HEADER)
    • 包含机器类型、节区数量、时间戳等
  • 可选头 (IMAGE_OPTIONAL_HEADER)
    • 重要字段:入口点地址、ImageBase、节区对齐等
    • 32位和64位版本结构不同

(3)节区表 (Section Table)

  • 描述每个节区的属性(名称、虚拟大小、虚拟地址、文件大小、文件偏移、标志等)
  • 常见节区:
    • .text - 代码段
    • .data - 初始化数据
    • .rdata - 只读数据
    • .idata - 导入表
    • .edata - 导出表
    • .rsrc - 资源
    • .reloc - 重定位信息

(4)节区数据

  • 实际包含代码和数据的部分

2.重要数据结构

(1)导入表 (Import Table)

  • 描述程序依赖的外部DLL和函数
  • 通过 IMAGE_DIRECTORY_ENTRY_IMPORT 目录项定位
  • 包含 IMAGE_IMPORT_DESCRIPTOR 数组

(2) 导出表 (Export Table)

  • 描述DLL导出的函数
  • 通过 IMAGE_DIRECTORY_ENTRY_EXPORT 目录项定位
  • 包含 IMAGE_EXPORT_DIRECTORY 结构

(3) 资源表 (Resource Table)

  • 包含程序的图标、对话框、字符串等资源
  • 多级树形结构

(4) 重定位表 (Relocation Table)

  • 包含需要重定位的地址列表
  • 对DLL很重要,因为DLL不能总是加载到首选基址

(5) TLS (Thread Local Storage) 表

  • 包含线程本地存储的回调函数

3.PE 文件分析工具

  1. 命令行工具:

    • dumpbin (Visual Studio 附带)
    • objdump (GNU工具链)
    • pedump (专用PE分析工具)
  2. 图形化工具:

    • PEView
    • CFF Explorer
    • PEiD (检测加壳)
    • IDA Pro (反汇编)
    • Ghidra (NSA开源逆向工具)
  3. Python库:

    • pefile (最流行的PE解析Python库)
    • LIEF (跨平台二进制解析库)

4.PE 文件格式示例

cpp
// 简化的DOS头部结构
typedef struct _IMAGE_DOS_HEADER {
    WORD e_magic;    // "MZ"
    // ... 其他字段 ...
    LONG e_lfanew;   // PE头偏移
} IMAGE_DOS_HEADER;

// PE签名后的COFF文件头
typedef struct _IMAGE_FILE_HEADER {
    WORD Machine;
    WORD NumberOfSections;
    DWORD TimeDateStamp;
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD SizeOfOptionalHeader;
    WORD Characteristics;
} IMAGE_FILE_HEADER;

5.PE 文件分析示例 (使用 pefile)

python
import pefile

pe = pefile.PE("notepad.exe")

print("PE Sections:")
for section in pe.sections:
    print(f"{section.Name.decode().strip()}: VA={section.VirtualAddress:08x} Size={section.Misc_VirtualSize:08x}")

print("\nImported DLLs:")
for entry in pe.DIRECTORY_ENTRY_IMPORT:
    print(entry.dll.decode())
    for imp in entry.imports:
        print(f"\t{imp.name.decode() if imp.name else str(imp.ordinal)}")

6.加壳与混淆

许多恶意软件会对PE文件进行加壳或混淆:

  • 压缩壳:UPX、ASPack等
  • 加密壳:Themida、VMProtect等
  • 自定义壳

分析加壳程序通常需要先脱壳或动态分析。

7.64位PE (PE32+)

64位PE结构与32位类似,主要区别:

  • 魔法数字为PE32+
  • 可选头扩展为IMAGE_OPTIONAL_HEADER64
  • 地址和指针变为64位

理解PE结构是Windows平台二进制分析的基础,对于安全研究人员和逆向工程师至关重要。

8.题目复现

题目:[PE结构]

  • 题目来源:polarctf-reverse-[PE结构]

image-20250419111338380

  • 解题:

file命令进行文件信息查看:file [文件名]

image-20250419111515430

出现这种情况通常表示该文件可能已损坏、不完整或被加壳/混淆,此处是PE结构存在问题

010打开该文件,发现DOS头部不正确,MZ(Mark Zbikowski)2个字符(即0x4D, 0x5A)开头,被称为DOS签名。

屏幕截图2025-04-19111722

改为正确的DOS头部

image-20250419112215888

保存后运行,得到flag

image-20250419112244392

滇ICP备2025057983号-1