Loadable Kernel Module for bullhead
Contents
1. Environment
- bullhead, aka LG Nexus 5X
- Android Version : 8.1.0 Oreo
- Kernel Version : 3.10.73-g25966c546824
- Build Number : OPM5.171019.015
2. References
A. https://github.com/julius-b/android-lkm
B. https://mobile-security.gitbook.io/mobile-security-testing-guide/android-testing-guide/0x05c-reverse-engineering-and-tampering
C. https://zhuanlan.kanxue.com/article-4374.htm
D. http://gooddexamples.blogspot.com/2017/12/how-to-build-kernel-for-nexus5x.html
E. https://dayntimes.tistory.com/1278
F. https://xiphiasilver.net/2019/07/18/android-rooting-from-a-to-z/
G. https://stackoverflow.com/questions/37317906/error-building-android-kernel-multiple-target-patterns
H. https://stackoverflow.com/questions/35691830/arm64-image-to-zimage-or-boot-img
I. https://www.hackerschool.org/Sub_Html/HS_Posting/?uid=41
J. https://stackoverflow.com/questions/20836536/why-do-i-get-a-zero-android-kernel-address
3. Kernel Source
|
1 |
hacker:~# git clone https://github.com/xiphiasilver/bullhead.git kernel |
4. Prebuilt Toolchain
당연하게도 컴파일러의 버전에 상당히 영향을 받는다.
|
1 |
hacker:~# git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 -b oreo-r6-release --single-branch |
5. Kernel Build
|
1 2 3 4 5 6 7 8 9 10 |
hacker:~/kernel# export ARCH=arm64 hacker:~/kernel# export CCPATH=/root/aarch64-linux-android-4.9/bin hacker:~/kernel# export PATH=${CCPATH}:${PATH} hacker:~/kernel# export CROSS_COMPILE=aarch64-linux-android- hacker:~/kernel# make bullhead_defconfig hacker:~/kernel# make menuconfig // Setting to Loadable Module Support hacker:~/kernel# make hacker:~/kernel# cd ./arch/arm64/boot hacker:~/kernel/arch/arm64/boot# ls Image Image.gz Image.gz-dtb ... |
make menuconfig의 설정과 관련해서는 오른쪽 주석을 참고하자.1https://zhuanlan.kanxue.com/article-4374.htm
https://xiphiasilver.net/kernel-build-configuration-for-bullhead/
Enable loadable module support를 설정하고, restrict kernel memory permissions as much as possible을 해제한다.
armeabi 아키텍처, 즉 32비트에서는 zImage 파일이 생성된다.2https://stackoverflow.com/questions/35691830/arm64-image-to-zimage-or-boot-img
6. Building Tool, mkbootimg
|
1 2 3 4 5 6 7 8 9 |
hacker:~# git clone https://github.com/xiphiasilver/bootimg-tools.git tools hacker:~# cd tools/mkbootimg hacker:~/tools/mkbootimg# gcc -o unmkbootimg unmkbootimg.c hacker:~/tools/mkbootimg# cp unmkbootimg ../ & cd ../libmincrypt hacker:~/tools/libmincrypt# gcc -c *.c -I../include hacker:~/tools/libmincrypt# ar rcs libmincrypt.a *.o hacker:~/tools/libmincrypt# cd ../mkbootimg hacker:~/tools/mkbootimg# gcc mkbootimg.c -o mkbootimg -I../include ../libmincrypt/libmincrypt.a -std=c99 hacker:~/tools/mkbootimg# cp mkbootimg ../ |
2-D를 참고했다.
7. Making Boot Image(boot.img)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
hacker:~/tools/repack# ../unmkbootimg -i boot.img kernel written to 'kernel' (10827689 bytes) ramdisk written to 'ramdisk.cpio.gz' (1232520 bytes) To rebuild this boot image, you can use the command: mkbootimg --base 0 --pagesize 4096 --kernel_offset 0x00008000 --ramdisk_offset 0x02000000 --second_offset 0x00f00000 --tags_offset 0x01e00000 --cmdline 'console=ttyHSL0,115200,n8 androidboot.hardware=bullhead boot_cpus=0-5 lpm_levels.sleep_disabled=1 msm_poweroff.download_mode=0 loop.max_part=7 buildvariant=user' --kernel kernel --ramdisk ramdisk.cpio.gz -o boot.img hacker:~/tools/repack# ls -alh boot.img Image.gz-dtb kernel ramdisk.cpio.gz hacker:~/tools/repack# ../mkbootimg --base 0 --pagesize 4096 --kernel_offset 0x00008000 --ramdisk_offset 0x02000000 --second_offset 0x00f00000 --tags_offset 0x01e00000 --cmdline 'console=ttyHSL0,115200,n8 androidboot.hardware=bullhead boot_cpus=0-5 lpm_levels.sleep_disabled=1 msm_poweroff.download_mode=0 loop.max_part=7 buildvariant=user' --kernel Image.gz-dtb --ramdisk ramdisk.cpio.gz -o new_boot.img |
boot.img는 팩토리 이미지(bullhead-opm5.171019.015)에서 추출한 원본 이미지이다.
8. Testing Built Kernel
|
1 2 3 |
hacker:~/tools/repack# adb reboot fastboot hacker:~/tools/repack# adb reboot bootloader hacker:~/tools/repack# fastboot boot new_boot.img |
정상적으로 부팅된다면, 플래시 메모리에 영구적으로 저장한다.
|
1 |
hacker:~/tools/repack# fastboot flash boot new_boot.img |
컴파일된 커널이 정상적으로 부팅되지 않은 것은 mkbootimg가 원인인 경우도 있다고 한다. 3https://dayntimes.tistory.com/1278
이러한 경우의 수를 없애기 위해, 원본 이미지에서 추출한 파일만으로 부트 이미지를 만들어 먼저 시험해 보는 것이 좋다.
9. Rooting
컴파일된 커널이 정상적으로 부팅되면, 안드로이드 디바이스를 루팅한다.4https://xiphiasilver.net/bullhead-rooting-from-a-to-z/
10. LKM Build
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/syscalls.h> int __init my_init(void) { printk("Hello World\n"); return 0; } void __exit my_exit(void) { printk("Goodbye\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
obj-m += hello.o KERNEL_PATH := /root/kernel/ CCPATH := /root/aarch64-linux-android-4.9/bin/ CROSS_COMPILE := aarch64-linux-android- ARCH=arm64 SUBARCH=arm64 export PATH := ${CCPATH}:${PATH} #CFLAGS += -fPIC CFLAGS += -fno-pic all: make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_PATH) M=$(PWD) CFLAGS_MODULE=$(CFLAGS) modules -j$(nproc --all) clean: make -C $(KERNEL_PATH) M=$(PWD) clean |
|
1 |
hacker:~/kernel/drive/hello# make |
11. Signing Modules
|
1 |
insmod: failed to load /data/local/tmp/hello.ko: Required key not available |
|
1 |
hacker:~/kernel# ./scripts/sign-file sha512 ./signing_key.priv ./signing_key.x509 drivers/hello/hello.ko drivers/hello/hello-signed.ko |
커널 빌드할 때 CONFIG_MODULE_SIG 설정을 해제하면, 이 과정은 불필요하다.
12. Modules Execution
|
1 |
bullhead:/data/local/tmp# insmod hello-signed.ko |
아래와 같은 에러가 발생한다면, make menuconfig에서 LKM Support를 설정하여 다시 컴파일해야 한다.
|
1 |
insmod: failed to load /data/local/tmp/hello.ko: Function not implemented |
13. Check Running
|
1 2 3 4 |
bullhead:/data/local/tmp# dmesg -wT ... [ 1652.944291] Hello World ... |
로그는 cat /proc/kmsg로도 확인할 수 있다.