0x01编辑代码
- 创建一个新文件
syscall_counter.py
,然后输入以下Python脚本。这个脚本使用BCC创建了一个eBPF程序,该程序会挂接(hook)到sys_clone
系统调用,每次调用都会增加计数器。
from bcc import BPF
# 定义eBPF程序
prog = """
#include <linux/sched.h>
BPF_HASH(syscall_count, u32, u64);
int count_sys_clone(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid() >> 32; // 获取进程ID
u64 zero = 0, *val;
// 增加syscall_count哈希表中对应PID的计数
val = syscall_count.lookup_or_try_init(&pid, &zero);
if (val) {
(*val)++;
}
return 0;
}
"""
# 加载eBPF程序
b = BPF(text=prog)
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="count_sys_clone")
# 输出标题
print("%-6s %-12s" % ("PID", "CLONE-COUNT"))
try:
# 循环检索并输出系统调用的计数
while True:
syscall_count = b.get_table("syscall_count")
for k, v in syscall_count.items():
print("%-6d %-12d" % (k.value, v.value))
b.trace_print()
syscall_count.clear()
except KeyboardInterrupt:
pass
- 保存文件后,使用具有必要权限的用户(通常是root)来运行此脚本
sudo python syscall_counter.py
0x实时跟踪系统调用
- 实时监控系统调用。
- 分析系统调用的使用模式,以识别性能热点或不寻常的系统行为。
syscall_trace.py
from bcc import BPF
# 定义eBPF程序
program = """
#include <uapi/linux/ptrace.h>
// 定义输出数据的结构体
struct data_t {
u64 ts;
u32 pid;
char comm[TASK_COMM_LEN];
char syscall[__SYSCALL_NAME_LEN];
int ret;
};
BPF_PERF_OUTPUT(syscalls);
// 记录系统调用的入口
int trace_syscall_entry(struct pt_regs *ctx) {
struct data_t data = {};
data.ts = bpf_ktime_get_ns();
data.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&data.comm, sizeof(data.comm));
// 获取系统调用名称
int syscall_nr = PT_REGS_PARM1(ctx);
bpf_probe_read_kernel_str(&data.syscall, sizeof(data.syscall), (void *)syscall_nr);
syscalls.perf_submit(ctx, &data, sizeof(data));
return 0;
}
// 记录系统调用的退出
int trace_syscall_exit(struct pt_regs *ctx) {
struct data_t data = {};
data.ts = bpf_ktime_get_ns();
data.pid = bpf_get_current_pid_tgid() >> 32;
data.ret = PT_REGS_RC(ctx);
bpf_get_current_comm(&data.comm, sizeof(data.comm));
// 获取系统调用名称
int syscall_nr = PT_REGS_PARM1(ctx);
bpf_probe_read_kernel_str(&data.syscall, sizeof(data.syscall), (void *)syscall_nr);
syscalls.perf_submit(ctx, &data, sizeof(data));
return 0;
}
"""
b = BPF(text=program)
b.attach_tracepoint(tp="raw_syscalls:sys_enter", fn_name="trace_syscall_entry")
b.attach_tracepoint(tp="raw_syscalls:sys_exit", fn_name="trace_syscall_exit")
print("Tracing syscalls... Hit Ctrl-C to end.")
# 处理事件的回调函数
def print_event(cpu, data, size):
event = b["syscalls"].event(data)
print(f"[{event.ts}] PID: {event.pid}, Comm: {event.comm}, Syscall: {event.syscall}, Return: {event.ret}")
b["syscalls"].open_perf_buffer(print_event)
while True:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
break