Loadable Kernel Module for bullhead
· 5 min read
1. Evironment
bullhead, aka LG Nexus 5XAndroid Version : 8.1.0 OreoKernel Version : 3.10.73-g25966c546824Build Number : OPM5.171019.015
2. kernel Source
hacker:~# git clone https://github.com/xiphiasilver/bullhead.git kernel
3. Prebuilt Toolchain
당연하게도 컴파일러의 버전에 상당히 영향을 받는다.
hacker:~# git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 -b oreo-r6-release --single-branch
4. Kernel Build
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의 설정과 관련해서는 아래 링크를 참고하자.
Enable loadable module support를 설정하고, restrict kernel memory permissions as much as possible을 해제한다.
armeabi 아키텍처, 즉 32비트에서는 zImage 파일이 생성된다. 아래 링크를 참고하자.
5. Building Tool, mkbootimg
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 ../
이 링크를 참고했다.
6. Making Boot Image(boot.img)
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)에서 추출한 원본 이미지이다.
7. Testing Built Kernel
hacker:~/tools/repack# adb reboot fastboot
hacker:~/tools/repack# adb reboot bootloader
hacker:~/tools/repack# fastboot boot new_boot.img
정상적으로 부팅된다면, 플래시 메모리에 영구적으로 저장한다.
hacker:~/tools/repack# fastboot flash boot new_boot.img
컴파일된 커널이 정상적으로 부팅되지 않은 것은 mkbootimg가 원인인 경우도 있다고 한다.
8. Rooting
컴파일된 커널이 정상적으로 부팅되면, 안드로이드 디바이스를 루팅한다.
9. LKM Build
hello.c
#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");
Makefile
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
hacker:~/kernel/drive/hello# make
10. Signing Modules
insmod: failed to load /data/local/tmp/hello.ko: Required key not available
hacker:~/kernel# ./scripts/sign-file sha512 ./signing_key.priv ./signing_key.x509 drivers/hello/hello.ko drivers/hello/hello-signed.ko
커널 빌드할 때 CONFIG_MODULE_SIG 설정을 해제하면, 이 과정은 불필요하다.
11. Modules Execution
bullhead:/data/local/tmp# insmod hello-signed.ko
아래와 같은 에러가 발생한다면, make menuconfig에서 LKM Support를 설정하여 다시 컴파일해야 한다.
insmod: failed to load /data/local/tmp/hello.ko: Function not implemented
12. Check Running
bullhead:/data/local/tmp# dmesg -wT
...
[ 1652.944291] Hello World
...
로그는 cat /proc/kmsg로도 확인할 수 있다.
13. References
- https://github.com/julius-b/android-lkm
- https://mobile-security.gitbook.io/mobile-security-testing-guide/android-testing-guide/0x05c-reverse-engineering-and-tampering
- https://zhuanlan.kanxue.com/article-4374.htm
- http://gooddexamples.blogspot.com/2017/12/how-to-build-kernel-for-nexus5x.html
- https://dayntimes.tistory.com/1278
- https://xiphiasilver.net/2019/07/18/android-rooting-from-a-to-z/
- https://stackoverflow.com/questions/37317906/error-building-android-kernel-multiple-target-patterns
- https://stackoverflow.com/questions/35691830/arm64-image-to-zimage-or-boot-img
- https://www.hackerschool.org/Sub_Html/HS_Posting/?uid=41
- https://stackoverflow.com/questions/20836536/why-do-i-get-a-zero-android-kernel-address