点击蓝字 关注我们
PART 01
前言
在进行Android 系统安全分析的过程中,或对Android kernel研究的时候,可能需要会编译内核,甚至救砖。
PART 02
Build Kernel for pixel 5
首先来说明一下pixel5的内核编译,由于之前编译过pixel6 Kernel,因此以为编译的过程中两者的区别并不大,但是没想到pixel5 编译的坑很多,因此这一章节会讲述一下编译的时候遇到的一些问题和各种错误,还有有关GKI 在pixel 5 内核和pixel6 内核编译的一些不同。
在编译内核之前先去官网获取原厂镜相包,刷成砖后及时恢复:https://developers.google.cn/android/images?hl=zh-cn#redfin
首先拉取android-msm-redbull-4.19-android11-qpr2 分支的代码,然后根据自己手机的分支CommitID 进行checkout,然后开始编译出kernel,编译出来的内容在out/android-msm-pixel-4.19/dist 中。在这里编译内核已经完成了。
1. repo init -u https://android.googlesource.com/kernel/manifest -b android-msmredbull-
4.19-android11-qpr2
2. repo sync
3. cd /private/msm-google/ ; git checkout 9ceb3bf92e0a
4. ./build_redbull.sh
拉取AOSP的 android-11.0.0_r34分支的代码,这里记得下载extract-google_devices-redfin.sh 文件,以获取设备厂商的驱动。然后编译出全量的刷机镜像,刷入到手机,确保编译出来的AOSP在pixel5中能够正常lunch。
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# repo init -u
https://android.googlesource.com/platform/manifest -b android-11.0.0_r34
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# repo sync
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# chmod 777 extractgoogle_
devices-redfin.sh
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# ./extract-google_devicesredfin.
sh
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# chmod -R 777 vendor/
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# source build/envsetup.sh
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# lunch // 选择aosp_redfinuserdebug
root@4cd0e87f2387:~/aosp/pixel5_android-11.0.0_r34# make
// 能刷入到手机内
E:2__filepixel52__aosp编译android-11.0.0_r34>set ANDROID_PRODUCT_OUT=./
E:2__filepixel52__aosp编译android-11.0.0_r34>fastboot flashall -w
E:2__filepixel52__aosp编译android-11.0.0_r34 的目录
2024/06/19 15:57 <DIR> .
2024/06/19 15:57 <DIR> ..
2024/06/19 15:57 22 android-info.txt
2024/06/19 15:52 26,533,888 boot-debug.img
2024/06/19 15:52 100,663,296 boot.img
2024/06/19 15:51 9,103,752 bootloader.img
2024/06/19 15:51 335,787 dtb.img
2024/06/19 15:51 16,777,216 dtbo.img
2024/06/19 15:51 239,603,860 product.img
2024/06/19 15:50 137,891,980 radio.img
2024/06/19 15:50 14,426,115 ramdisk-debug.img
2024/06/19 15:50 14,252,291 ramdisk-recovery.img
2024/06/19 15:50 940,919 ramdisk.img
2024/06/19 15:50 4,976 super_empty.img
2024/06/19 15:50 880,324,888 system.img
2024/06/19 15:47 107,098,236 system_ext.img
2024/06/19 15:47 24,416,368 system_other.img
2024/06/19 15:47 2,785,604 userdata.img
2024/06/19 15:47 8,192 vbmeta.img
2024/06/19 15:47 4,096 vbmeta_system.img
2024/06/19 15:47 8,566,493 vendor-ramdisk-debug.cpio.lz4
2024/06/19 15:47 706,507,008 vendor.img
2024/06/19 15:45 8,908,800 vendor_boot-debug.img
2024/06/19 15:45 100,663,296 vendor_boot.img
22 个文件 2,399,817,083 字节
2 个目录 77,827,821,568 可用字节
Linux localhost 4.19.135-g3fdbc8e39c0d-ab7132628 #1 SMP PREEMPT Mon Feb 8
18:40:22 UTC 2021 aarch64
aosp_redfin-userdebug 11 RQ2A.210405.005
到这里,就可以开始将自己编译的 kernel 产出物 整合到AOSP 代码中进行整体编译。
把android-msm-redbull-4.19-android11-qpr2 中out 内的一些文件都拷贝到aosp/device/google/redbull-kernel 内,具体的内容如下:
cd /root/aosp/android-msm-redbull-4.19-android11-qpr2/out/android-msm-pixel-
4.19/dist
cp /root/aosp/android-msm-redbull-4.19-android11-qpr2/out/android-msm-pixel-
4.19/dist/*.ko /root/aosp/pixel5_android-11.0.0_r34/device/google/redbullkernel/
cp /root/aosp/android-msm-redbull-4.19-android11-qpr2/out/android-msm-pixel-
4.19/dist/Image.lz4 /root/aosp/pixel5_android-11.0.0_r34/device/google/redbullkernel/
cp /root/aosp/android-msm-redbull-4.19-android11-qpr2/out/android-msm-pixel-
4.19/dist/Image.lz4-dtb /root/aosp/pixel5_android-
11.0.0_r34/device/google/redbull-kernel/
cp /root/aosp/android-msm-redbull-4.19-android11-qpr2/out/android-msm-pixel-
4.19/dist/kernel-uapi-headers.tar.gz /root/aosp/pixel5_android-
11.0.0_r34/device/google/redbull-kernel/
cp /root/aosp/android-msm-redbull-4.19-android11-qpr2/out/android-msm-pixel-
4.19/dist/kernel-headers.tar.gz /root/aosp/pixel5_android-
11.0.0_r34/device/google/redbull-kernel/
然后重新编AOSP:
将 kenrel/out 内的 vendor_boot.img 和 aosp /out 内的boot.img 这两个文件分别刷入到手机中,内核就成功刷入了。
为了测试custom kernel 编译成功,可以在kernel 代码中加入一些调试输出,比如在binder.c 内加入printk 的信息。
设备启动的时候就可以看到输出打印信息了。
在更改内核kernel代码之后,重新编译刷入,内核版本信息中会带有 _dirty ,可能会影响一些应用,只需要在源码目录中git commit 即可。
以上是一次完整的pixel 5 内核编译的过程,这里来解释一下为什么pixel5 编译的时候需要和aosp 整合编译,按照我的理解,由于android在推出GKI 之后,GKI 通过统一核心内核,把其他功能,如SOC,ODM 等提供的,从内核剥离并提供稳定接口KMI,一举解决了碎片化问题,并且Google 强制要求,Android12 以上版本的设备,出厂必须使用GKI内核。所以可能只有遵循GKI的设备内核才能单独编译,比如pixel6, 但pixel 5 很遗憾是非GKI 支持的设备。
但如果仍然要编译 Android12 以上版本的 kernel, 也是有办法的,请看下面的内容(踩坑记录):
将手机的系统刷入官方的android12出厂映像,拉取并同步锁android12的源码。
repo init -u https://android.googlesource.com/kernel/manifest -b android-msmredbull-
4.19-android12 & repo sync
编译后会获得boot.img,当我尝试使用“fastboot boot boot.img”命令启动 boot.img 时,立即被重定向回引导加载程序 ( bootloader )。我怀疑这可能是编译出来的boot.img 跟原厂的boot.img 有很大的不同。
为了辨别为什么编译的kernel 刷入手机内会立即重定向到bootloader,于是使用https://forum.xdadevelopers.com/attachments/android-image-kitchen-v3-8-win32-zip.5300919/ 对boot.img 进行解包。
将原厂可用的boot.img 和编译出来的boot.img 进行对比,两者的区别很明显。
这里看到了lleavesg 的博客 https://blog.lleavesg.top/article/pixel5-kernel-build#a92b6fd699a341a5a08d008a31ccf167 里面的思路,将原厂的ramdisk 解包出来后,放到目录中。
然后修改 build.sh ,再次编译出boot.img,刷入后依旧重定向到bootloder。前面说过官方对Android12之后做了一些更改,着直接导致了android12 原厂包中的boot 移除了ramdisk,所以只能从Android11中提取,这里跟lleavesg 沟通之后,他已经将blog 补上了说明。
PART 03
Build LineageOS for pixel6
LineageOS 是一个基于 Android 的开源操作系统,以其高度的定制性、安全性和隐私保护而闻名。它起源于著名的 CyanogenMod 项目,并在 2016 年重组后继续发展,目前已经成为拥有庞大用户群和活跃开发者社区的开源项目。本节的内容是关于给pixel6 编译LineageOS,在参照lineageOS 官网的编译流程 https://wiki.lineageos.org/devices/raven/build/ 并不能很顺利的编译,会碰各种各样的错误。
首先按照lineageOS 官网build 文档搭建对应的环境,比如所需的python 环境,Java 环境等,还有一些依赖库,这里要注意的是python 必须是3.8 版本,不然在执行breakfast 会报错。
apt install bc bison build-essential ccache curl flex g++-multilib gcc-multilib
git git-lfs gnupg gperf imagemagick lib32readline-dev lib32z1-dev libelf-dev
liblz4-tool libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync
schedtool squashfs-tools xsltproc zip zlib1g-dev
apt install lib32ncurses5-dev libncurses5 libncurses5-dev
apt install libwxgtk3.0-dev
然后同步源码,之后拉取要编译设备的配置文件和内核文件。
repo init -u https://github.com/LineageOS/android.git -b lineage-21.0 --git-lfs
repo sync
source build/envsetup.sh
breakfast raven // 指定设备代号,拉取对应的配置文件和内核文件。
这里在执行breakfast 的时候,会出现vendor/google/raven/raven-vendor.mk does not exit…错误。
这是由于没有vendor blob 的原因,在官方文档中有说明这一点:
其实如果把lineageOS不同设备的编译文档都看一遍,lineageOs 对于不同的设备来说,其实基础源码库都是相同的,不同的点在于下载vender device 对应的vendor 代码。要解决breakfast 的问题,需要从lineageOS 设备中提取专有的blob,官方的解决办法如下:https://wiki.lineageos.org/extracting_blobs_from_zips , 官网中提供了三种办法来提取专有的blob,我尝试了重lineageOS 安装包中提,编译的过程中会出现很多的错误,虽然不断修正错误,但依旧于事无补。
在这里找到了直接同步设备vendor的办法:https://gist.github.com/fourkbomb/261ced58cd029c5f7742350aafdd9825。从 https://github.com/TheMuppets/manifests/blob/lineage-21.0/muppets.xml 获取到raven/vendor,然后加入到 .repo/local_manifests/roomservice.xml。
重新同步一下代码 repo sync。
现在执行breakfast raven。
解决完 vendor blob 的问题后,基本上编译不会出其他的问题了,编译一路畅通。
croot
brunch raven
最后将编译出来的产物直接刷入到设备中即可。
我还尝试将pixel 6P 编译出来的Kernelsu 镜像单独刷入到LineageOS 中,系统没有出现其他的异常,可能得益于GKI,android官方的boot.img 和 lineageOS 编译出来的boot.img 是通用的。
这里需要说明一下,GKI(通用内核)推出后,部分设备的内核和Android的源码库可以分离、单独编译内核和系统。不过Lineage还是放一起的,比如在pixel 6P 中,内核和系统源码已经分离了,在pixel5中内核代码和系统源码还是在一起的,对pixel 内核有定制化需求的可以直接使用lineageOS。
PART 04
motorola 通过9008救砖
常在河边走,哪有不湿鞋,在一次对Motorola 设备进行操作的时候,导致设备处于硬砖状态,bootloader 损坏,这种情况下,将无法再访问Fastboot模式,手机无法正常开机,解硬砖就需要进入深度刷机的模式,配合高通的9008端口模式,进而恢复设备的bootloader。
通过9008救砖需要制作一根工程线,淘宝有的买,但是制作一根也不难,直接将一根具备数据传输功能充电线表皮剥开,你会看到四根线,如果只有红黑两根线,只有充电功能,其中绿色和黑色的线分别是火线和零线,用小刀轻轻的将这两根线的表皮刮下来露出其中的铜丝,一定不要过于用力然后直接切断了。
将绿色的线和黑色的线短接后,插入到设备中,大概5秒钟,就可以看到9008端口。
下载对应的blankflash:https://mirrors.lolinet.com/firmware/lenomola/2021/pstar_retcn/blankflash/
现在同时按住音量- 和电源按钮,并在同时按住的时候启动 blank-flash.bat。
之后手机就会自动开启到 bootloader 界面。
下载完整的系统固件XT2153-1_PSTAR_CMCC_11_RRAA31.Q3-19-86_subsidy-DEFAULT_regulatory-DEFAULT_CFC.xml.zip。
解开zip 包后,可以看到很多的镜像。
由于固件包中没有 flash-all.bat 文件,所以要留意一些XML文件,类似于 flashfile.xml、servicefile.xml 文件,打开其中的一个flashfile.xml 文件,可以理解到这里的一些含义,将不同的固件刷入到对应的分区中。
写了一个脚本提取要刷入的分区和镜像:
import xml.etree.ElementTree as ET
# 要解析的XML文件路径
xml_file = 'flashfile.xml'
# 解析XML文件并获取根元素
tree = ET.parse(xml_file)
root = tree.getroot()
# 确保根元素是<flashing>
if root.tag == 'flashing':
# 找到所有<step>元素
steps = root.findall('.//step')
for step in steps:
# 获取filename和partition属性
filename = step.get('filename')
partition = step.get('partition')
if filename and partition: # 确保属性存在
# 按照指定格式输出
print(f"fastboot flash {partition} {filename}")
else:
print("The XML file does not have the expected structure.")
提取出来后如下所示:
fastboot flash partition gpt.bin
fastboot flash bootloader bootloader.img
fastboot flash vbmeta vbmeta.img
fastboot flash vbmeta_system vbmeta_system.img
fastboot flash modem NON-HLOS.bin
fastboot flash fsg fsg.mbn
fastboot flash bluetooth BTFM.bin
fastboot flash dsp dspso.bin
fastboot flash logo logo.bin
fastboot flash boot boot.img
fastboot flash vendor_boot vendor_boot.img
fastboot flash dtbo dtbo.img
fastboot flash super super.img_sparsechunk.0
fastboot flash super super.img_sparsechunk.1
fastboot flash super super.img_sparsechunk.2
fastboot flash super super.img_sparsechunk.3
fastboot flash super super.img_sparsechunk.4
fastboot flash super super.img_sparsechunk.5
fastboot flash super super.img_sparsechunk.6
fastboot flash super super.img_sparsechunk.7
fastboot flash super super.img_sparsechunk.8
fastboot flash super super.img_sparsechunk.9
fastboot flash super super.img_sparsechunk.10
fastboot flash super super.img_sparsechunk.11
fastboot flash super super.img_sparsechunk.12
在刷入的时候,建议按照XML文件中提到的顺序来进行刷写,不然会还是会变成砖。
PART 05
总结
本文总结了为Pixel 5和Pixel 6编译内核时遇到的常见错误及解决方案,分析了GKI对内核编译的影响,并指出Pixel 5作为非GKI设备在编译中的特殊性和限制。同时,还简要介绍了利用9008端口恢复Android设备的方法,能够为开发者和用户提供实用的指导。
往期精彩合集
● 前后端分离架构下 利用SpringBoot确保接口安全性
● 联想全球安全实验室热招AI安全领域精英,欢迎志同道合的小伙伴加入!
● 联想全球安全实验室受邀参加XCon2024安全技术峰会,应“适者生存”的丛林法则,分享《近源渗透之攻守道》
● Web安全之SRI(Subresource Integrity子资源完整性)详解
● 联想GIC全球安全实验室受邀参加行业研讨会,分享红蓝对抗思想在产品安全中的应用
长
按
关
注
联想GIC全球安全实验室(中国)
原文始发于微信公众号(联想全球安全实验室):pixel5内核build、pixel6 LineageOS编译、motorola救砖