这篇文章上次修改于 836 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
前言
Android从9.0版本开始全面支持eBPF(extended Berkeley Packet Filters), 其主要用在流量统计上, 也可以用来监控CPU/IO/内存等模块的状态.简单来说, eBPF可以与内核的kprobe/tracepoints/skfilter等模块相结合, 将eBPF的函数hook到内核事件从而监控相应的系统状态。
在之前,逆向分析过程中为了追踪so的系统调用,通常是结合frida做的
基于frida,各路大佬给出了多种方案,在此列举一二
frida-syscall-interceptor
frida-syscall-interceptor Arm64版
interruptor
frida-svc-interceptor
Frida-Seccomp
另外补充一个非frida的方案
Syscall_intercept_arm64
frida很方便,但是随着对抗日益升级,使用frida的前提是先过frida检测,检测手段不断在升级,搞不定岂不是很难受,这个时候就要换个赛道
- 改内核?水平不够
- 自编译ROM?太复杂
- 使用沙盒APP?难以贴近真机环境
而eBPF可以以不侵入的方式去记录程序的一举一动,对于APP来说是完全无感的
对于逆向工作者来说,eBPF有个【缺陷】,即无法更改其中的逻辑,只能记录信息
不过查询资料,应该是可以配合SECCOMP
来实现修改
【更正】实际上是存在bpf_probe_write_user
这样的函数,可以修改用户态数据;不过没有修改内核态数据的函数
说了这么多,其实就一句话,系统自带有追踪系统调用的功能,正是基于eBPF提供的
环境
- Android 11
- Pixel 4XL
- root权限
步骤
下面命令中的路径在不同系统可能不同,即有的系统是第一个,有的是第二个,有的两个都有
- /sys/kernel/tracing
- /sys/kernel/debug/tracing
而两个都有的话,其实是一样的,比如本文使用的测试环境就是两个都有
进入shell环境,并切换到root身份
adb shell
su
先查看是否支持syscall调用的追踪
coral:/ # zcat /proc/config.gz | grep TRACEPOINT
CONFIG_TRACEPOINTS=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
# CONFIG_TRACEPOINT_BENCHMARK is not set
如果出现CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
那么就说明支持
执行下面两个命令,对系统调用之前的状态进行追踪
echo 1 > /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/enable
echo 1 > /sys/kernel/debug/tracing/tracing_on
注意,如果不想追踪了,记得将配置改回去,毕竟会带来一些性能消耗...
echo 0 > /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/enable
echo 0 > /sys/kernel/debug/tracing/tracing_on
相关的输出会保存到/sys/kernel/debug/tracing/trace
,而默认有一个格式,通过下面的命令可以看到格式
coral:/ # head /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 265418/5871240 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
也就是说会打印PID
信息,那么可以过滤下pid,减少输出
日志信息实时输出到/sys/kernel/debug/tracing/trace_pipe
那么查看指定pid的系统调用人命令如下
cat /sys/kernel/debug/tracing/trace_pipe | grep 23841
效果是这样的
其中NR后面的数字就是系统调用号,至于后面几个...暂时没有搞清楚
这个输出格式可以通过下面的命令查看
coral:/ # cat /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/format
name: sys_enter
ID: 18
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:long id; offset:8; size:8; signed:1;
field:unsigned long args[6]; offset:16; size:48; signed:0;
print fmt: "NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", REC->id, REC->args[0], REC->args[1], REC->args[2], REC->args[3], REC->args[4], REC->args[5]
系统提供的比较简单,我们当然可以自行编写eBPF程序,然后解析参数,具体打印出调用的详细情况
关于这一点,后面会单独写一篇文章
除了sys_enter
,还有sys_exit
,是系统调用结束后的状态
同样也可以通过上面方式开启追踪
如果相同时开启,那么执行下面的命令即可
echo 1 > /sys/kernel/debug/tracing/events/raw_syscalls/enable
这个时候你会发现,其实在/sys/kernel/debug/tracing/events
下面还有许多类型的事件,它们都可以通过向对应的enable
管道写入配置,开启tracing_on
,实现对应信息的追踪
/sys/kernel/debug/tracing/events
下面有许多文件夹,每个文件夹下可能还有文件夹
如果向更高层级的文件夹的enable
写入1
,那么文件夹下的子文件夹的对应事件也会被开启记录
而/sys/kernel/debug/tracing/events/enable
则是最顶层的控制开关,如果向其中写入1,那么将记录所有内置的事件,这个时候输出会非常多
没有评论