内核篇加载内核模块(Android10)
The following article is from 卓码星球 Author QDroid88888
一、 开发前期准备
本文中使用的是linageOs源码中下载的oneplus3 安卓10内核源码进行研究测试。交叉编译链使用的是linageOs源码中的交叉编译链。
lineageOs源码中oneplus3内核源码位置路径:
/home/qiang/lineageOs/kernel/oneplus/msm8996
lineageOs源码中交叉编译目录位置路径:
/home/qiang/lineageOs/prebuilts/gcc/linux-x86
为了方便研究测试,不破坏lineageOs中的内核源码结构。我新建一个目录专门存放内核源码、内核模块源码。并将内核源码拷贝到该目录。
本文后续测试的内核源码目录路径:
home/qiang/myproject/kernel/oneplus3/msm8996
本文后续内核模块编写存放目录路径:
/home/qiang/myproject/kernel/oneplus3/modules
二、编译内核源码
找到oneplus3设备的内核源码配置
安卓源码中device/厂商/手机型号/BoardConfig.mk文件中配置了内核源码路径和编译配置文件。因此在device/oneplus/oneplus3/BoardConfig.mk中存放了相关的内核配置信息,如下所示:
BOARD_KERNEL_BASE := 0x80000000
BOARD_KERNEL_PAGESIZE := 4096
BOARD_KERNEL_TAGS_OFFSET := 0x02000000
BOARD_RAMDISK_OFFSET := 0x02200000
BOARD_KERNEL_IMAGE_NAME := Image.gz-dtb
TARGET_KERNEL_SOURCE := kernel/oneplus/msm8996
TARGET_KERNEL_CONFIG := lineageos_oneplus3_defconfig
以上TARGET_KERNEL_CONFIG变量指定了oneplus3内核的编译配置文件名为:lineageos_oneplus3_defconfig。
在内核源码中编译配置文件一般存放在路径arch/处理器平台/configs下面。由于一加3手机为arm64,所以在路径arch/arm64/configs下找到配置文件lineageos_oneplus3_defconfig。如下所示:
qiang@ubuntu:~/myproject/kernel/oneplus3/msm8996/arch/arm64/configs$ pwd
/home/qiang/myproject/kernel/oneplus3/msm8996/arch/arm64/configs
qiang@ubuntu:~/myproject/kernel/oneplus3/msm8996/arch/arm64/configs$ ls -la lineageos_oneplus3_defconfig
-rw-rw-r-- 1 qiang qiang 15001 1月 3 23:00 lineageos_oneplus3_defconfig
为编译配置添加内核可加载、卸载选项
由于编译内核模块的时候需要依赖于已经编译过的内核输出,并且内核需要配置为可加载才能正常编译内核模块。所以需要修改一下arch/arm64/configs/lineageos_oneplus3_defconfig,添加如下配置项。
# 开启内核模块可加载
CONFIG_MODULES=y
# 开启内核模块可卸载
CONFIG_MODULE_UNLOAD=y
配置编译内核源码脚本
脚本如下
# 设置编译平台为64位arm
export ARCH=arm64
export SUBARCH=arm64
# 配置arm64的交叉编译路径
export PATH=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin:$PATH
# 配置32位arm的交叉编译路径
# 测试过程中32位的不设置居然编译不过
export PATH=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin:$PATH
# 设置64位交叉编译工具前缀
# 这个前缀其实就是交叉编译链路径/home/qiang/lineageOs/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin 下面的工具的公共前缀
export CROSS_COMPILE=aarch64-linux-android-
# 设置32位交叉编译工具前缀
# 这个前缀其实就是交叉编译链路径/home/qiang/lineageOs/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin 下面的工具的公共前缀
export CROSS_COMPILE_ARM32=arm-linux-androideabi-
# 通过make命令生成编译配置文件.config
# O=out指定输出目录 lineageos_oneplus3_defconfig:这个是oneplus3的内核编译配置
make O=out lineageos_oneplus3_defconfig
# 执行内核编译
make -j2 O=out ARCH=arm64
以上脚本在终端难的一个一个的输入,我将上面的弄成一个make.sh文件,到时候直接执行。make.sh内容如下:
#!/bin/bash
# 切换到内核源码根目录去
cd ./msm8996
make mrproper
make clean
export ARCH=arm64
export SUBARCH=arm64
export PATH=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin:$PATH
export PATH=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin:$PATH
export CROSS_COMPILE=aarch64-linux-android-
export CROSS_COMPILE_ARM32=arm-linux-androideabi-
make -j2 O=out lineageos_oneplus3_defconfig
make -j2 O=out ARCH=arm64
在终端执行make.sh之后就可以看到编译内核了,如下所示:
qiang@ubuntu:~/myproject/kernel/oneplus3$ ./make.sh
make[1]: Entering directory '/home/qiang/myproject/kernel/oneplus3/msm8996/out'
GEN ./Makefile
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/conf
编译完成之后,可以在目录/home/qiang/myproject/kernel/oneplus3/msm8996/out下面找到编译产生的文件和内核镜像。
三、编写helloworld模块
此处编写一个简单的HelloWorld模块进行研究测试。
创建helloworld.c模块源文件
文件代码如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
static int __init hello_init(void){
printk(KERN_ALERT "Hello World!\n");
return 0;
}
static void __exit hello_exit(void){
printk(KERN_ALERT "See You,Hello World!\n");
}
module_init(hello_init);
module_exit(hello_exit);
创建模块编译配置文件Makefile
Makefile如下:
# 设置内核源码编译的输出目录
KERNEL_OUT=/home/qiang/myproject/kernel/oneplus3/msm8996/out
# 设置arm64交叉编译链工具路径
TOOLCHAIN=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
# 设置arm32交叉编译链工具路径
TOOLCHAIN32=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
# 设置模块
obj-m := helloworld.o
# 编译命令配置
all:
make ARCH=arm64 CROSS_COMPILE_ARM32=$(TOOLCHAIN32) CROSS_COMPILE=$(TOOLCHAIN) -C $(KERNEL_OUT) M=$(shell pwd) modules
# 清理编译命令
clean:
make -C $(KERNEL_OUT) M=$(shell pwd) clean
在helloworld模块目录执行make命令进行编译
编译如下:
qiang@ubuntu:~/myproject/kernel/oneplus3/modules/helloworldmodule$ pwd
/home/qiang/myproject/kernel/oneplus3/modules/helloworldmodule
qiang@ubuntu:~/myproject/kernel/oneplus3/modules/helloworldmodule$ ls -la
total 16
drwxrwxr-x 2 qiang qiang 4096 1月 5 21:18 .
drwxrwxr-x 6 qiang qiang 4096 1月 5 21:17 ..
-rw-rw-r-- 1 qiang qiang 310 1月 5 21:06 helloworld.c
-rw-rw-r-- 1 qiang qiang 498 1月 5 21:08 Makefile
qiang@ubuntu:~/myproject/kernel/oneplus3/modules/helloworldmodule$ make
make ARCH=arm64 CROSS_COMPILE_ARM32=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi- CROSS_COMPILE=/home/qiang/lineageOs/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android- -C /home/qiang/myproject/kernel/oneplus3/msm8996/out M=/home/qiang/myproject/kernel/oneplus3/modules/helloworldmodule modules
make[1]: Entering directory '/home/qiang/myproject/kernel/oneplus3/msm8996/out'
CC [M] /home/qiang/myproject/kernel/oneplus3/modules/helloworldmodule/helloworld.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/qiang/myproject/kernel/oneplus3/modules/helloworldmodule/helloworld.mod.o
LD [M] /home/qiang/myproject/kernel/oneplus3/modules/helloworldmodule/helloworld.ko
make[1]: Leaving directory '/home/qiang/myproject/kernel/oneplus3/msm8996/out'
模块编译好之后就可以 adb push到手机,使用insmod加载模块进行测试验证了。以后就可以通过写内核系统hook模块进行系统调用内核层拦截、写netfileter hook模块进行网络管控等等操作。