diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 4e03bb2..10077a6 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -21,9 +21,9 @@ ], "compilerPath": "/usr/bin/g++-11", "cStandard": "c23", - "cppStandard": "c++11", + "cppStandard": "c++23", "intelliSenseMode": "linux-gcc-x64" } ], "version": 4 -} \ No newline at end of file +} diff --git a/ebpf/build.sh b/ebpf/build.sh new file mode 100755 index 0000000..94fb097 --- /dev/null +++ b/ebpf/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +g++ main.cpp -o main -lbcc -pthread -lstdc++fs diff --git a/ebpf/core.ebpf.c b/ebpf/core.ebpf.c new file mode 100644 index 0000000..f8cccf7 --- /dev/null +++ b/ebpf/core.ebpf.c @@ -0,0 +1,35 @@ +#include +#include + +struct event_data_t { + int type; + u32 pid; + u32 ppid; +} __attribute__((packed)); + +BPF_PERF_OUTPUT(events); + +int trace_process_start(struct pt_regs *ctx, struct filename *filename) { + struct event_data_t event_data; + + u32 pid = bpf_get_current_pid_tgid(); + u32 ppid = bpf_get_current_pid_tgid() >> 32; + event_data.type = 0; + event_data.pid = pid; + event_data.ppid = ppid; + events.perf_submit(ctx, &event_data, sizeof(event_data)); + return 0; +} + +int trace_process_exit(struct pt_regs *ctx) { + struct event_data_t event_data; + + u32 pid = bpf_get_current_pid_tgid(); + u32 ppid = bpf_get_current_pid_tgid() >> 32; + event_data.type = 1; + event_data.pid = pid; + event_data.ppid = ppid; + events.perf_submit(ctx, &event_data, sizeof(event_data)); + + return 0; +} diff --git a/ebpf/main b/ebpf/main new file mode 100755 index 0000000..b149fb4 Binary files /dev/null and b/ebpf/main differ diff --git a/ebpf/main.cpp b/ebpf/main.cpp new file mode 100644 index 0000000..4ca6ef1 --- /dev/null +++ b/ebpf/main.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +const std::string EBPF_SOURCE_PATH = "core.ebpf.c"; + +volatile bool interrupted = false; + +void signal_handler(int signal) { interrupted = true; } + +std::pair get_process_path(int pid) { + try { + char path[4096] = {0}; + std::string symlink_path = "/proc/" + std::to_string(pid) + "/exe"; + ssize_t len = readlink(symlink_path.c_str(), path, sizeof(path)); + if (len != -1) { + return {true, std::string(path)}; + } + } catch (...) { + } + return {false, "unknown"}; +} + +std::string get_process_name(pid_t pid) { + std::string process_name; + std::ifstream comm_file("/proc/" + std::to_string(pid) + "/comm"); + + if (comm_file.is_open()) { + std::getline(comm_file, process_name); + comm_file.close(); + } else { + process_name = "unknown"; + } + + return process_name; +} + +std::string get_process_cmdline(pid_t pid) { + std::string cmdline; + std::ifstream cmdline_file("/proc/" + std::to_string(pid) + "/cmdline"); + + if (cmdline_file.is_open()) { + std::getline(cmdline_file, cmdline, '\0'); + cmdline_file.close(); + } else { + cmdline = "unknown"; + } + + return cmdline; +} +void print_event(void *context, void *data, int data_size) { + struct event_data_t { + int type; + uint32_t pid; + uint32_t ppid; + }; + + auto event = static_cast(data); + auto [process_exists, path] = get_process_path(event->pid); + if (event->type == 0 && process_exists == false) { + // 进程启动如果路径为空说明取不到了 + // 进程结束路径一定是取不到的 + return; + } + auto process_name = get_process_name(event->pid); + auto cmdline = get_process_cmdline(event->pid); + auto event_type = event->type == 0 ? "start" : "exit"; + printf("type: %s pid: %d ppid: %d path: %s name: %s cmdline: %s\n", + event_type, event->pid, event->ppid, path.c_str(), + process_name.c_str(), cmdline.c_str()); +} + +int main() { + ebpf::BPF bpf; + std::ifstream ebpf_file(EBPF_SOURCE_PATH, std::ios::binary); + // 检查文件是否存在 + if (ebpf_file.fail()) { + std::cerr << "Failed to open " << EBPF_SOURCE_PATH << std::endl; + return 1; + } + std::vector ebpf_program((std::istreambuf_iterator(ebpf_file)), + std::istreambuf_iterator()); + auto init_res = + bpf.init(std::string(ebpf_program.data(), ebpf_program.size())); + if (init_res.code() != 0) { + std::cerr << "Failed to initialize BPF program: " << init_res.msg() + << std::endl; + return 1; + } + + std::string execve_fnname = bpf.get_syscall_fnname("execve"); + std::string exit_group_fnname = bpf.get_syscall_fnname("exit_group"); + + auto attach_res1 = bpf.attach_kprobe(execve_fnname, "trace_process_start"); + auto attach_res2 = + bpf.attach_kprobe(exit_group_fnname, "trace_process_exit"); + + if (attach_res1.code() != 0 || attach_res2.code() != 0) { + std::cerr << "Failed to attach kprobes: " << attach_res1.msg() << " " + << attach_res2.msg() << std::endl; + return 1; + } + + signal(SIGINT, signal_handler); + + auto ret = + bpf.open_perf_buffer("events", print_event, nullptr, nullptr, 256); + if (ret.code() != 0) { + fprintf(stderr, "Error: open_perf_buffer: %s\n", ret.msg().c_str()); + return EXIT_FAILURE; + } + auto table = bpf.get_table("events"); + auto perf_buffer = bpf.get_perf_buffer("events"); + + while (!interrupted) { + perf_buffer->poll(1000); + } + + return 0; +} diff --git a/ebpf/test.py b/ebpf/test.py new file mode 100644 index 0000000..92346c8 --- /dev/null +++ b/ebpf/test.py @@ -0,0 +1,69 @@ +from bcc import BPF +from time import sleep + +# eBPF program to trace process creation and exit +program = """ +#include +#include + +struct event_data_t { + int type; + u32 pid; + u32 ppid; +} __attribute__((packed)); + +BPF_PERF_OUTPUT(events); + +int trace_process_start(struct pt_regs *ctx, struct filename *filename) { + struct event_data_t event_data; + + u32 pid = bpf_get_current_pid_tgid(); + u32 ppid = bpf_get_current_pid_tgid() >> 32; + event_data.type = 0; + event_data.pid = pid; + event_data.ppid = ppid; + events.perf_submit(ctx, &event_data, sizeof(event_data)); + return 0; +} + +int trace_process_exit(struct pt_regs *ctx) { + struct event_data_t event_data; + + u32 pid = bpf_get_current_pid_tgid(); + u32 ppid = bpf_get_current_pid_tgid() >> 32; + event_data.type = 1; + event_data.pid = pid; + event_data.ppid = ppid; + events.perf_submit(ctx, &event_data, sizeof(event_data)); + + return 0; +} +""" + +# initialize BPF and attach tracepoints +b = BPF(text=program) +b.attach_kprobe(event=b.get_syscall_fnname("execve"), fn_name="trace_process_start") +b.attach_kprobe(event=b.get_syscall_fnname("exit_group"), fn_name="trace_process_exit") + +import psutil + +def get_process_path(pid): + try: + proc = psutil.Process(pid) + return proc.exe() + except (psutil.NoSuchProcess, psutil.AccessDenied): + return "unknown" + +# process event data +def print_event(cpu, data, size): + event = b["events"].event(data) + path = get_process_path(event.pid) + print(f"type: {event.type} pid: {event.pid}, ppid: {event.ppid} path: {path}") + +b["events"].open_perf_buffer(print_event) + +while True: + try: + b.perf_buffer_poll() + except KeyboardInterrupt: + exit()