第 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(通常是mainCRTStartup→main) - 导入表是黄金线索:看导入函数猜功能(
GetProcAddress+哈希解析导入 → 反分析)
3.5 Mach-O(macOS / iOS)
关键段:__TEXT(代码+__cstring 字符串)、__DATA(全局+__objc_* ObjC 元数据)、__LINKEDIT(符号+签名)。
- fat/universal 二进制:一个文件里多个架构,
lipo -info - 工具:
otool -l/-L/-t、nm、jtool2、class-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 # 导出
动手练习
- 找一个 ELF 和 PE,分别用
readelf/rabin2打印节区,找到.text的文件偏移和虚拟地址,算出 delta。 - 分析一个可执行文件的导入表,凭导入函数猜出它 80% 的功能。
- 用
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 章节)