Skip to main content

Loadable Kernel Module for bullhead

· 5 min read

1. Evironment

  • bullhead, aka LG Nexus 5X
  • Android Version : 8.1.0 Oreo
  • Kernel Version : 3.10.73-g25966c546824
  • Build 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