逆向工程实战手册 第 3 章

第 3 章 二进制文件格式基础

📍 知识点地图 | 主题:二进制文件格式 | 前置:第1章 | 后续:第4-5章 | 核心概念:ELF/PE/Mach-O、magic、节区、导入导出

3.1 为什么必须懂文件格式

所有静态分析工具(readelf、IDA、Ghidra、radare2)都是"按格式解析"。不懂格式,就看不懂工具输出;遇到格式被破坏/定制的样本,还能手动解析绕过工具限制。

3.2 通用概念

  • Magic Number:文件头部的魔数,用于识别类型。xxd | head 看前几字节。
  • 7f 45 4c 46 = ELF;4d 5a = PE (MZ);ca fe ba be = Mach-O fat;50 4b = ZIP/APK/JAR
  • 节区(Sections):逻辑分组(代码、数据、只读数据、符号表……)
  • 段(Segments):运行时内存布局(加载到哪些地址)
  • 符号表(Symbols):函数/变量名字,strip 后消失
  • 导入(Imports)/ 导出(Exports):调用的外部函数 / 暴露的函数

3.3 ELF(Linux / Android 原生)

readelf -h file 看文件头;readelf -l 看程序头(段);readelf -S 看节区。

关键节区:

节区 内容
.text 代码
.rodata 只读数据(字符串、常量表)
.data / .bss 全局变量
.plt / .got 动态调用跳板 / 全局偏移表
.dynsym / .symtab 动态符号 / 全符号表

常用命令:

file binary                    # 类型+架构
readelf -h binary              # 头
readelf -l binary              # 段
readelf -S binary              # 节区
readelf -d binary              # 动态段(依赖库)
objdump -d binary              # 反汇编
objdump -T binary              # 动态符号
nm binary                      # 符号表
strip 后的 ELF: nm 没输出   rabin2 -z / 字符串+交叉引用定位

三种加载视角(关键!)

文件偏移 (file offset)  ≠  虚拟地址 (VA)  ≠  逻辑地址 (RVA/Offset)
# 工具里看到的是 VA,十六进制编辑器里是 file offset
# 转换: readelf -S 看每个节的 Offset 和 Addr 的差值(delta)
# 修复损坏的 ELF 需要手动解析 Program Header

案例:ELF 节区头被破坏(Section Header 损坏)时,readelf -S 报错,但 readelf -l(只看程序头)仍可用,Ghidra/IDA 也能靠程序头加载。损坏节区头是常见的反分析手段。

3.4 PE(Windows exe/dll/sys)

结构:DOS 头(MZ) → PE 头 → 节区表 → 各节区。

节区 内容
.text 代码
.rdata 只读数据
.data 全局变量
.idata 导入表
.reloc 重定位
  • 工具:dumpbin /headers(VS 自带)、objdump -p、pefile(Python)、rabin2
  • 入口:AddressOfEntryPoint(通常是 mainCRTStartupmain
  • 导入表是黄金线索:看导入函数猜功能(GetProcAddress+哈希解析导入 → 反分析)

3.5 Mach-O(macOS / iOS)

关键段:__TEXT(代码+__cstring 字符串)、__DATA(全局+__objc_* ObjC 元数据)、__LINKEDIT(符号+签名)。

  • fat/universal 二进制:一个文件里多个架构,lipo -info
  • 工具:otool -l/-L/-tnmjtool2class-dump
  • 代码签名codesign -dv 查看;修改后需重签(codesign -f -s - 临时 ad-hoc)
  • ObjC 运行时:类信息在 __objc_methname 等节区 → class-dump 直接导出类结构

3.6 DEX / APK(Android)

  • APK = ZIP 包:classes.dex(Java 字节码)+ AndroidManifest.xml(二进制 XML)+ res/ + lib/*.so
  • DEX → jadx 反编译为 Java;smali 是 DEX 的汇编形式(baksmali/apktool)
  • 加固 APK:classes.dex 被加密,真实 dex 运行时才解密 → 需要脱壳(Frida dump / FART 等)

3.7 其他格式速查

格式 识别 分析
Python .pyc 头部 \x61\x0d\x0d\x0a uncompyle6 / pycdc / dis
WASM \0asm wasm2c / wabt / Ghidra
.NET PE 存在 CLR 头(COM descriptor) dnSpy / ILSpy / monodis
Java .class CA FE BA BE javap / CFR
UPX 加壳 段名 UPX0/UPX1 upx -d 脱壳
固件 自定义 binwalk / unblob
HarmonyOS .abc HAP 内 abc-decompiler

3.8 快速识别工具组合

file target                    # 第一手信息
xxd target | head -3           # 看 magic
rabin2 -I target               # radare2 全家信息(架构/入口/类型)
rabin2 -S target               # 节区
rabin2 -z target               # 字符串
rabin2 -i target               # 导入
rabin2 -E target               # 导出

动手练习

  1. 找一个 ELF 和 PE,分别用 readelf/rabin2 打印节区,找到 .text 的文件偏移和虚拟地址,算出 delta。
  2. 分析一个可执行文件的导入表,凭导入函数猜出它 80% 的功能。
  3. file+xxd 识别:一个 APK、一个 .pyc、一个 WASM(可以自己造)。

深入阅读

  • 仓库:skills/reverse-engineering/elf-analysis.md(ELF 深度分析、ARM64 寄存器、注入技术、损坏 ELF 修复)
  • 仓库:skills/reverse-engineering/platforms.md(Mach-O、固件、内核驱动、CAN 总线)
  • 仓库:skills/reverse-engineering/tools.md(Python 字节码、WASM、.NET、UPX 等分析)
  • 仓库:skills/reverse-engineering/field-notes.md(Binary Types 章节)