编程 eCapture v2 深度解析:当 AI Agent 写了 90% 的代码,开源开发进入「产品经理模式」

2026-04-10 04:16:16 +0800 CST views 1

eCapture v2 深度解析:当 AI Agent 写了 90% 的代码,开源开发进入「产品经理模式」

背景:一个 1.5 万 Star 的 eBPF 项目,被 AI 重写了

2026年4月,一个爆炸性的消息在开源圈传开:eCapture v2 发布,而这次版本更新中,90% 的代码是由 GitHub Copilot AI Agent 完成的

这不是噱头,不是营销,而是一次真实的生产级实验——作者 CFC4N(网名)在博客中公开了完整的贡献数据:

贡献者新增行数删除行数新增占比
@Copilot(AI Agent)28,42610,392~90%
@cfc4n(作者本人)2,097781~7%
社区贡献者1,08296~3%

更关键的是,这不是简单的「AI 帮忙写了几行代码」,而是一次完整的架构重构——8 个 Probe 全部标准化重写,user/ 目录彻底删除,E2E 测试覆盖 72+ 场景。作者的角色从「写代码的人」变成了「写需求的人和审 PR 的人」。

这标志着开源开发进入了一个新范式:产品经理模式

eCapture 是什么:用 eBPF 撕开 TLS 加密的黑盒

在深入 v2 的变革之前,先理解 eCapture 解决的核心问题。

传统 TLS 抓包的痛点

网络调试、安全分析、流量审计——这些场景下,抓包是基本功。但 TLS/SSL 加密的普及,让「抓包」变成了「抓乱码」:

传统方案:
1. 中间人代理(MITM):需要生成 CA 证书,客户端安装信任,配置复杂
2. 服务端 keylog:需要修改应用代码,导出会话密钥,生产环境不现实
3. 服务端配置:修改 SSL 库配置,重启服务,影响可用性

每一种方案都有明显的短板。而 eCapture 的思路完全不同——不碰证书,不改配置,不重启服务

eBPF 的「降维打击」

eBPF(Extended Berkeley Packet Filter)是 Linux 内核的可编程扩展。它允许你在内核态插入安全、高效的沙箱代码,无需修改内核源码或加载模块。

eCapture 的核心原理:

┌─────────────────────────────────────────────────────────┐
│                    用户态(User Space)                   │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐           │
│  │ OpenSSL  │    │  GnuTLS  │    │  GoTLS   │  ...      │
│  └────┬─────┘    └────┬─────┘    └────┬─────┘           │
│       │ SSL_write/SSL_read                              │
│       ▼                                                  │
├─────────────────────────────────────────────────────────┤
│                    内核态(Kernel Space)                 │
│  ┌─────────────────────────────────────────────┐        │
│  │  eBPF Probe(uprobe/tracepoint)             │        │
│  │  - Hook SSL_write/SSL_read                   │        │
│  │  - 捕获明文参数(plaintext buffer)           │        │
│  │  - 通过 perf buffer 发送到用户态              │        │
│  └─────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────┘

关键点:

  1. uprobe 机制:在用户态函数入口插入探针,捕获函数参数
  2. 明文捕获:SSL_write/SSL_read 的参数本身就是明文,在加密前/解密后截获
  3. 零侵入:不需要 CA 证书,不需要修改应用,不需要重启服务

支持的协议:

Probe协议/库用途
OpenSSLopenssl最广泛,覆盖 Nginx、Apache、curl 等
GnuTLSgnutls部分服务端应用
GoTLSGo crypto/tlsGo 语言应用
NSPRNSS/NSPRFirefox、部分 Java 应用
MySQLMySQL 协议数据库明文查询
PostgresPostgreSQL 协议数据库明文查询
Bash/ZshShell 命令命令行审计

一行命令,抓取 HTTPS 明文

# 抓取所有 OpenSSL 流量的明文
sudo ecapture tls

# 指定 PID,只抓特定进程
sudo ecapture tls -p 12345

# 输出为 pcap 格式,可用 Wireshark 打开
sudo ecapture tls -w capture.pcap

# 只抓特定域名(通过 SNI 过滤)
sudo ecapture tls --host="api.example.com"

这就是 eCapture 的价值:把网络调试从「配置地狱」变成「一行命令」

v2 的变革:从「能用」到「可以持续演进」

v1 时代的 eCapture 已经有 1.5 万 Star,功能完备,但内部架构却越来越难以维护。作者在博客中坦言:

老实说,v1 时代的 user/ 目录,笔者自己看着都头疼。

v2 的核心变化,可以用一句话概括:把整个项目从「能用」变成了「可以持续演进」

架构重构:user/ 目录彻底消失

v1 时代,所有 Probe 的代码都堆在 user/ 目录下:

user/
├── bash.go
├── mysql.go
├── openssl.go
├── gnutls.go
├── gotls.go
├── nspr.go
├── postgres.go
└── zsh.go

随着支持的协议越来越多,这个目录越来越乱——命名不统一、接口不一致、职责边界模糊。

v2.0.0 用 7 个 Phase 完成了完整的迁移:

internal/probe/
├── base/
│   ├── config.go      # 通用配置
│   ├── probe.go       # BaseProbe 实现
│   └── event.go       # 事件基类
├── openssl/
│   ├── config.go      # 嵌入 BaseConfig
│   ├── event.go       # 实现 DecodeFromBytes()
│   ├── register.go    # init() 自注册
│   └── openssl_probe.go  # 嵌入 BaseProbe
├── gotls/
│   └── ...
└── ...

每个 Probe 现在都有统一的文件结构,职责清晰,接口一致。

三大设计模式:工厂、模板方法、观察者

v2 引入了三个设计模式,彻底解耦了各个组件:

1. 工厂模式(Factory Pattern)

// register.go - 每个 Probe 自注册
func init() {
    factory.RegisterProbe("openssl", NewOpenSSLProbe)
}

// factory.go - 统一创建入口
func NewProbe(name string, cfg config.Config) (Probe, error) {
    creator, ok := probes[name]
    if !ok {
        return nil, fmt.Errorf("unknown probe: %s", name)
    }
    return creator(cfg)
}

好处:

  • 新增 Probe 只需实现接口,在 init() 中自注册
  • CLI 命令通过工厂创建,互不依赖
  • 符合开闭原则:扩展开放,修改关闭

2. 模板方法模式(Template Method Pattern)

// base/probe.go - 公共流程
type BaseProbe struct {
    name   string
    config config.Config
}

func (p *BaseProbe) Run() error {
    // 1. 初始化(公共逻辑)
    if err := p.Initialize(); err != nil {
        return err
    }
    
    // 2. 启动(子类实现)
    if err := p.Start(); err != nil {
        return err
    }
    
    // 3. 事件循环(公共逻辑)
    p.eventLoop()
    
    // 4. 停止(子类实现)
    return p.Stop()
}

// openssl/openssl_probe.go - 差异化逻辑
func (p *OpenSSLProbe) Start() error {
    // OpenSSL 特有的启动逻辑
    return p.attachOpenSSL()
}

好处:

  • 公共流程在 BaseProbe 中实现一次
  • 子 Probe 只需覆写差异化逻辑
  • 减少重复代码,降低维护成本

3. 观察者模式(Observer Pattern)

// 事件分发器
type EventDispatcher struct {
    subscribers map[string][]Subscriber
}

func (d *EventDispatcher) Dispatch(event Event) {
    for _, sub := range d.subscribers[event.Type()] {
        sub.OnEvent(event)
    }
}

// 订阅者:文件写入、pcap 写入、WebSocket 推送
type FileWriter struct {}
func (w *FileWriter) OnEvent(event Event) {
    w.file.Write(event.Data())
}

type PcapWriter struct {}
func (w *PcapWriter) OnEvent(event Event) {
    w.writePcapRecord(event)
}

type WebSocketWriter struct {}
func (w *WebSocketWriter) OnEvent(event Event) {
    w.conn.WriteMessage(event.JSON())
}

好处:

  • 事件源和消费者完全解耦
  • 新增输出格式只需实现 Subscriber 接口
  • 支持多路输出(同时写文件 + 推送远端)

事件流转全链路

从 eBPF 内核态抓到数据,到最终写入文件或推送到远端,完整路径如下:

┌─────────────────────────────────────────────────────────────┐
│ 内核态                                                       │
│  ┌──────────────┐                                           │
│  │ eBPF Program │  uprobe/tracepoint                        │
│  │ (C code)     │  ──────────────────┐                     │
│  └──────────────┘                   │                     │
│         │ perf buffer               │                     │
└─────────│───────────────────────────│─────────────────────┘
          ▼                           │
┌─────────────────────────────────────│─────────────────────┐
│ 用户态                               │                     │
│  ┌──────────────┐                   │                     │
│  │ EventDecoder │  ◄────────────────┘                     │
│  └──────┬───────┘                                          │
│         │ Event                                            │
│         ▼                                                  │
│  ┌──────────────────┐                                      │
│  │ EventDispatcher  │                                      │
│  └────────┬─────────┘                                      │
│           │ Dispatch                                       │
│           ▼                                                │
│  ┌─────────┐ ┌─────────┐ ┌─────────────┐                  │
│  │FileWriter│ │PcapWriter│ │WebSocketWriter│               │
│  └─────────┘ └─────────┘ └─────────────┘                  │
└─────────────────────────────────────────────────────────────┘

这个链路在 v2 里被完整地标准化了。之前 v1 里部分 Probe 是直接写文件,绕过了 Dispatcher,导致远端推送(ecaptureQ 模式)下数据丢失——这个 Bug 在 v2.1.0 的 #964 里修掉了。

面向用户的改进:GoTLS 四元组、pcap 可靠写入、Android 成熟

架构重构是「内功」,用户能感知到的是「外功」。

1. GoTLS 终于有四元组了

很多同学用 eCapture 抓 Go 应用的 TLS 流量,一直有个痛点:抓到的明文没有连接信息,不知道这条流量来自哪个 IP、哪个端口。

# v1 输出:只有明文,没有连接信息
GET /api/users HTTP/1.1
Host: api.example.com
...

# v2 输出:带连接四元组
[192.168.1.100:54321 -> 10.0.0.1:443]
GET /api/users HTTP/1.1
Host: api.example.com
...

v2.0.1 和 v2.1.0 里,贡献者 @zenyanle 接连贡献了两个 PR(#947, #960),给 GoTLS Probe 加上了从 tls.Conn 里提取 fd、进而获取连接四元组的能力。

对于要做流量审计或安全分析的同学,这个功能很关键。

2. pcap 写入更可靠了

v2.0.0 引入了缓冲 pcapng 写入,带上了接口元数据;v2.2.0 修掉了一个 Close() 里的竞态条件——之前在高并发场景下,DSB keylog 写入会出现数据乱序或丢失的情况。

// v2 的 pcap 写入流程
type PcapWriter struct {
    buf     *bufio.Writer
    mu      sync.Mutex
    closed  bool
}

func (w *PcapWriter) Write(record PcapRecord) error {
    w.mu.Lock()
    defer w.mu.Unlock()
    
    if w.closed {
        return ErrClosed
    }
    
    // 缓冲写入,批量 flush
    return w.buf.Write(record.Bytes())
}

func (w *PcapWriter) Close() error {
    w.mu.Lock()
    defer w.mu.Unlock()
    
    if w.closed {
        return nil
    }
    
    // 先 flush 缓冲区,再关闭
    if err := w.buf.Flush(); err != nil {
        return err
    }
    
    w.closed = true
    return w.file.Close()
}

现在写 pcap 文件,序列化保证了,关闭时也不会丢尾巴了。

3. Android 支持更成熟

v2 系列对 Android 的支持大幅提升:

  • BoringSSL Android 16 的 offset 更新(#885)
  • Android 模拟器的 DNS 解析问题修复(#957)
  • Android e2e PCAP 模式自动探测活跃网络接口(#976)
  • Build tag 从 androidgki 统一改名为 ecap_android(#930)

对于在 Android 上用 eCapture 做流量分析的同学,v2 系列的稳定性比 v1 强了不止一个量级。

4. 全覆盖的 E2E 测试体系

v2.0.0 里加入了 72+ 个 E2E 测试场景,覆盖了 bash、tls、gnutls、gotls 全部模块,以及 pcap/keylog/text 三种抓包模式。

# E2E 测试示例
func TestOpenSSL_KeyLog(t *testing.T) {
    // 1. 启动测试 HTTPS 服务
    server := startTLSServer(t)
    defer server.Close()
    
    // 2. 启动 eCapture
    ec := startECapture(t, "tls", "-w", "capture.keylog")
    defer ec.Stop()
    
    // 3. 发送测试请求
    resp, err := http.Get(server.URL)
    require.NoError(t, err)
    resp.Body.Close()
    
    // 4. 验证 keylog 文件
    keylog := parseKeylog(t, "capture.keylog")
    require.NotEmpty(t, keylog)
    require.Equal(t, server.TLSVersion(), keylog.Version)
}

这意味着每次发版前,核心路径都会被自动验证一遍。用户升级时踩到「老功能突然坏了」这种坑的概率,大幅降低。

AI Agent 的真实参与:从「辅助」到「主导」

现在回到最核心的问题:AI Agent 到底做了什么?

数据说话:90% 的代码,35% 的 PR

从 v2.0.0 到 v2.2.1,GitHub 上合并了约 37 个 PR,分布如下:

贡献者PR 数量占比
@Copilot(GitHub Copilot AI Agent)13~35%
@cfc4n(作者本人)21~57%
社区贡献者(@zenyanle、@Carl Chen 等)3~8%

v2.0.0 那次大重构是 AI 参与度最高的版本:8 个 Probe 的标准化迁移、E2E 测试框架搭建,10 个 PR 直接由 @Copilot 提交,占当版 PR 总量的近 45%。

再看代码行数:

贡献者新增行数删除行数新增占比
@Copilot(AI Agent)28,42610,392~90%
@cfc4n(作者本人)2,097781~7%
社区贡献者1,08296~3%

90% 的代码是 AI 写的,作者的角色更像产品经理加 Code Reviewer。

AI 是怎么知道该做什么的?

答案是:每一个 AI PR 背后,都对应着作者写的一个详细 Issue

# Issue 示例:重构 OpenSSL Probe

## 目标
将 user/openssl.go 迁移到 internal/probe/openssl/,符合 v2 架构规范。

## 要求
1. 创建 internal/probe/openssl/ 目录
2. 实现 config.go,嵌入 BaseConfig
3. 实现 event.go,实现 DecodeFromBytes() 接口
4. 实现 register.go,在 init() 中调用 factory.RegisterProbe()
5. 实现 openssl_probe.go,嵌入 BaseProbe,覆写 Initialize/Start/Stop/Close
6. 保持原有功能不变,通过 E2E 测试

## 参考
- 已完成的 Bash Probe:internal/probe/bash/
- 架构设计文档:docs/architecture.md

任务描述写得越清楚,AI 出活越靠谱;描述含糊的,烂 PR 照样打回去重写。

那段时间的工作流,基本是「作者当产品经理 + Code Reviewer,AI 当执行工程师」。

AI Agent 擅长什么?不擅长什么?

擅长:模式清晰、重复度高的任务

比如「按照这个标准模板,把剩余 6 个 Probe 全部重构一遍」。

// AI 擅长的模式化任务
// 给定 Bash Probe 的模板,生成 OpenSSL Probe

// bash/bash_probe.go(模板)
type BashProbe struct {
    base.BaseProbe
    config *BashConfig
}

func (p *BashProbe) Initialize() error {
    return p.loadBPFProgram()
}

func (p *BashProbe) Start() error {
    return p.attachUprobe()
}

// AI 生成的 openssl/openssl_probe.go
type OpenSSLProbe struct {
    base.BaseProbe
    config *OpenSSLConfig
}

func (p *OpenSSLProbe) Initialize() error {
    return p.loadBPFProgram()
}

func (p *OpenSSLProbe) Start() error {
    return p.attachUprobe()
}

这种活交给 AI 效率极高。

不擅长:涉及 eBPF 内核行为的细节、并发竞态的根因分析

// AI 不擅长的问题
// 为什么在高并发场景下,DSB keylog 写入会出现数据乱序?

// 这需要理解:
// 1. eBPF perf buffer 的读取语义
// 2. Go 的 goroutine 调度
// 3. pcapng 格式的序列化要求
// 4. 文件系统的写入缓冲

// 这类问题还是得靠人来兜底

v2 实践的启示:AI Agent 不是替代,是解放

v2 这次实践下来,作者的感受是:

AI Agent 不是替代开发者,而是把开发者从重复劳动里解放出来,让人能把精力放在真正需要判断力的地方。

这标志着开源开发进入了一个新范式:

传统模式产品经理模式
开发者写代码开发者写需求(Issue)
开发者做 Code ReviewAI 写代码,开发者做 Code Review
重复劳动消耗精力精力集中在架构决策、Bug 分析
一个人干多个人的活一个人 + AI = 一个团队

破坏性变更备忘:从 v1 升级到 v2

如果你有基于 eCapture 源码开发的二次开发代码,升级 v2 需要注意以下几点:

变更项v1v2
Probe 代码位置user/internal/probe/
Build tag(Android)androidgkiecap_android
eBPF bytecode 目录项目根ebpfassets/
Probe 注册方式手动初始化init() 自注册 + Factory

实战:用 eCapture 抓包的真实场景

场景 1:调试微服务 HTTPS 调用

# 找到目标进程
ps aux | grep my-service

# 抓取该进程的 TLS 明文
sudo ecapture tls -p $(pgrep -f my-service) -w debug.pcap

# 用 Wireshark 打开
wireshark debug.pcap

场景 2:审计数据库查询

# 抓取 MySQL 明文查询
sudo ecapture mysql -w mysql.pcap

# 抓取 PostgreSQL 明文查询
sudo ecapture postgres -w postgres.pcap

场景 3:安全分析——检测敏感数据泄露

# 抓取所有 TLS 流量,输出为 text
sudo ecapture tls -o sensitive.log

# 搜索敏感关键词
grep -E 'password|token|secret|credit_card' sensitive.log

场景 4:Android 应用流量分析

# 在 Android 设备上运行
adb shell su -c "ecapture tls -w /sdcard/capture.pcap"

# 拉取到本地
adb pull /sdcard/capture.pcap

# 用 Wireshark 分析
wireshark capture.pcap

技术深度:eBPF uprobe 的实现原理

uprobe 的工作机制

uprobe 是 Linux 内核提供的用户态探针机制,允许在用户态函数入口/出口插入断点。

┌─────────────────────────────────────────────────────────┐
│ 用户态进程                                               │
│  ┌────────────────────────────────────────────┐        │
│  │ SSL_write@plt                               │        │
│  │  jmp *SSL_write@got                         │        │
│  └────────────────────────────────────────────┘        │
│         │                                                │
│         ▼                                                │
│  ┌────────────────────────────────────────────┐        │
│  │ SSL_write(libssl.so)                      │        │
│  │  0x7f12345678: push rbp                     │ ◄── uprobe 断点
│  │  0x7f12345679: mov rbp, rsp                 │        │
│  │  ...                                        │        │
│  └────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────┘
         │
         ▼ 内核态信号
┌─────────────────────────────────────────────────────────┐
│ eBPF 程序                                                │
│  SEC("uprobe/SSL_write")                                │
│  int probe_ssl_write(struct pt_regs *ctx) {             │
│      // 从寄存器中提取参数                               │
│      const void *buf = (const void *)PT_REGS_PARM2(ctx);│
│      size_t count = PT_REGS_PARM3(ctx);                 │
│                                                          │
│      // 读取明文数据                                     │
│      bpf_probe_read(&data, count, buf);                 │
│                                                          │
│      // 发送到用户态                                     │
│      bpf_perf_event_output(ctx, &events, ..., &data);   │
│      return 0;                                           │
│  }                                                       │
└─────────────────────────────────────────────────────────┘

关键技术点

  1. 符号解析:通过 /proc/pid/maps 和 ELF 解析,找到目标函数地址
  2. 断点注入:通过 perf_event_open + ioctl(PERF_EVENT_IOC_SET_BPF) 注入 eBPF 程序
  3. 参数提取:通过 pt_regs 结构从寄存器中提取函数参数
  4. 数据传输:通过 perf buffer 或 ring buffer 将数据发送到用户态

与竞品对比:eCapture vs tcpdump vs mitmproxy

特性eCapturetcpdumpmitmproxy
TLS 明文捕获✅ 无需配置❌ 只能抓密文✅ 需要配置 CA
侵入性零侵入零侵入需要安装 CA
性能影响低(eBPF)中(代理转发)
平台支持Linux/Android全平台全平台
数据库支持✅ MySQL/PG
实时推送✅ WebSocket

总结:开源开发的「产品经理模式」来了

eCapture v2 的发布,不仅是一个技术工具的升级,更是一次开源开发范式的实验。

技术层面

  • 架构重构:工厂模式 + 模板方法 + 观察者,彻底解耦
  • 功能增强:GoTLS 四元组、pcap 可靠写入、Android 成熟
  • 质量保障:72+ E2E 测试,核心路径全覆盖

范式层面

  • AI Agent 写了 90% 的代码,35% 的 PR
  • 作者角色从「写代码」变成「写需求 + 审 PR」
  • 开源开发进入「产品经理模式」

启示

  • AI Agent 擅长模式清晰、重复度高的任务
  • 人负责架构决策、Bug 分析、需求定义
  • AI 不是替代,是解放——把人从重复劳动中解放出来

eCapture 的作者在博客最后写道:

v2 是一次迟到很久的重构。老实说,v1 时代的 user/ 目录,笔者自己看着都头疼。这次借着 AI Coding Agent 的帮助,总算把欠的技术债还掉了大半。

这或许就是 AI Agent 时代开源开发的新常态:技术债不再是负担,因为 AI 可以帮你还


项目地址:https://github.com/gojue/ecapture(15,097 ⭐)

官网:https://ecapture.cc

作者博客:https://www.cnxct.com/ecapture-v2/

复制全文 生成海报 eBPF AI Agent 开源 网络抓包 GitHub Copilot

推荐文章

企业官网案例-芊诺网络科技官网
2024-11-18 11:30:20 +0800 CST
CSS 媒体查询
2024-11-18 13:42:46 +0800 CST
MySQL死锁 - 更新插入导致死锁
2024-11-19 05:53:50 +0800 CST
JavaScript设计模式:发布订阅模式
2024-11-18 01:52:39 +0800 CST
Go的父子类的简单使用
2024-11-18 14:56:32 +0800 CST
JS 箭头函数
2024-11-17 19:09:58 +0800 CST
Vue3 vue-office 插件实现 Word 预览
2024-11-19 02:19:34 +0800 CST
12个非常有用的JavaScript技巧
2024-11-19 05:36:14 +0800 CST
Golang 中你应该知道的 Range 知识
2024-11-19 04:01:21 +0800 CST
Rust 中的所有权机制
2024-11-18 20:54:50 +0800 CST
Nginx 防止IP伪造,绕过IP限制
2025-01-15 09:44:42 +0800 CST
前端如何一次性渲染十万条数据?
2024-11-19 05:08:27 +0800 CST
用 Rust 玩转 Google Sheets API
2024-11-19 02:36:20 +0800 CST
imap_open绕过exec禁用的脚本
2024-11-17 05:01:58 +0800 CST
Vue3结合Driver.js实现新手指引功能
2024-11-19 08:46:50 +0800 CST
Python 微软邮箱 OAuth2 认证 Demo
2024-11-20 15:42:09 +0800 CST
CSS 中的 `scrollbar-width` 属性
2024-11-19 01:32:55 +0800 CST
使用xshell上传和下载文件
2024-11-18 12:55:11 +0800 CST
支付页面html收银台
2025-03-06 14:59:20 +0800 CST
前端代码规范 - 图片相关
2024-11-19 08:34:48 +0800 CST
如何配置获取微信支付参数
2024-11-19 08:10:41 +0800 CST
如何在Vue3中定义一个组件?
2024-11-17 04:15:09 +0800 CST
程序员茄子在线接单