ebpf入门---监听所有新进程

本文介绍了eBPF(扩展的伯克利包过滤器),一种可以在不修改内核源代码的情况下与内核交互的技术。文章探讨了eBPF的底层优势,如绕过安全监控和潜在的隐秘操作,以及通过hooksyscall进行系统调用的示例。最后提到了将Python和Go代码编译为静态链接的挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是ebpf

eBPF 全称 extended Berkeley Packet Filter,中文意思是 扩展的伯克利包过滤器。一般来说,要向内核添加新功能,需要修改内核源代码或者编写 内核模块 来实现。而 eBPF 允许程序在不修改内核源代码,或添加额外的内核模块情况下运行

用途

ebpf由于直接与内核交互,所以更为底层,可以用来绕过一些安全组件的监控功能。同时可以做到如你看不见的后门(通过hook read的syscall,篡改返回结果)等等更有意思的场景。个人看来,ebpf在未来会得到更广泛的应用,同时也是以后rootkit的首选

简单使用

今天这个demo是个入门,原理就是hook syscall,判断是否是execve,然后获取对应的pid和执行文件,然后返回并输出

python

整体代码还是很简单的,注释里面也比较详细了

from bcc import BPF

bpf_text = """
#include <linux/binfmts.h>
struct data_t {
    int pid;
    char comm[TASK_COMM_LEN];
    char filename[256]; 
};

BPF_PERF_OUTPUT(myevents);//注册events

TRACEPOINT_PROBE(raw_syscalls, sys_enter) {
    if (args->id != __NR_execve)
        return 0;
    struct data_t data = {};
    data.pid = bpf_get_current_pid_tgid() >> 32;//获取pid
    bpf_get_current_comm(&data.comm, sizeof(data.comm));//获取当前进程的命令名称
    bpf_probe_read_user(&data.filename, sizeof(data.filename), (void *)args->args[0]);//用户空间读取execve的第一个参数,通常是要执行的文件路径
    myevents.perf_submit(args, &data, sizeof(data));// 将data结构体的内容发送到用户空间的events性能事件输出
    return 0;
}
"""

b = BPF(text=bpf_text)#创建了一个BPF对象b,它用于编译和加载前文中定义的eBPF程序


def print_event(cpu, data, size):#它是一个回调函数,用于处理从eBPF程序发送到用户空间的事件。函数的参数包括:cpu:捕获事件的CPU编号。,data:一个包含eBPF事件数据的字节流。,size:数据的大小。
    event = b["myevents"].event(data)#将data字节流转换成一个Python对象,这个对象包含了与eBPF程序中定义的数据结构匹配的字段
    print("New process created, PID: %d, Command: %s, Path: %s" % (event.pid, event.comm.decode('utf-8', 'replace'), event.filename.decode('utf-8', 'replace')))


b["myevents"].open_perf_buffer(print_event)#这行代码将print_event回调函数附加到名为myevents的eBPF性能事件输出上。当myevents输出中有新的事件时,print_event函数将被调用。

print("Listening for sys_execve calls... Press Ctrl+C to exit.")
try:
    while True:
        b.perf_buffer_poll()#用于轮询性能事件缓冲区,检查是否有任何新的事件到达。如果有,它将调用open_perf_buffer登记的回调函数来处理事件。
except KeyboardInterrupt:
    pass

运行效果
在这里插入图片描述

go

go代码更为复杂一点,但大体逻辑上类似

package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "os"
    "os/signal"

    "github.com/iovisor/gobpf/bcc"
)

const bpfProgram = `
#include <linux/sched.h>

struct data_t {
    u32 pid;
    char comm[TASK_COMM_LEN];
    char filename[256];
};

BPF_PERF_OUTPUT(myevents);

TRACEPOINT_PROBE(raw_syscalls, sys_enter) {


    if (args->id != __NR_execve) return 0;
    struct data_t data = {};
    data.pid = bpf_get_current_pid_tgid() >> 32;
    bpf_get_current_comm(&data.comm, sizeof(data.comm));
    bpf_probe_read_user(&data.filename, sizeof(data.filename), (void *)args->args[0]);


    myevents.perf_submit(args, &data, sizeof(data));

    return 0;
}

`

type execveEvent struct {
    Pid      uint32
    Comm     [16]byte
    Filename [256]byte
}

func main() {

    //创建了一个新的 eBPF 模块,并加载了 eBPF 程序。defer module.Close() 确保在程序结束时清理和关闭 eBPF 模块
    module := bcc.NewModule(bpfProgram, []string{})
    defer module.Close()
    //加载 eBPF 程序中定义的跟踪点
        tracepoint, err := module.LoadTracepoint("tracepoint__raw_syscalls__sys_enter")
    if err != nil {
    fmt.Fprintf(os.Stderr, "Failed to load tracepoint: %s\n", err)
    os.Exit(1)
    }

    //将跟踪点附加到系统调用的入口点
    err = module.AttachTracepoint("raw_syscalls:sys_enter", tracepoint)
    if err != nil {
    fmt.Fprintf(os.Stderr, "Failed to attach tracepoint: %s\n", err)
    os.Exit(1)
    }

    //创建一个新的性能事件表来接收 eBPF 程序发送的事件,并创建一个 Go 通道来接收这些事件
    table := bcc.NewTable(module.TableId("myevents"), module)
    channel := make(chan []byte)
    perfMap, err := bcc.InitPerfMap(table, channel, nil)
    if err != nil {
    fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err)
    os.Exit(1)
    }

    go func() {
    for {
    data := <-channel
    var event execveEvent
    err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event)
    if err != nil {
    fmt.Fprintf(os.Stderr, "Failed to decode received data: %s\n", err)
    continue
    }
    filename := string(bytes.Split(event.Filename[:], []byte("\x00"))[0])
    fmt.Printf("execve called by PID %d (%s): %s\n", event.Pid, event.Comm, filename)
    }
    }()

    //启动性能事件表来接收事件,并确保在程序结束时停止它
    perfMap.Start()
    defer perfMap.Stop()

    fmt.Println("Waiting for execve events... Press Ctrl-C to exit.")
    signals := make(chan os.Signal, 1)
    signal.Notify(signals, os.Interrupt)
    <-signals
}

效果
在这里插入图片描述

但是这两个都有一个共性的问题,python虽然可以是pyinstaller去编译成可执行文件,但和go编译的结果都是动态链接的,而往往目标机器上可能没有对应的库,所以我们要转化为静态链接,目前这两个demo我尝试了一下是无法变成静态链接的,如果有思路也可以进一步交流

<think>嗯,用户之前问过如何用Python制作杀毒软件,现在又提到可能不需要特征比对,而是在运行时拦截恶意操作。这说明用户可能对传统基于特征码的杀毒方法不太满意,想探索行为监控的方法。我需要先确认用户的需求是什么,他们可能希望更主动的防御方式,类似于实时监控程序行为而不是静态扫描。 用户可能对现有杀毒软件的工作原理有一定了解,但想用Python实现类似行为分析的功能。需要分析行为监控的可行性,以及Python在这方面的优缺点。比如,Python在系统底层操作上的限制,可能需要依赖其他工具或库。 另外,用户可能关心如何具体实现行为拦截,比如监控文件操作、网络访问、进程创建等。这时候需要给出具体的实现思路,比如使用hook技术或现有库,同时指出潜在的技术难点,比如权限问题、性能影响等。 还要考虑到用户的技术水平,可能对系统底层不太熟悉,所以需要建议一些适合入门的库或框架,比如sysinternals的某些工具,或者Python的psutil、socket等库。同时提醒用户Python在实时监控方面的局限性,可能需要结合其他语言或工具。 最后,总结行为监控的优点和挑战,帮助用户权衡是否采用这种方法,并鼓励他们进行实验和学习。可能需要推荐进一步的学习资源,如动态分析工具或沙箱技术,供用户深入研究。</think>你的思路更偏向于 **主动防御(Active Defense)** 或 **行为监控(Behavior Monitoring)**,这种方法不依赖静态特征库,而是通过动态拦截程序的行为(如文件篡改、网络通信、系统调用等)来判断是否恶意。这种设计确实更先进,但实现难度也更高。以下是具体分析和建议: --- ### **1. 行为监控的核心逻辑** - **监控对象** 需重点关注高风险行为: - **文件操作**:加密文件(类似勒索软件)、覆盖系统文件 - **进程行为**:注入其他进程、提权操作 - **网络活动**:连接恶意 IP、高频发送敏感数据 - **注册表/配置修改**(Windows 特有) - **内存操作**:代码注入、Shellcode 执行 - **拦截机制** - **Hook 技术**:挂钩系统 API(如 Windows 的 `CreateProcess`、`WriteFile`),在关键操作前阻断。 - **沙箱(Sandbox)**:在隔离环境中运行程序,观察其行为。 - **系统日志监控**:解析系统日志(如 Linux 的 `auditd`、Windows 事件日志)检测异常。 --- ### **2. Python 的实现可能性** #### **可行方案** - **简易行为监控器** 用 Python 调用系统工具或库实现基础监控- **文件监控**:使用 `watchdog` 库监听文件变动,结合规则判断是否恶意(如频繁修改 `.docx` 文件)。 ```python from watchdog.events import FileSystemEventHandler class Handler(FileSystemEventHandler): def on_modified(self, event): if event.src_path.endswith(".docx"): analyze_behavior(event.src_path) # 自定义分析函数 ``` - **网络监控**:用 `scapy` 或 `socket` 库抓包,检测可疑连接: ```python from scapy.all import sniff def packet_callback(packet): if packet.haslayer("IP") and packet["IP"].dst == "1.2.3.4": block_ip(packet["IP"].src) # 封禁来源 IP sniff(prn=packet_callback, store=0) ``` - **进程监控**:通过 `psutil` 库追踪进程行为: ```python import psutil for proc in psutil.process_iter(): if "malicious.exe" in proc.name(): proc.kill() ``` #### **技术难点** - **底层交互限制** Python 难以直接挂钩系统 API(需依赖 C/C++ 扩展或调用外部工具如 `Sysinternals` 的 `Process Monitor`)。 - **性能与实时性** 纯 Python 实现的监控可能延迟较高,难以处理高频操作。 - **绕过风险** 恶意程序可能检测到 Python 监控进程并主动终止它。 --- ### **3. 改进方向** #### **结合系统工具** - **Windows** 调用 PowerShell 或 `Windows Defender` 的 API(如 `AMSI` 接口)增强拦截能力。 - **Linux** 利用 `auditd` 或 `eBPF` 实现内核级监控(需编写 C 模块)。 #### **集成机器学习** 通过行为日志训练模型,识别异常模式: ```python from sklearn.ensemble import IsolationForest # 假设 logs 是包含 CPU、文件操作等指标的数据集 model = IsolationForest() model.fit(logs) anomalies = model.predict(new_logs) # 预测异常行为 ``` #### **沙箱化执行** 结合虚拟化技术(如 `Docker`)运行可疑程序: ```bash # 在 Docker 容器中运行程序并监控 docker run --rm -v /safe/path:/app malware.exe ``` --- ### **4. 实际案例参考** - **开源项目** - **Cuckoo Sandbox**:Python 编写的自动化恶意软件分析系统,支持行为监控- **ProcMon**(非 Python):Windows 系统级行为监控工具,可导出日志供 Python 分析。 - **商业产品逻辑** 火绒、卡巴斯基等杀毒软件会混合使用特征码扫描 + 行为分析 + 云查杀。 --- ### **5. 对初学者的建议** 1. **从简单场景入手** 例如:监控 USB 设备插入时自动扫描文件,或阻止特定程序启动。 2. **利用现有中间件** 如 `YARA` 规则匹配进程内存中的恶意代码片段。 3. **测试环境安全** 务必在虚拟机中测试,避免真实系统被感染。 --- ### **总结** - **可以实现**:用 Python 构建轻量级行为监控工具,尤其适合学习原理。 - **难以实用化**:高实时性、防绕过、性能优化需依赖底层语言(如 C)或系统级支持。 - **进阶学习**:推荐研究反病毒引擎(如 ClamAV)、逆向工程(如 IDA Pro)或威胁狩猎框架(如 MITRE ATT&CK)。 如果需要具体的代码示例(如拦截进程创建),可以进一步说明场景!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值