
hunter的这个overlay system检测不是必要的,一开始推测检测原理就是在native 拿 statfs和fstatfs函数查看/system返回的f_type

10进制的2035054128对应的16进制是 0x794C7630 也就是overlayFS的魔数(magic number 这个专业术语我也不知道是什么)
5eb90ccb0bd2:/data/local/tmp # stat -f -c %T /system
0x794c7630strace一下 再拿ebpf处理一下就ojbk了

牛头也检测,但是方法和hunter有些区别
root@orangepi5pro:~/ebpf# cat /sys/kernel/debug/tracing/available_events | grep statfs
syscalls:sys_exit_fstatfs
syscalls:sys_enter_fstatfs
syscalls:sys_exit_statfs
syscalls:sys_enter_statfs
root@orangepi5pro:~/ebpf# cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_statfs/format
name: sys_enter_statfs
ID: 735
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int __syscall_nr; offset:8; size:4; signed:1;
field:const char * pathname; offset:16; size:8; signed:0;
field:struct statfs * buf; offset:24; size:8; signed:0;
print fmt: "pathname: 0x%08lx, buf: 0x%08lx", ((unsigned long)(REC->pathname)), ((unsigned long)(REC->buf))
光这一个点位还不够 fstats 也需要操作,ctx->arg[1] 是一个statfs的指针结构体,这个偷不了懒了,涉及到的syscall操作比较多,需要先用enter_openat判断路径存入hash_map,再去和enter_fstats和exit_fstats配合,exit的时候在hash_map里取出地址修改buf里的type,statfs的结构在这里能看到,最后在exit_fstats清理掉map
https://elixir.bootlin.com/linux/v5.10/source/arch/mips/include/uapi/asm/statfs.h#L23
cat /sys/kernel/debug/tracing/events/syscalls/sys_exit_fstatfs/format <
name: sys_exit_fstatfs
ID: 732
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int __syscall_nr; offset:8; size:4; signed:1;
field:long ret; offset:16; size:8; signed:1;
print fmt: "0x%lx", REC->ret
cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_fstatfs/format <
name: sys_enter_fstatfs
ID: 733
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int __syscall_nr; offset:8; size:4; signed:1;
field:unsigned int fd; offset:16; size:8; signed:0;
field:struct statfs * buf; offset:24; size:8; signed:0;
print fmt: "fd: 0x%08lx, buf: 0x%08lx", ((unsigned long)(REC->fd)), ((unsigned long)(REC->buf))#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
// 简化版 只做可行性验证
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 128);
__type(key, unsigned int);
__type(value, u64);
} fstatfs_map SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_fstatfs")
int tracepoint__syscalls__sys_enter_fstatfs(struct trace_event_raw_sys_enter *ctx)
{
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
unsigned int pid_ns = get_namespace_pid(task);
if(pid_ns != filter_ns){
return 0;
}
u32 pid = bpf_get_current_pid_tgid() >> 32;
u64 statfs_addr = (u64)ctx->args[1];
bpf_map_update_elem(&fstatfs_map, &pid, &statfs_addr, BPF_ANY);
return 0;
}
SEC("tracepoint/syscalls/sys_exit_fstatfs")
int tracepoint__syscalls__sys_exit_fstat(struct trace_event_raw_sys_exit *ctx)
{
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
unsigned int pid_ns = get_namespace_pid(task);
if(pid_ns != filter_ns){
return 0;
}
u32 pid = bpf_get_current_pid_tgid() >> 32;
u64 *statfs_addr = bpf_map_lookup_elem(&fstatfs_map, &pid);
if(!statfs_addr){
return 0;
}
struct statfs statfs;
int ret = bpf_probe_read_user(&statfs, sizeof(statfs), (const void *)*statfs_addr);
if(statfs.f_type == 2035054128){
statfs.f_type = 0xef53;
bpf_probe_write_user((void *)*statfs_addr, &statfs, sizeof(statfs));
}
bpf_map_delete_elem(&fstatfs_map, &pid);
return 0;
}
char LICENSE[] SEC("license") = "GPL";最后效果 又换成vendor了 实际测试下来上面的没有效果 但是代码对以后的修改结构体变量有帮助


补上之后,好消息是消失了,但是又蹦出来了个新的东西 (Permission 权限检测问题)
