原力注入

ELF 分析 Skill:轻松掌握 Linux 二进制文件格式 ELF 的秘密

我们的 C 程序编译通过了,但一运行就 Segmentation fault (core dumped)。没有堆栈回溯、没有行号、只有冷冷的一行错误——我们盯着屏幕,不知道是哪个指针越了界、哪次 strcpy 写穿了缓冲区。我们想用 GDB 加载 core dump,发现二进制是 stripped 的,符号表被剥离了;想查安全特征,看看编译时到底有没有开 Stack Canary,又不知道从哪里下手。

这时候需要的是一个能读懂 ELF 文件的搭档。ELF(Executable and Linkable Format)是 Linux 系统上所有可执行文件、共享库和内核模块的通用格式。我们需要的答案——架构、符号、安全特征、库依赖、反汇编——全都写在 ELF 的结构里,只是散落在几十个命令的输出中,等着人去拼凑。

本文从 ELF 基础知识出发,介绍一套专门为此设计的 Claude Code 分析技能——elf-analyzer(ELF 结构分析)、binary-reverse(逆向工程)和 linux-pwn(漏洞利用)。这三个技能将专业的二进制分析知识编码为 AI 可执行的指令,不用记住几十个命令行参数,也能像资深工程师一样拆解 ELF 文件的秘密。


一、背景:每个 Linux 用户都会遇见的 ELF

1.1 一个无处不在的格式

打开终端,运行一条最简单的命令:

file /bin/ls

会看到这样的输出:

/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped

ELF —— Executable and Linkable Format(可执行和可链接格式)—— 是 Linux 世界的通用语言。我们运行的每一个命令、加载的每一个共享库(.so 文件)、内核加载的每一个模块(.ko 文件),甚至操作系统内核本身,都遵循 ELF 规范。

图片

入门文章 - Linux 二进制文件格式 ELF 入门为我们打开了理解 ELF 的大门。从 ELF Header 中解读架构(32 位还是 64 位?)、端序(小端还是大端?)、文件类型(可执行还是共享库?),到程序头和节头的区别,再到静态链接与动态链接的分野——这些基础知识是二进制分析的地基。

1.2 ELF 的四个应用场景

正如那篇 elf_101 文章指出的,理解 ELF 格式的动机来自四个方向:

  • • 理解操作系统:进程是如何从磁盘上的二进制文件变成内存中的运行实体的?
  • • 软件开发:为什么编译出来的文件这么大?为什么链接失败?stack smash 是什么意思?
  • • 数字取证(DFIR):这个可疑的文件到底是什么?它会在系统上做什么?
  • • 恶意软件分析:这个 ELF 样本是否包含 C2 通信、反调试、持久化机制?

这四个场景有一个共同点:它们都需要我们阅读并理解 ELF 文件的内部结构。而这正是我们技能设计的起点。


二、问题:手工 ELF 分析的三道坎

亲手分析过一个 ELF 文件的人,一定经历过这三道坎。

2.1 命令太多,参数记不住

elf_101 文章帮我们理解了 ELF 的基础结构,但动手分析时很快就会发现——命令实在太多了。

分析一个 ELF 文件至少需要七八个命令:

file binary                 # 初步识别
readelf -h binary           # ELF 头部
readelf -l binary           # 程序头(运行时视图)
readelf -S binary           # 节头(链接视图)
readelf -d binary           # 动态链接信息
readelf -s binary           # 符号表
objdump -d binary           # 反汇编
strings binary              # 字符串提取
ldd binary                  # 库依赖

每个命令还有各种参数变体,不同发行版上命令名称可能不同。readelf 还是 eu-readelf?objdump 还是 llvm-objdump?checksec 安装了吗?每切换到一个新环境,就要重新梳理一遍工具链。

2.2 输出太多,重点找不到

readelf -S /usr/bin/ps 输出 29 个 section header,objdump -d 可能输出几万行反汇编。真正的关键信息——比如 "这个二进制有 Full RELRO,GOT 不可写"——隐藏在大量元数据中。从这些输出中手动提取关键决策信息,是一个费时费力的过程。

2.3 知识太散,上下串联难

最重要的不是"看到什么",而是"这意味着什么"。看看这些场景:

  • • 看到 GNU_STACK 的 Flags 是 RW(不是 RWE)—— 意味着 NX 启用,栈不可执行,需要 ROP
  • • 看到 BIND_NOW 和 GNU_RELRO 同时存在 —— 意味着 Full RELRO,GOT 覆写路径封堵
  • • 看到 Type: EXEC —— 意味着非 PIE,地址固定,不需要信息泄露就能构建 ROP 链
  • • 看到 not stripped —— 意味着符号表完整,可以直接用函数名定位

这些"如果-那么"的决策链,构成了资深工程师与新手的本质差异。但谁来帮我们记住并在合适的时机提醒这些决策呢?


三、方案:三个 Claude Code Skill,一条完整分析链路

基于对 GitHub 上 6 个核心技能仓库和 4800+ 个 SKILL.md 文件的深入调研,我们构建了三款 Claude Code 技能。它们分别覆盖 ELF 分析链路的不同阶段,可以独立使用,也可以接力串联。

3.1 技能总览

                    ┌──────────────────┐
                    │   elf-analyzer   │  ← ELF 格式分析 (起点)
                    │  (8 文件, 2541行) │
                    └────────┬─────────┘
                             │ triage 结果
              ┌──────────────┼──────────────┐
              ▼              │              ▼
  ┌───────────────────┐      │    ┌──────────────────┐
  │  binary-reverse   │◄─────┘    │    linux-pwn     │  ← 漏洞利用
  │ (6 文件, 2038行)   │           │  (7 文件, 2037行)  │
  │  通用逆向工程       │           │  二进制漏洞利用    │
  └───────────────────┘           └──────────────────┘

3.2 elf-analyzer:我们的 ELF 体检医生

一句话定位:自动完成从文件识别到安全态势评估的全流程。

当我们把 /usr/bin/ps 交给它,它会自动完成 elf_101 文章中描述的所有检查步骤——file → checksec → readelf -h/-l/-d/-s → ldd → strings——并输出一份结构化的分析报告。

它的知识库(7 个 reference 文件)覆盖了 ELF 的所有核心维度:

Reference 文件
解决的问题
elf-triage.md
如何系统化地收集 ELF 基本信息?460 行的完整命令序列
elf-headers.md
ELF Header 中每个字节的含义?Program Header 和 Section Header 的区别?
elf-dynamic.md
GOT/PLT 的工作原理?LD_PRELOAD 如何劫持函数?rpath 注入怎么检测?
elf-security.md
RELRO/Canary/NX/PIE/seccomp/FORTIFY — 每个缓解措施怎么检测?怎么绕过?
static-analysis.md
objdump/radare2/Ghidra — stripped 二进制怎么分析?
dynamic-analysis.md
GDB/strace/ltrace/Frida — 什么时候用哪个?断点怎么设?
unpacking.md
UPX 壳怎么脱?自定义壳的入口点怎么找?

使用示例:

在 Claude Code 中打开终端,直接对话:

"分析 /usr/bin/ps 的安全特征"

Claude 会自动探测工具链、执行 triage、对比 elf-security.md 中的规则,然后输出:

## ELF 分析结果: /usr/bin/ps

### 基本信息
- 架构: x86-64 | 端序: little-endian | 链接: dynamic
- Stripped: yes | 加壳: no

### 安全态势
| RELRO | Canary | NX | PIE | seccomp | FORTIFY |
|-------|--------|----|----|---------|---------|
| Partial| Yes    | Yes| Yes| No      | Yes     |

### 关键发现
- Partial RELRO: GOT[3-*] 可写,存在 ret2dlresolve 可能
- NX enabled: 需要 ROP/ret2libc
- PIE enabled: 需要信息泄露获取代码基址
- 反调试检测: ptrace 调用未发现

### 进一步建议
- 如需漏洞利用 → 切换到 linux-pwn 技能
- 如需深入理解代码逻辑 → 切换到 binary-reverse 技能

3.3 binary-reverse:我们的代码透视镜

一句话定位:跨越反汇编、混淆和编程语言的逆向工程工具箱。

Triage 回答了"这个二进制有什么特征",binary-reverse 回答了"它的代码在做什么"。它覆盖了 elf_101 文章中提到的"更进一步"的部分——当 strings 和 file 不够用的时候。

知识库(5 个 reference 文件):

Reference 文件
解决的问题
disasm-patterns.mdpush rbp; mov rbp, rsp
 是什么?ARM64 的 stp x29, x30, [sp, #-32]! 是什么意思?495 行的模式库
crypto-patterns.md
那段循环是不是 AES?63 7C 77 7B 是什么?362 行的密码学指纹库
anti-analysis.md
它在检测调试器吗?ptrace(PTRACE_TRACEME) 怎么绕过?455 行的反分析技术全解
language-specific-re.md
这个 Go 二进制怎么分析?Rust 的 Option/Result 在反汇编中长什么样?
advanced-tools.md
angr 怎么自动解出 flag?Qiling 怎么跨平台模拟 ARM 代码?

使用示例:

"这个二进制里有一段 XOR 循环,帮我分析它在做什么"

Claude 会加载 disasm-patterns.md 和 crypto-patterns.md,将反汇编片段与模式库对照:

检测到的模式:
1. 函数序言: 标准 x86-64 (push rbp; mov rbp, rsp; sub rsp, 0x40)
2. XOR 循环: xor [rsi+rcx], 0x55 → 单字节 XOR 解码,key = 0x55
3. 后续调用: call printf@plt → 解码结果被打印
4. 未检测到 AES/RC4/Base64 常量

结论: 这是一个简单的 XOR 字符串去混淆函数,key = 0x55。

或者面对一个 Go 编译的二进制:

"这个二进制是 Go 写的,stripped 了,帮我恢复函数名"

Claude 会加载 language-specific-re.md,自动调用 GoReSym,基于 pclntab 恢复函数符号。

3.4 linux-pwn:我们的漏洞利用军师

一句话定位:从漏洞发现到完整 exploit 的技术全栈。

当 elf-analyzer 完成了安全态势评估,linux-pwn 接手回答"这能利用吗?怎么利用?"

知识库(6 个 reference 文件):

Reference 文件
回答的关键问题
exploit-primitives.mdgets()
 有多危险?printf(user_input) 能怎么利用?漏洞评分算法
heap-exploitation.md
tcache poisoning 怎么操作?House of Apple 2 在 glibc 2.34+ 怎么用?FSOP 的两跳绕过是什么?
rop-advanced.md
找不到 pop rdx 怎么办?ret2csu 万能 gadget 怎么用?SROP 一次调用如何控制所有寄存器?
format-string-deep.md%n
 被过滤了怎么办?盲打 pwn(没有二进制文件)怎么操作?__printf_chk 如何绕过?
kernel-exploitation.md
怎么从内核模块漏洞提权到 root?prepare_kernel_cred + commit_creds 链怎么构造?KASLR 怎么绕过?
kernel-modules.md
.ko 模块的特殊 section 有哪些?eBPF 程序的 verifier 怎么分析?io_uring 攻击面在哪?

使用示例:

用户: "这个二进制 checksec 显示 NX enabled, PIE disabled, Partial RELRO, Canary disabled。而且代码里用了 gets(),怎么利用?"

Claude 会加载 exploit-primitives.md → 自动路由到 rop-advanced.md:

安全态势: NX=Yes, PIE=No, RELRO=Partial, Canary=No

利用策略:
1. gets() 无条件栈溢出 → 覆盖返回地址
2. NX enabled → 不能直接栈 shellcode → 需要 ROP/ret2libc
3. PIE disabled → 所有代码地址固定 → 不需要泄露基址
4. Partial RELRO → GOT 可写 → ret2dl_resolve 也可行
5. Canary disabled → 无需泄露 canary,直接溢出即可

推荐路径 (最简单):
  ROP 链: pop rdi; ret → "/bin/sh" 字符串地址 → system@plt
  (所有地址固定,objdump 直接查)

进阶路径 (不依赖 libc 版本):
  ret2dl_resolve: 伪造 Elf64_Sym("system") → _dl_runtime_resolve

用户: "如果这个二进制是 PIE enabled 呢?"

区别: PIE enabled → 代码基址随机 → 需要先泄露一个代码段地址
额外步骤: 在 ROP 链之前,先通过 puts@plt 泄露任意 GOT 条目中的
libc 地址或栈上的返回地址,计算基址。
其余 ROP 链结构不变——所有 gadget 偏移加上泄露的基址即可。

3.5 技能的 token 管理:有限上下文中的高效分析

每个技能都内建了 token 预算管理机制,遵循四条铁律:

  1. 1. 聊天只放结论 — 不粘贴几千行反汇编,只展示关键发现和下一步
  2. 2. 输出落盘 — 大型输出(strings、objdump -d、strace 日志)写入 case 目录,用 rg 检索
  3. 3. 两击失败即转向 — 一个方法失败两次?记录原因,换工具,不固执
  4. 4. 脚本持久化 — 重复使用的解码逻辑写成 Python 脚本存到 case 目录

这意味着即使是分析一个复杂的、加壳的、stripped 的 ELF 样本,技能也不会消耗无谓的上下文。


四、实战演练:分析一个未知 ELF 文件

让我们用一个具体例子串联三个技能的协作流程。假设我们拿到一个陌生的 ELF 文件 suspicious.elf。

第一步:Triage(elf-analyzer)

"分析 suspicious.elf"

elf-analyzer 自动执行:
  file suspicious.elf → ELF 64-bit, x86-64, dynamically linked, stripped
  checksec → RELRO: Full, Canary: Yes, NX: Yes, PIE: Yes
  readelf -l → 2 个 LOAD segments, GNU_STACK=RW, GNU_RELRO present
  readelf -d → BIND_NOW present → Full RELRO confirmed
  strings → 发现 URL "hxxp://evil-c2.example.com/api/beacon"
          → 发现路径 "/tmp/.hidden/init.so"
          → 发现 "UPX!" 字符串
  ldd → libc.so.6, libpthread.so.0

关键发现:
  - UPX 加壳!→ 切换到脱壳流程
  - Full RELRO → GOT 不可写
  - NX+Canary+PIE 全开 → 利用难度较高

第二步:脱壳 + 深入理解(elf-analyzer → binary-reverse)

"先脱壳,然后分析它的 C2 通信逻辑"

upx -d suspicious.elf -o unpacked.elf  → 成功脱壳
re-analyze unpacked.elf → not stripped (符号表恢复)
切换到 binary-reverse:
  - 识别 C2 URL 的引用函数
  - 发现 XOR 解码循环 (key = 0x2F)
  - 追踪到 socket → connect → send 调用链
  - 确认 C2 通信协议: HTTP POST, User-Agent 硬编码

第三步:漏洞评估与利用(linux-pwn)

"这个 C2 通信函数里有 recv() 写入 256 字节栈缓冲区,能利用吗?"

切换到 linux-pwn:
  安全态势回顾: Full RELRO, Canary, NX, PIE 全开
  漏洞: recv(sock, stack_buf[128], 256, 0) → 128 字节溢出

  路由决策:
  - Canary → 需要先泄露 canary
  - NX → 需要 ROP/ret2libc
  - PIE → 需要泄露代码基址
  - Full RELRO → GOT 不可写,走 ret2libc(通过 PLT 直接调用 system,无需覆写 GOT)

  推荐路径:
  1. 先利用 recv 溢出 1 字节 → 泄露 canary
  2. 再通过 recv 泄露返回地址 → 计算 PIE 基址
  3. 最后构造 ROP 链: pop rdi; ret → "/bin/sh" → system@plt

五、设计权衡与边界

5.1 为什么拆成三个技能而不是一个?

最初的设计是一个单一的 elf-analyzer 技能,包含了从 triage 到 kernel exploit 的所有知识。但随着知识库膨胀到 19 个文件(6495 行),我们意识到每次分析都携带不相关的知识是对 token 的大量浪费。

拆分为三个技能后:

  • • elf-analyzer 是入口,覆盖 80% 的场景("这是什么文件?它安全吗?")
  • • binary-reverse 按需加载("我需要深入理解它的代码")
  • • linux-pwn 按需加载("我需要攻击它")

每个技能保持在 2300 行以内,初始 SKILL.md 在 100-150 行,大幅降低了首次加载的 token 消耗。

5.2 自动化 vs 手工掌控

这些技能的价值不在于"替代我们的知识",而在于"补充我们的盲区":

  • • 我们不需要记住 readelf -d 的输出怎么映射到 Full/Partial RELRO 判定——技能会做
  • • 我们不需要记忆 AES S-Box 的 256 字节——技能会匹配
  • • 我们不需要自己跟踪 "NX+Canary+PIE+Full RELRO → 不能用 GOT 覆写 → 需要 House of Apple 2" 的决策链——技能会路由

但我们仍然做最终的决策。技能是工具,不是替代。

5.3 持续进化

技能的 reference 文件设计为活文档——每次分析中发现的新模式(新的密码学常量、新的反分析技术、新版本的 glibc 变化)都可以追加到对应的 reference 中。这使技能具备从实践中自我进化的能力。


六、开始使用

环境准备

本文中的例子涉及两类操作:静态分析(在任何平台均可)和动态分析(需要 Linux 环境)。

macOS 本地验证(静态分析):

# 安装 GNU binutils(提供 greadelf/gobjdump/gnm/gstrings)
brew install binutils radare2 upx

# 设置别名(或加到 ~/.zshrc)

export
 PATH="/opt/homebrew/opt/binutils/bin:$PATH"
alias
 readelf=greadelf
alias
 objdump=gobjdump
alias
 nm=gnm

以上安装后,文章中 file、readelf -h/-l/-S/-d/-s、objdump -d、nm、strings、hexdump 等静态分析命令均可直接在 macOS 终端中验证。checksec 如无法通过 pwntools 安装(Python 3.14+ 兼容性问题),可使用等效命令替代(见 elf-triage.md 第 2 步的手动检查方法)。

Docker 环境(动态分析 + 运行样本):

# 启动隔离容器,挂载当前目录
docker run -it --rm --name elf-lab \
  -v "$(pwd):/work" \
  ubuntu:22.04 bash

# 一次性安装所需工具

apt update && apt install -y \
  binutils file strace ltrace gdb \
  python3 python3-pip radare2 upx-ucl \
  pax-utils elfutils netcat-openbsd

pip3 install pwntools --break-system-packages

文章中涉及 strace、ltrace、GDB 调试、upx -d 脱壳、运行二进制样本等操作,建议在容器中进行——天然隔离,用完即弃。

测试用 ELF 文件:如没有现成的 Linux ELF 文件,可用一行汇编快速创建一个:

echo '.globl _start; _start: mov \$1,%rax; mov \$1,%rdi; lea msg(%rip),%rsi; mov \$13,%rdx; syscall; mov \$60,%rax; xor %rdi,%rdi; syscall; .data; msg: .ascii "Hello, ELF!\\n"' > /tmp/minimal.s
clang --target=x86_64-linux-gnu -nostdlib -static -fuse-ld=lld -Wl,-e_start -o /tmp/test-elf /tmp/minimal.s
file /tmp/test-elf
# → ELF 64-bit LSB executable, x86-64, statically linked, not stripped

安装技能

# 克隆到本地后,创建符号链接到 Claude Code skills 目录
ln
 -s "$(pwd)/skills/elf-analyzer" ~/.claude/skills/elf-analyzer
ln
 -s "$(pwd)/skills/binary-reverse" ~/.claude/skills/binary-reverse
ln
 -s "$(pwd)/skills/linux-pwn" ~/.claude/skills/linux-pwn

快速上手

cd ~/.claude/skills
claude

然后在对话中:

  • • "分析这个 ELF: /usr/bin/ssh"
  • • "帮我看看这个二进制有没有反调试"
  • • "这个 CTF pwn 题怎么做?"

Claude 会自动激活对应的技能。


附录:技能文件清单

elf-analyzer(8 文件, 2,541 行)

SKILL.md                                 调度器
references/
├── elf-triage.md         (460行)        Triage 完整流程 + 辅助工具
├── elf-headers.md        (276行)        ELF 结构深度解析
├── elf-dynamic.md        (323行)        GOT/PLT/LD_PRELOAD/rpath
├── elf-security.md       (324行)        安全缓解机制全解
├── static-analysis.md    (323行)        objdump/radare2/Ghidra
├── dynamic-analysis.md   (380行)        GDB/strace/Frida
└── unpacking.md          (304行)        UPX + 通用脱壳策略

binary-reverse(6 文件, 2,038 行)

SKILL.md                                 调度器
references/
├── disasm-patterns.md    (495行)        x86-64/ARM64 模式库
├── crypto-patterns.md    (362行)        AES/RC4/SHA/TEA 检测
├── anti-analysis.md      (455行)        反调试/反VM/反混淆
├── language-specific-re.md (259行)      Go/Rust/C++/Swift 专项
└── advanced-tools.md     (367行)        angr/Qiling/Unicorn/BinDiff

linux-pwn(7 文件, 2,037 行)

SKILL.md                                 调度器
references/
├── exploit-primitives.md  (318行)       漏洞原语识别 + 评分
├── heap-exploitation.md   (337行)       House of系列/tcache/FSOP
├── rop-advanced.md        (356行)       ret2csu/SROP/栈枢轴
├── format-string-deep.md  (280行)       格式字符串深入利用
├── kernel-exploitation.md (352行)       内核提权 + 保护绕过
└── kernel-modules.md      (302行)       .ko/eBPF/io_uring 分析

本文参考了 Linux 二进制文件格式 ELF 101 一文中对 ELF 格式的基础讲解,并基于对 GitHub 上 6 个核心技能仓库(malware-analysis-static、CyberSecurity-Skill、ctf-skills、Claude-Red、antigravity-awesome-skills、awesome-llm-reverse-engineering)的深入分析构建。