You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用eBPF(BCC)获取系统调用表地址?Kprobe及符号表疑问

如何用eBPF的Kprobe获取系统调用地址及查找内核符号表

一、查找内核符号表中系统调用表的方法

内核符号表包含内核导出的所有函数、变量地址,系统调用表的符号名随架构不同有所差异:

  • x86_64 架构:符号名为 sys_call_table
  • ARM64 架构:通常为 sys_call_table 或 el0_sys_call_table
  • 其他架构可通过内核文档或源码确认

1. 用户空间直接查看

可以通过 /proc/kallsyms 文件直接查询:

# 查看系统调用表地址
cat /proc/kallsyms | grep sys_call_table

如果输出为空,说明内核限制了符号访问,临时解除限制:

sysctl -w kernel.kptr_restrict=0

注意:该设置会在重启后失效,生产环境需谨慎操作。

2. eBPF程序内动态查找

在eBPF程序中无法直接读取 /proc 文件,需使用内核提供的 bpf_kallsyms_lookup_name 函数查找符号地址。但该函数属于GPL-only接口,因此你的eBPF程序必须声明为GPL兼容:

char __license[] SEC("license") = "GPL";

二、eBPF程序实现获取系统调用地址

以下是示例程序,通过Kprobe触发时查找系统调用表,并获取指定系统调用(如sys_open)的地址:

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

// 声明GPL许可证,才能使用bpf_kallsyms_lookup_name
char __license[] SEC("license") = "GPL";

// 通过Kprobe hook任意内核函数(这里以sys_open为例)触发逻辑
SEC("kprobe/sys_open")
int BPF_KPROBE(sys_open) {
    void *sys_call_table;
    void *sys_open_addr;

    // 查找系统调用表地址
    sys_call_table = (void *)bpf_kallsyms_lookup_name("sys_call_table");
    if (!sys_call_table) {
        bpf_printk("Failed to find sys_call_table");
        return 0;
    }

    // 根据系统调用号获取对应地址,__NR_open为x86_64下open的系统调用号
    sys_open_addr = ((void **)sys_call_table)[__NR_open];
    bpf_printk("sys_open address: %p", sys_open_addr);

    return 0;
}

三、关键注意事项

  • 系统调用号兼容性:不同内核版本、架构的系统调用号可能不同,建议在用户空间通过 sys/syscall.h 中的 __NR_* 宏获取,或动态传递给eBPF程序。
  • 内核符号隐藏:部分发行版内核可能未导出 sys_call_table,此时可尝试通过hook内核中调用系统调用的入口函数(如 do_syscall_64)间接获取系统调用表地址。
  • Kprobe限制:部分内核函数被加入Kprobe黑名单,无法直接hook,需提前确认目标函数是否允许Kprobe附着。
  • 权限问题:加载eBPF程序需要CAP_BPF、CAP_PERFMON等权限,运行时需以root用户执行。

内容的提问来源于stack exchange,提问作者bbpfuser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:20:27