eBPF on Android之编译内核与打补丁(解决触摸和WIFI失效问题)
2022-11-8 17:59:15 Author: mp.weixin.qq.com(查看原文) 阅读量:15 收藏


本文为看雪论坛优秀文章

看雪论坛作者ID:seeeseee


前言

在之前的这篇文章中尝试了ptach内核,但是尝试开启CONFIG_KRETPROBES后出现了触摸和WIFI失效的情况。
  • eBPF on Android之打补丁和编译内核
https://blog.seeflower.dev/archives/139
后来和missking交流之后,发现文章中修改内核编译选项的操作是不标准的,具体可以参考下面的文章:
  • 修改Linux Kernel defconfig的标准方法
https://adtxl.com/index.php/archives/124.html
简单来说正确的步骤如下:
cd private/msm-google
进入内核源码目录。
make ARCH=arm64 floral_defconfig
生成floral_defconfig对应的.config配置文件;
这一步是基于arch/arm64/configs/floral_defconfig配置文件进行的生成。
make ARCH=arm64 menuconfig
打开内核编译配置的可视化界面。
make ARCH=arm64 savedefconfig
根据.config配置文件生成defconfig配置文件。
cp defconfig arch/arm64/configs/floral_defconfig
覆盖原有的floral_defconfig配置文件。
这里当然可以用mv命令。
rm .config
删除.config配置文件,不然编译时会提示你需要清理。
然而即使这样我编译出来的内核还是会导致触摸和WIFI失效,后来在参考了下面的几个帖子之后,把触摸修好了,但是WIFI始终没有修好。
刷自编译内核导致屏幕触控失灵的问题 Google pixel 4XL
https://www.akr-developers.com/d/440
Pixel3 Aosp自编译内核如何正确的驱动设备正常运行
https://www.akr-developers.com/d/526
求助:刷入内核后触摸屏失灵
https://www.akr-developers.com/d/469
实操篇- pixel 2 刷8.0.0/8.1.0 AOSP +4.4 Kernel (重点解决刷完触屏失灵问题)
https://bbs.pediy.com/thread-264295.htm
编译内核(Pixel 2)
https://bbs.pediy.com/thread-255846.htm
android内核编译问题,多谢
https://bbs.pediy.com/thread-273148.htm
修好触摸主要参考第一个帖子第四楼
https://www.akr-developers.com/d/440/4
先在.repo/manifests/default.xml里面进行配置fts_touch这些。
但是发现这些驱动代码目录不对,然后用git submodule命令去把代码同步过去、或者手动复制。
在一系列操作之后,终于触摸能用了,后面接着看了下怎么修WIFI,但是涉及的内容实在是太多了,就暂时搁置没有再研究了。
也正是这一番操作,我注意到build/build.sh还有个设定是BUILD_BOOT_IMG,也就是单独编译内核的时候,是可以构建出boot.img的。
网上没有找到关于BUILD_BOOT_IMG这个选项的用法,虽然脚本中有说明,但是当时已经是筋疲力尽,对于里面提到的GKI_RAMDISK_PREBUILT_BINARY和VENDOR_RAMDISK_BINARY更是一头雾水。
最近假期又有点时间了,于是认真看了脚本说明和逻辑,结合boot.img解包的信息,终于搞清楚单独编译内核且触摸和WIFI都正常的正确姿势了。
操作其实很简单,不需要大改特改。
本文将就正确单独编译安卓内核和给内核打bpf_probe_read_user补丁进行详细指南。
博客中以下两篇文章步骤或多或少存在问题,请勿参考,以本文为准。
eBPF on Android之打补丁和编译内核(https://blog.seeflower.dev/archives/139/
android-msm-crosshatch-4.9-pie-qpr2内核编译记录(https://blog.seeflower.dev/archives/17/


环境

仅供参考
  • Pixel 4XL
  • coral-tp1a.220905.004 最新版系统,Android 13
  • Linux localhost 4.14.276-ge333cb8619d0-ab8811257 #1 SMP PREEMPT Fri Jul 8 12:00:53 UTC 2022 aarch64 Toybox
  • Ubuntu 20.04


步骤

该使用代理连接的时候请自行加代理。

准备环境和同步代码

https://source.android.com/setup/build/initializing

首先根据官方指南安装必要库和软件。
sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig
创建一个工作目录,后面的文件都会放这下面。
mkdir ~/Desktop/p4xlexport WORK_DIR=~/Desktop/p4xlcd ${WORK_DIR}
https://source.android.com/setup/build/building-kernels
根据官方的说明,我这里选择Pixel 4XL对应的分支android-msm-coral-4.14-android13。
为了能对应上手机的内核版本,这里没有加上--depth=1,后面需要checkout。
repo init -u https://android.googlesource.com/kernel/manifest -b android-msm-coral-4.14-android13repo sync
repo不会设置?请参考:
https://lug.ustc.edu.cn/wiki/mirrors/help/aosp/
最新版的内核编译脚本会使用自带的编译工具,不需要自己设置clang环境变量。
如果你同步的内核源代码没有编译工具,需要自己手动同步一下,如下:
cd prebuiltsgit clone https://android.googlesource.com/kernel/prebuilts/build-toolsmv build-tools kernel-build-toolsexport PATH=${WORK_DIR}/prebuilts/kernel-build-tools/linux-x86/bin:$PATH
代码同步好之后,进入private/msm-google文件夹,通过下面的命令切换到和手机内核版本一致的commit。
我的内核版本是4.14.276-ge333cb8619d0-ab8811257,那么对应的commit id就是e333cb8619d0。
git checkout e333cb8619d0

修改编译脚本和准备文件

脚本分析

如果对这个部分不感兴趣,请直接查看脚本修改小节。
首先将手机当前的boot.img用Android-Image-Kitchen解包,会得到一堆文件,终端会给出这些信息:
ANDROID! magic found at: 0BOARD_KERNEL_CMDLINE console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 androidboot.memcg=1 cgroup.memory=nokmem usbcore.autosuspend=7 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 androidboot.boot_devices=soc/1d84000.ufshc loop.max_part=7 buildvariant=userBOARD_KERNEL_BASE 0x00000000BOARD_NAMEBOARD_PAGE_SIZE 4096BOARD_HASH_TYPE sha1BOARD_KERNEL_OFFSET 0x00008000BOARD_RAMDISK_OFFSET 0x01000000BOARD_SECOND_OFFSET 0x00000000BOARD_TAGS_OFFSET 0x00000100BOARD_OS_VERSION 13.0.0BOARD_OS_PATCH_LEVEL 2022-09BOARD_HEADER_VERSION 2BOARD_HEADER_SIZE 1660BOARD_DTB_SIZE 1048284BOARD_DTB_OFFSET 0x01f00000
在build/build.sh中查找BUILD_BOOT_IMG,在脚本末尾的代码如下:
对代码阅读后可知:当BOOT_IMAGE_HEADER_VERSION为3的时候才会检查GKI_RAMDISK_PREBUILT_BINARY和KERNEL_VENDOR_CMDLINE。
但是解包的结果中可以看到BOARD_HEADER_VERSION是2。
脚本的帮助信息中说,如果BOOT_IMAGE_HEADER_VERSION值小于3,那么还需要指定BASE_ADDRESS和PAGE_SIZE。
这两个选项的值其实就是解包信息中的BOARD_KERNEL_BASE和BOARD_PAGE_SIZE。
解包信息中的BOARD_KERNEL_CMDLINE则就是KERNEL_CMDLINE。
KERNEL_BINARY的值直接说了是Image.lz4或者Image.gz,我们知道编译产物中有Image.lz4,所以指定为Image.lz4。
MKBOOTIMG_PATH默认是tools/mkbootimg/mkbootimg.py,但是我发现同步下来的代码并没有这个脚本,这个我们去AOSP之类的代码中找一个就行了,比如:
http://aospxref.com/android-11.0.0_r21/xref/system/tools/mkbootimg/mkbootimg.py
或者直接同步下官方的代码。
git clone https://android.googlesource.com/platform/system/tools/mkbootimg
我这里直接把脚本放在了${WORK_DIR},也就是整个代码的根目录下面。
那么问题来了,VENDOR_RAMDISK_BINARY应该是什么呢,哪里找,脚本里面的说明如下:
Name of the vendor ramdisk binary which includes the device-specific components of ramdisk like the fstab file and the device-specific rc files.
最开始我也是迷糊的,boot.img解包出来的文件有一个是boot.img-ramdisk.cpio.gz。
看build/build.sh的逻辑是要和initramfs.cpio甚至GKI_RAMDISK_PREBUILT_BINARY一起打包。
那么解包出来的boot.img-ramdisk.cpio.gz是需要更新内容吗,还是接着用呢?
在此之前的经验告诉我,肯定不是直接接着用解包出来的boot.img-ramdisk.cpio.gz。
注意到BUILD_INITRAMFS的描述是if defined, build a ramdisk containing all .ko files and resulting depmod artifacts。
就是说会打包出一个ramdisk包含所有.ko也就是驱动模块文件。
虽然之前编译的时候没有定义这个,但是产物确实有initramfs.img。
发现原来是private/msm-google/build.config.common文件中设置了:
而脚本中也确实是这样,可以看到中途会产生initramfs.cpio。
而initramfs.cpio正好是和VENDOR_RAMDISK_BINARY一起打包的,也就是说VENDOR_RAMDISK_BINARY应该是.cpio文件。
boot.img-ramdisk.cpio.gz解压确实会有一个boot.img-ramdisk.cpio文件。
那么将VENDOR_RAMDISK_BINARY指定为解压的boot.img-ramdisk.cpio,然后和initramfs.cpio打包,那不就会把所有驱动都带上了吗,触摸什么的应该都会正常吧。
经过实践,确实是这样。

脚本修改

需要注意的是脚本操作VENDOR_RAMDISK_BINARY的时候,操作的是${DIST_DIR}下面的文件。
我们需要在脚本中把解压的boot.img-ramdisk.cpio复制到${DIST_DIR}。于是在build/build.sh中echo " Files copied to ${DIST_DIR}"之前加上复制命令。
if [ -f "${VENDOR_RAMDISK_BINARY}" ]; then  cp ${VENDOR_RAMDISK_BINARY} ${DIST_DIR}fi

准备文件

将手机当前的boot.img用Android-Image-Kitchen解包。

将解包出来的boot.img-ramdisk.cpio.gz解压,得到boot.img-ramdisk.cpio,放在${WORK_DIR},也就是整个代码的根目录下面。

同步官方的代码或者直接下载mkbootimg.py,同样放到${WORK_DIR},也就是整个代码的根目录下面。

git clone https://android.googlesource.com/platform/system/tools/mkbootimg

编译命令

做完上面的准备后,结合解包的信息,正常情况下使用下面的命令就能编译生成boot.img。
BUILD_CONFIG=private/msm-google/build.config.floral BUILD_BOOT_IMG=1 MKBOOTIMG_PATH=mkbootimg.py VENDOR_RAMDISK_BINARY=boot.img-ramdisk.cpio KERNEL_BINARY=Image.lz4 BOOT_IMAGE_HEADER_VERSION=2 KERNEL_CMDLINE="console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 androidboot.memcg=1 cgroup.memory=nokmem usbcore.autosuspend=7 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 androidboot.boot_devices=soc/1d84000.ufshc loop.max_part=7 buildvariant=user" BASE_ADDRESS=0x00000000 PAGE_SIZE=4096 build/build.sh
注意:KERNEL_CMDLINE BASE_ADDRESS PAGE_SIZE请从解包的内核信息中获取。

添加bpf_probe_read_user

根据bcc的issue:bpf_probe_read_user returns error (-14) on Android 11, Kernel 4.14, ARM64
https://github.com/iovisor/bcc/issues/3175#issuecomment-730949741
要添加读取用户空间数据的功能,可以参考下面这个补丁。
https://lkml.org/lkml/diff/2019/5/2/1100/1
这里没有几行,我手动找到对应的代码位置,添加了代码。
private/msm-google/include/uapi/linux/bpf.h
private/msm-google/kernel/trace/bpf_trace.c
private/msm-google/tools/include/uapi/linux/bpf.h
注意原patch中有两处FN(probe_read_user),,但是我截图没有,这是因为我这个版本的源代码已经有这个了。
主要是缺少BPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size, const void *, unsafe_ptr)函数。
请打补丁的时候仔细确定,看好了再修改,否则编译会出问题,提示重定义什么的。
还有更多的bpf帮助函数需要patch?可以参考bcc给出的相关函数的commit列表,不过还是参考下安卓的补丁写法比较好。
https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#helpers
这里针对的是我的Pixel 4XL的做法,4.9这些内核也可以打补丁,但是需要自己参考一些新一点的内核源码做patch。

修改内核编译配置并编译

修改内核编译配置

首先进入内核源码目录
cd private/msm-google
生成floral_defconfig对应的.config配置文件,这一步是基于arch/arm64/configs/floral_defconfig配置文件进行的生成。
make ARCH=arm64 floral_defconfig
打开内核编译配置的可视化界面。
make ARCH=arm64 menuconfig
如图所示,这里按空格键可以切换选项选中状态。
按/可以进行搜索,这样可以知道一些选项在哪里,以及选项的限制条件等等。
比如这里CONFIG_KRETPROBES是多个条件共同决定的,只要这些条件均为y那么CONFIG_KRETPROBES自然会变成y。
而图中后面的SAMPLE_KRETPROBES会多出一个Location指示,这一种除了子条件要通过,同时需要到对应的子菜单修改选中状态。
修改选项状态之后,按TAB键可以切换底部的选项,先选择Save保存.config文件,然后选择Exit退出编辑。
然后根据.config配置文件生成defconfig配置文件的命令如下,注意这里生成的defconfig是精简的,有些选项你可能明明设置了但是里面没有。
实际上在编译的时候会生成完整的版本,不用担心,如果说编译阶段(out文件夹下)生成的.config文件没有你之前设置的,那么可能有选项冲突了。
make ARCH=arm64 savedefconfig
覆盖原有的floral_defconfig配置文件。
cp defconfig arch/arm64/configs/floral_defconfig
删除.config配置文件,不然编译时会提示你需要清理。
rm .config
至此完成了内核编译配置的修改,可以开始正式编译了。

正式编译

如果你有编译过内核的经验,会发现自己编译出来的内核版本有+或者dirty这些内容。
如果你想去掉这些,那么请先把相关代码的修改添加commit,就可以避免这个问题。
编译命令如下:
BUILD_CONFIG=private/msm-google/build.config.floral BUILD_BOOT_IMG=1 MKBOOTIMG_PATH=mkbootimg.py VENDOR_RAMDISK_BINARY=boot.img-ramdisk.cpio KERNEL_BINARY=Image.lz4 BOOT_IMAGE_HEADER_VERSION=2 KERNEL_CMDLINE="console=ttyMSM0,115200n8 androidboot.console=ttyMSM0 printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 service_locator.enable=1 androidboot.memcg=1 cgroup.memory=nokmem usbcore.autosuspend=7 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 androidboot.boot_devices=soc/1d84000.ufshc loop.max_part=7 buildvariant=user" BASE_ADDRESS=0x00000000 PAGE_SIZE=4096 build/build.sh
可以看到boot.img正常生成了。
可以发现会比之前仅用Image.lz4-dtb替换boot.img-kernel后使用Android-Image-Kitchen重打包得到的产物明显大不少。
经过验证,这样编译打包出来的boot.img刷机后可以正常开机、触摸和WIFI均正常,用Magisk打补丁后也能正常使用。
相关eBPF设定开启情况
内核符号情况


总结

在之前的文章中,我认为内核编译可能会遭遇各种问题,以至于通过修改并重新编译内核在4.x系列的手机上可能过于折腾。
但是在达成了不需要完整AOSP环境,直接编译内核生成正常可用的boot.img的目的之后,eBPF在安卓上的可玩性又好了很多。
最后再次汇总下整个操作步骤:

使用Android-Image-Kitchen解包手机当前的boot.img

从boot.img-ramdisk.cpio.gz解压得到boot.img-ramdisk.cpio

下载mkbootimg.py

修改build/build.sh,作用是将boot.img-ramdisk.cpio复制到产物目录下,参与后续打包

同步内核源代码

把boot.img-ramdisk.cpio和mkbootimg.py均放到内核项目根目录

修改内核编译配置,注意指定架构

cd private/msm-google

make ARCH=arm64 floral_defconfig

make ARCH=arm64 menuconfig

make ARCH=arm64 savedefconfig

cp defconfig arch/arm64/configs/floral_defconfig

rm .config

cd ../../

根据原始boot.img解包信息修改好编译命令

BUILD_CONFIG=private/msm-google/build.config.floral BUILD_BOOT_IMG=1 MKBOOTIMG_PATH=mkbootimg.py VENDOR_RAMDISK_BINARY=boot.img-ramdisk.cpio KERNEL_BINARY=Image.lz4 BOOT_IMAGE_HEADER_VERSION=2 KERNEL_CMDLINE="..." BASE_ADDRESS=0x00000000 PAGE_SIZE=4096 build/build.sh

完成编译,得到修改了内核选项的、可正常使用的boot.img

https://github.com/iovisor/bcc/issues/3175#issuecomment-730949741

看雪ID:seeeseee

https://bbs.pediy.com/user-home-941366.htm

*本文由看雪论坛 seeeseee 原创,转载请注明来自看雪社区

看雪CTF官网:https://ctf.pediy.com/

# 往期推荐

1.CVE-2022-21882提权漏洞学习笔记

2.wibu证书 - 初探

3.win10 1909逆向之APIC中断和实验

4.EMET下EAF机制分析以及模拟实现

5.sql注入学习分享

6.V8 Array.prototype.concat函数出现过的issues和他们的POC们

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458482837&idx=1&sn=e9f8fdb506ac7bf40c34fc866b4a4cfe&chksm=b18e481f86f9c109c03412ece8afa950b302d53518d0fa5f18aedcbac0cb28ad7f84aba836a2#rd
如有侵权请联系:admin#unsafe.sh