首页
社区
课程
招聘
[原创] 60秒学会用eBPF-BCC hook系统调用
发表于: 2022-10-28 08:07 25558

[原创] 60秒学会用eBPF-BCC hook系统调用

2022-10-28 08:07
25558

(备注1: 为了格式工整, 前面都是废话, 建议直接从11 hello world开始看)
(备注2: 60秒指的是在Linux上, 如果是Android可能要在基础再上加点)

整理自2022/10 (bcc Release v0.25.0)

.
.

Linux内核中运行的虚拟机,
可以在外部向其注入代码执行.
.
.

理解成BFP PLUS++
.
.

BPF虚拟机只运行BPF指令, 直接敲BPF指令比较恶心.
BCC可以理解成辅助写BPF指令的工具包,
用python和c语言间接生成EBPF指令.
.
.

指的是开源项目&&开发者社区,
BCC是IOVisor项目下的编译器工具集.
.
.


.
.

参考官方文档
https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md
.

查看自己Linux 内核版本 (ubuntu)

.
.

Brendan Gregg出品教程
https://www.brendangregg.com/ebpf.html
.

linux内核调试追踪技术20讲
https://space.bilibili.com/646178510/channel/collectiondetail?sid=468091
.

使用ebpf跟踪rpcx微服务
https://colobu.com/2022/05/22/use-ebpf-to-trace-rpcx-microservices/
.
.

具体参考官方文档
https://github.com/iovisor/bcc/blob/master/INSTALL.md
.

iovisor版 (官网说这个比较旧)

.

.


.
.

.

.

.
.

运行hello_world.py
进入bcc/examples目录,
运行脚本sudo python3 hello_world.py,
它的逻辑是, hook了某个syscall, 每当运行该syscall, 就输出helloworld.
你随便点点鼠标, 就能触发它显示日志了.

.

运行hello_fields.py
这个脚本是一样的逻辑, 不过输出格式对齐了,

.
.

进入bcc/tools/目录,运行opensoop.py脚本.
然后自己开clion编一个demo,
调用open触发eBFP的callback.

.
.

opensoop.py的实现
ok, 上面这样eBPF就算跑起来了,
然后, 直奔主题, 就说上面那个脚本是怎么hook的open?
.
我打开那个脚本看了一下, 一大堆基本都在处理兼容和格式.
把不关心的东西都删了, 留下核心的代码, 写好注释放这里了.
.
.

如何任意的hook syscall?
只关心4点:
(1)怎么写before?
(2)怎么写after?
(3)怎么注册hook?
(4)怎么输出日志?
(跟xposed差不多的叙事结构)

.
.

60秒学会用eBPF-BCC hook系统调用 ( 2 ) hook安卓所有syscall
.
.

xxx@ubuntu:~/Desktop/bcc/build$ uname -a
Linux ubuntu 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
xxx@ubuntu:~/Desktop/bcc/build$ uname -a
Linux ubuntu 5.15.0-52-generic #58~20.04.1-Ubuntu SMP Thu Oct 13 13:09:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)
echo "deb [trusted=yes] https://repo.iovisor.org/apt/xenial xenial-nightly main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)
echo "deb [trusted=yes] https://repo.iovisor.org/apt/xenial xenial-nightly main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.5 LTS
Release:    20.04
Codename:   focal
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.5 LTS
Release:    20.04
Codename:   focal
# For Focal (20.04.1 LTS)
sudo apt install -y bison build-essential cmake flex git libedit-dev \
  libllvm12 llvm-12-dev libclang-12-dev python zlib1g-dev libelf-dev libfl-dev python3-distutils
# For Focal (20.04.1 LTS)
sudo apt install -y bison build-essential cmake flex git libedit-dev \
  libllvm12 llvm-12-dev libclang-12-dev python zlib1g-dev libelf-dev libfl-dev python3-distutils
git clone https://github.com/iovisor/bcc.git
mkdir bcc/build; cd bcc/build
cmake ..
make
sudo make install
cmake -DPYTHON_CMD=python3 .. # build python3 binding
pushd src/python/
make
sudo make install
popd
git clone https://github.com/iovisor/bcc.git
mkdir bcc/build; cd bcc/build
cmake ..
make
sudo make install
cmake -DPYTHON_CMD=python3 .. # build python3 binding
pushd src/python/
make
sudo make install
popd
#!/usr/bin/env python
# 该代码在ubuntu 20环境里运行通过
from __future__ import print_function
from bcc import ArgString, BPF
from bcc.containers import filter_by_containers
from bcc.utils import printb
import argparse
from collections import defaultdict
from datetime import datetime, timedelta
import os
 
# 注入到eBPF虚拟机的代码
bpf_text = '''
#include <uapi/linux/ptrace.h>
#include <uapi/linux/limits.h>
#include <linux/sched.h>
 
// hook到参数和返回值,放在这两个结构里
struct val_t {
  u64 id;
  char comm[TASK_COMM_LEN];
  const char *fname;
};
 
// 同上
struct data_t {
  u64 id;
  int ret;
  char comm[TASK_COMM_LEN];
  char name[NAME_MAX];
};
 
 
// 创建一个events (hook到东西后就用它通知python那个callback输出)
BPF_PERF_OUTPUT(events);
 
 
// 这个api是在创建一个map变量,变量名为infotmp
// 因为你不能在eBPF里用std::map, 只能用它提供的这种东西.
BPF_HASH(infotmp, u64, struct val_t);
 
 
// after函数
int after_openat(struct pt_regs *ctx) {
  u64 id = bpf_get_current_pid_tgid(); // 获取tid
  struct val_t *valp;
  struct data_t data = {};
  valp = infotmp.lookup(&id); // 在map中查询id
  if (valp == 0) {
    return 0;
  }
  // 从map中读取至局部变量
  bpf_probe_read_kernel(&data.comm, sizeof(data.comm), valp->comm);
  bpf_probe_read_user_str(&data.name, sizeof(data.name), (void *)valp->fname);
  data.id = valp->id;
  data.ret = PT_REGS_RC(ctx); // before里读取了参数,此时在after里补充返回值
  events.perf_submit(ctx, &data, sizeof(data)); // 提交perf poll事件来让perf输出(作用就是,调用它会通知python中那个callback输出日志)
  infotmp.delete(&id); // 从map中删除id
  return 0;
}
 
 
int syscall__before_openat(struct pt_regs *ctx, int dfd,
                                const char __user *filename, int flags) {
  struct val_t val = {};
  u64 id = bpf_get_current_pid_tgid();
  u32 pid = id >> 32;
  // 获取当前进程名
  if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
    val.id = id;
    val.fname = filename;
    infotmp.update(&id, &val); // id插入map
  }
  return 0;
};
'''
 
# 注册hook
b = BPF(text=bpf_text)
b.attach_kprobe(event="__x64_sys_openat", fn_name="syscall__before_openat")
b.attach_kretprobe(event="__x64_sys_openat", fn_name="after_openat")
 
# 回调函数
def my_callback(cpu, data, size):
    temp = b["events"].event(data)
    if temp.id is not None:
        print("[pid]",temp.id & 0xffffffff, end=" ")
    if temp.name is not None:
        print("[path]",temp.name, end=" ")
    if temp.ret is not None:
        print("[ret]",temp.ret, end=" ")
    if temp.comm is not None:
        print("[comm]",temp.comm, end=" ")
    print("")
 
b["events"].open_perf_buffer(my_callback, page_cnt=64)
while True:
    try:
        # 等待数据, 触发open_perf_buffer指定的回调函数
        b.perf_buffer_poll()
    except KeyboardInterrupt:
        exit()
pass
#!/usr/bin/env python
# 该代码在ubuntu 20环境里运行通过
from __future__ import print_function
from bcc import ArgString, BPF
from bcc.containers import filter_by_containers
from bcc.utils import printb
import argparse
from collections import defaultdict
from datetime import datetime, timedelta
import os
 
# 注入到eBPF虚拟机的代码
bpf_text = '''
#include <uapi/linux/ptrace.h>
#include <uapi/linux/limits.h>
#include <linux/sched.h>
 
// hook到参数和返回值,放在这两个结构里
struct val_t {
  u64 id;
  char comm[TASK_COMM_LEN];
  const char *fname;
};
 
// 同上
struct data_t {
  u64 id;
  int ret;
  char comm[TASK_COMM_LEN];
  char name[NAME_MAX];
};
 
 
// 创建一个events (hook到东西后就用它通知python那个callback输出)
BPF_PERF_OUTPUT(events);
 
 
// 这个api是在创建一个map变量,变量名为infotmp
// 因为你不能在eBPF里用std::map, 只能用它提供的这种东西.
BPF_HASH(infotmp, u64, struct val_t);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-9-6 16:48 被爱吃菠菜编辑 ,原因: 精简
收藏
免费 22
支持
分享
最新回复 (9)
雪    币: 4034
活跃值: (2223)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
表哥NB
2022-10-28 09:28
0
雪    币: 2141
活跃值: (7231)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
3
Umiade 表哥NB
2022-10-28 09:53
0
雪    币: 2504
活跃值: (4631)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2022-10-28 11:53
0
雪    币: 3144
活跃值: (1624)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
表哥,我还是不会
2022-10-28 13:29
0
雪    币: 196
活跃值: (5976)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
6
射射老师,已经学会了。
2022-10-28 16:06
0
雪    币: 33
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7

666666

最后于 2022-11-17 15:32 被Bingo_player编辑 ,原因:
2022-10-28 16:59
0
雪    币: 5330
活跃值: (5479)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
8
666
2022-11-14 11:11
0
雪    币: 685
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
666
2023-3-17 17:48
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
666
2023-10-30 15:23
0
游客
登录 | 注册 方可回帖
返回
//