关于用eBPF分析802.11x WiFi头添加及追踪mac80211x内核函数的咨询
用eBPF查找802.11x WiFi头添加实现及追踪puts_wifi_header函数的方法
一、查找系统添加802.11x WiFi头的实现
要定位内核中添加802.11x WiFi帧头的逻辑,可通过以下步骤用eBPF追踪:
锁定核心追踪范围:802.11帧头的添加逻辑主要集中在
mac80211子系统的发送路径中,重点关注这类函数:- 帧构建类:
ieee80211_build_tx_frame、ieee80211_prepare_tx - 缓冲区操作类:
skb_push、skb_put(内核通用的缓冲区头/尾添加函数,mac80211会调用它们添加帧头) - 提交发送类:
ieee80211_submit_frame
- 帧构建类:
用BCC工具快速追踪验证:
比如用trace.py追踪skb_push并过滤mac80211相关调用栈,命令如下:trace.py -k skb_push -T执行后触发WiFi发送操作(比如ping同一WiFi下的设备),观察输出的调用栈,找到mac80211子系统中调用
skb_push添加帧头的上层函数,顺着调用栈就能定位到具体的头添加实现。也可以直接追踪mac80211的特定函数,比如:
trace.py -k ieee80211_build_tx_frame -A查看函数的参数和返回值,分析帧头构建的过程。
二、追踪mac80211子集中的puts_wifi_header函数
既然已经完成内核配置和环境搭建,完全可以通过eBPF的kprobe机制追踪该函数的执行过程,具体步骤如下:
1. 确认函数可追踪
先通过内核符号表确认函数存在:
grep puts_wifi_header /proc/kallsyms
如果能输出函数地址,说明该函数是导出的(或内核未开启符号混淆),可以被kprobe追踪。
2. 用BCC编写追踪脚本(快速验证)
创建一个Python脚本trace_puts_wifi_header.py,内容如下:
from bcc import BPF BPF_PROGRAM = """ #include <linux/skbuff.h> // 定义kprobe追踪puts_wifi_header int trace_puts_wifi_header(struct pt_regs *ctx, struct sk_buff *skb) { // 打印函数被调用的PID、进程名,以及skb的地址 bpf_trace_printk("puts_wifi_header called! PID: %d, Comm: %s, SKB addr: %p\\n", bpf_get_current_pid_tgid() >> 32, bpf_get_current_comm(), skb); return 0; } """ b = BPF(text=BPF_PROGRAM) # 挂载kprobe到目标函数 b.attach_kprobe(event="puts_wifi_header", fn_name="trace_puts_wifi_header") # 打印输出 print("Tracing puts_wifi_header... Hit Ctrl+C to stop.") b.trace_print()
执行脚本:
sudo python3 trace_puts_wifi_header.py
触发WiFi发送操作,就能看到函数被调用的日志。如果需要更详细的信息(比如帧头内容、参数细节),可以在BPF程序中通过skb指针读取相关数据(注意内核版本的结构体兼容性)。
3. 用libbpf-bootstrap编写C语言BPF程序(生产级)
如果需要更高效、稳定的追踪,可使用libbpf-bootstrap框架:
- 创建
puts_wifi_header_trace.bpf.c:
#include "vmlinux.h" #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> char LICENSE[] SEC("license") = "GPL"; SEC("kprobe/puts_wifi_header") int BPF_KPROBE(puts_wifi_header, struct sk_buff *skb) { u32 pid = bpf_get_current_pid_tgid() >> 32; char comm[16]; bpf_get_current_comm(comm, sizeof(comm)); bpf_printk("puts_wifi_header invoked by PID %d (%s), SKB: %p", pid, comm, skb); return 0; }
- 编写用户态加载程序(参考libbpf-bootstrap的模板),编译后执行,即可追踪函数执行。
注意事项
- 如果函数未导出,需要使用偏移量方式追踪,但需要先获取函数在内存中的偏移地址,这种方式兼容性较差,建议优先使用导出的函数。
- 不同内核版本的
struct sk_buff结构体可能有差异,读取内部字段时要对应目标内核的定义。
内容的提问来源于stack exchange,提问作者Shriyam Khatiwada
相关产品推荐
相关产品推荐

