这篇文章上次修改于 893 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

前言

bcc编译和体验记录

环境

  • Pixel 4XL
  • coral-sq3a.220605.009.a1
  • 手机有root权限

步骤

如果手机还没有准备rootfs环境,请参考下面的文章

配置rootfs

修改下源,安装一些软件

sed -i 's/ftp.us.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list

现在安装一些软件,这里的环境默认是root,命令操作都不需要加sudo

apt update
apt install git proxychains4 p7zip-full nano openssh-client openssh-server apt-utils

可能会出现下面的警告

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
debconf: delaying package configuration, since apt-utils is not installed

可以编辑.bashrc,在文件末尾加上export LC_ALL=C

nano ~/.bashrc
source ~/.bashrc

2022-06-26T15:09:41.png

后面再安装包的时候就不会出现了

2022-06-26T15:11:09.png

使用apt命令可能会提示说无法解析域名

经过查阅资料解决方案是修改/etc/passwd_apt655343003,这个时候可以用vi编辑

如果想在手机上通过文件管理器修改,那么请注意路径是/data/eadb/debian/etc/passwd

/data/eadb/debianrootfs的根目录

2022-06-26T15:03:44.png

详情请查阅

为了加快后面下载代码的速度,这里也配置下proxychains4

nano /etc/proxychains4.conf

编译并安装bcc

同步维术大佬修改好的bcc代码

proxychains -q git clone https://github.com/tiann/bcc.git

2022-06-26T15:13:54.png

由于后面还会同步其他项目的代码文件,所以这里第一次cmake也挂了代理

cd bcc
mkdir build && cd build
proxychains -q cmake ..

2022-06-26T15:15:50.png

LuaJIT和netperf这个可以暂时不管

然后开始编译bcc,成功之后安装

make -j8
make install

2022-06-26T15:19:29.png

2022-06-26T15:19:49.png

vscode远程连接与ssh配置

在体验bcc之前我们先配置下ssh,方便vscode连接修改代码

nano /etc/ssh/sshd_config

2022-06-26T15:21:10.png

2022-06-26T15:24:50.png

重启ssh服务,(手机每次重启后的第一次进入debian环境,可能都需要手动启动下ssh服务)

service ssh restart

然后把vscode的ssh配置公钥写入到debian的~/.ssh/authorized_keys

mkdir ~/.ssh
cat id_rsa.pub >> ~/.ssh/authorized_keys

2022-06-26T15:27:32.png

这个时候可以通过ssh连上了,电脑上vscode的ssh配置

2022-06-26T15:29:05.png

通过Remote SSH连上后,还可以安装上python插件等等

对了这个环境里面没有pip,手动通过get-pip.py安装上

proxychains -q wget https://bootstrap.pypa.io/get-pip.py
proxychains -q python get-pip.py

2022-06-26T15:33:21.png

这手机俨然可以做一个开发环境了啊(不是

体验bcc

现在来体验下bcc吧,先找个目标

2022-06-26T15:39:30.png

切换到bcc/tools下,示例如下,这个是用来统计指定库某个函数的调用情况,具体实现请查看stackcount.py脚本

2022-06-26T15:42:44.png

python stackcount.py -U -p 17507 /apex/com.android.runtime/lib64/bionic/libc.so:open

小姿势,有关bcc的脚本中,一般要指定库的时候都是指定进程内存加载的那个路径,比如这里的libc.so的路径是

  • /apex/com.android.runtime/lib64/bionic/libc.so

2022-06-26T15:44:31.png

如果指定为/system/lib64/libc.so测试是没有效果的

具体的测试效果如下图,可以看到统计了调用次数和调用栈情况

2022-06-26T15:40:46.png

不过看起来好像没有特别有用的信息,不过这个还需要自行编写脚本实现更强的效果~

小小总结

需要注意的是,如果手机是4.x系列的内核,可能测试其他很多脚本都跑不起来

这是因为手机内核可能没有开启CONFIG_KPROBES,所以能做到的是对用户态程序追踪

还有可以通过tracepoint之类的获取用户态程序调用情况

另外根据bcc已知issue,可以知道,安卓上在比较老的内核中是无法在内核态读取用户态数据的

只能自己打补丁,重新编译内核,如果内核什么都不改动,那么通过eBPF去追踪数据只能在已有的挂载点上做文章了

补丁链接

sslsniff.py这个脚本为例,执行命令如下

python sslsniff.py -p 17507 --no-openssl --no-gnutls --no-nss --hexdump -x --extra-lib openssl:/apex/com.android.conscrypt/lib64/libssl.so

这个脚本不是专门针对安卓的,所以这里要用--extra-lib

首先修改probe_SSL_do_handshake_enter这个函数,添加下面一行代码

u32 uid = bpf_get_current_uid_gid();

2022-06-26T15:54:35.png

因为这里后面用到了uid但是没有初始化...估计都没什么用人这个脚本,这问题一直存在

执行脚本会出现异常,经过分析这是因为BPF的验证器没有判断出来数据长度是不是合法的

2022-06-26T15:59:18.png

简言之就是图里的buf_copy_size在BPF验证器看来是不确定的,可能会超过限制的大小,到时候可能导致内核异常,所以提醒异常,无法通过检查

2022-06-26T16:01:20.png

这里将它改为一个定值,再运行就可以了

2022-06-26T16:03:10.png

然后操作下APP触发下https请求,可以看到有日志了

2022-06-26T16:03:41.png

但是没有打印出来具体数据是什么,给SSL_exit添加一行代码,打印下信息

bpf_trace_printk("[bpf_probe_read_user] ret:%d len:%d\\n", ret, len);

2022-06-26T16:08:46.png

进入adb shell并切换到root用户,打开trace记录开关,读取trace_pipe

echo 1 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace_pipe

不需要了记得关闭trace输出,因为这个还是有性能影响的,不用的时候还是关闭。不过放心,如果关机重启,会自动重置的

echo 0 > /sys/kernel/debug/tracing/tracing_on

输出结果如下

2022-06-26T16:08:16.png

可以看到返回结果是负数,但是数据长度是能打印出来的,这是因为数据长度获取是eBPF程序函数被调用的时候,通过上下文拿到的

而要读出数据内容,通过上下文拿到的是数据的地址,本来是可以通过bpf_probe_read_user读取的,但是这个函数的补丁是5.5及之后的内核才有的,所以这里读取失败了~

通过这个例子,可以看出4.x系列的手机,默认情况下,eBPF程序能做到的还是比较有限

综合看,如果想要有良好的bcc体验,要么采用高版本内核的手机,要么自行编译内核并开启相关的选项

建议,自行开启需要的内核选项,并打上bpf_probe_read_user的补丁,编译内核刷机,后续会单独出一篇文章记录下

也就是这三项搞定后,也能在4.x系列上实现无感抓包,无感hook~

  • 开启CONFIG_KPROBES
  • 开启CONFIG_IKHEADERS
  • bpf_probe_read_user补丁

补充

前面的内容中没有提到出现下面的错误怎么办

Unable to find kernel headers. Try rebuilding kernel with CONFIG_IKHEADERS=m (module)

经过实践,如果确实不想改动内核,那么是可以通过BCC_KERNEL_SOURCE环境变量指定内核源代码目录,然后正常运行的

不过安卓手机的内核源代码的文件结构不太一样,可以参考内核源码中的kernel_headers.py脚本梳理文件关系

然后把头文件弄到一起就好了,可以先建立一个目录然后设定环境变量export BCC_KERNEL_SOURCE=/kk

再执行脚本,这个时候会提示缺少什么头文件,然后就去手机的内核源代码找,然后弄到手机上debian下的这个文件夹里面,最后也是能用的,就是麻烦点

参考