这篇文章上次修改于 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
后面再安装包的时候就不会出现了
使用apt命令可能会提示说无法解析域名
经过查阅资料解决方案是修改/etc/passwd
的_apt
的65534
为3003
,这个时候可以用vi
编辑
如果想在手机上通过文件管理器修改,那么请注意路径是/data/eadb/debian/etc/passwd
/data/eadb/debian
是rootfs
的根目录
详情请查阅
为了加快后面下载代码的速度,这里也配置下proxychains4
nano /etc/proxychains4.conf
编译并安装bcc
同步维术大佬修改好的bcc代码
proxychains -q git clone https://github.com/tiann/bcc.git
由于后面还会同步其他项目的代码文件,所以这里第一次cmake
也挂了代理
cd bcc
mkdir build && cd build
proxychains -q cmake ..
LuaJIT和netperf这个可以暂时不管
然后开始编译bcc,成功之后安装
make -j8
make install
vscode远程连接与ssh配置
在体验bcc之前我们先配置下ssh,方便vscode连接修改代码
nano /etc/ssh/sshd_config
重启ssh服务,(手机每次重启后的第一次进入debian环境,可能都需要手动启动下ssh服务)
service ssh restart
然后把vscode的ssh配置公钥写入到debian的~/.ssh/authorized_keys
mkdir ~/.ssh
cat id_rsa.pub >> ~/.ssh/authorized_keys
这个时候可以通过ssh连上了,电脑上vscode的ssh配置
通过Remote SSH连上后,还可以安装上python插件等等
对了这个环境里面没有pip,手动通过get-pip.py
安装上
proxychains -q wget https://bootstrap.pypa.io/get-pip.py
proxychains -q python get-pip.py
这手机俨然可以做一个开发环境了啊(不是)
体验bcc
现在来体验下bcc吧,先找个目标
切换到bcc/tools
下,示例如下,这个是用来统计指定库某个函数的调用情况,具体实现请查看stackcount.py脚本
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
如果指定为/system/lib64/libc.so
测试是没有效果的
具体的测试效果如下图,可以看到统计了调用次数和调用栈情况
不过看起来好像没有特别有用的信息,不过这个还需要自行编写脚本实现更强的效果~
小小总结
需要注意的是,如果手机是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();
因为这里后面用到了uid但是没有初始化...估计都没什么用人这个脚本,这问题一直存在
执行脚本会出现异常,经过分析这是因为BPF的验证器没有判断出来数据长度是不是合法的
简言之就是图里的buf_copy_size在BPF验证器看来是不确定的,可能会超过限制的大小,到时候可能导致内核异常,所以提醒异常,无法通过检查
这里将它改为一个定值,再运行就可以了
然后操作下APP触发下https请求,可以看到有日志了
但是没有打印出来具体数据是什么,给SSL_exit
添加一行代码,打印下信息
bpf_trace_printk("[bpf_probe_read_user] ret:%d len:%d\\n", ret, len);
进入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
输出结果如下
可以看到返回结果是负数,但是数据长度是能打印出来的,这是因为数据长度获取是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下的这个文件夹里面,最后也是能用的,就是麻烦点
参考
- https://evilpan.com/2022/01/03/kernel-tracing/
- https://github.com/iovisor/bcc/issues/3731
- https://github.com/iovisor/bcc/issues/3175
- https://askubuntu.com/questions/910865/apt-get-update-fails-on-chroot-ubuntu-16-04-on-android
- https://github.com/Magisk-Modules-Repo/ssh
- https://github.com/tiann/eadb
- https://docs.github.com/cn/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
已有 14 条评论
博主,我在使用adeb时运行sslsniff.py,出现一下错误是怎么回事呢
sslsniff.py: error: argument --extra-lib: Invalid library path: '/apex/com.android.conscrypt/lib64/libssl.so'
@H 说明你的手机上不存在这个路径,你可以看看目标进程的maps,确定下libssl.so的具体路径,/proc/{pid}/maps
@sfx 刚才查了一下我的路径是这样的,d68c3000-d68d4000 r--p 00000000 07:10 18 /apex/com.android.conscrypt/lib/libssl.so。但是替换之后依然找不到,不知道什么原因
@H 安卓上eBPF不支持32位类库
@sfx 博主,eBPF uprobe 为何不支持32bit lib?要怎么兼容呢?
@11vm 具体为什么我也说不清楚,我尝试过,但是遇到各种无解问题。你可以尝试下
@sfx 你是不是没有加 lib_type
大佬好,这个Unable to find kernel headers问题可以这样解,kheaders.ko位于源码编译的out目录下,find一下就找到了,然后push到debian目录,apt-get install kmod
insmod kheaders.ko就好了
参考链接 https://zhuanlan.zhihu.com/p/608890200
@智取棋 源码编译的out目录,这是哪里?
Hi 博主
在adeb的debian系统看不到apex,看你能访问到
/apex/com.android.runtime/lib64/bionic/libc.so我尝试用mount去挂载,挂不上
请教下,你是是怎么做到的
@paul 我用的是eadb,不是adeb https://github.com/tiann/eadb
大佬,我编译好bcc之后第二天发现手机里bcc目录居然没了
passwd 里本来就是 3003,还是没网
大佬,知道这是什么问题吗?我看有说是编译环境问题的,但是我编译过程都是成功的。
ImportError: dynamic module does not define module export function (PyInit_libbcc)