KernelSU 是 Android GKI 设备的 root 解决方案,它工作在内核模式,并直接在内核空间中为用户空间应用程序授予 root 权限。KernelSU内核Root隐藏性更高。黑鹰本人一直用氢11养老,所以旧版本的集成KernelSU很少,所以才有了今天这个教程,乐享网也是第一次接触内核,所以教程不是很完美,也是自己的一个笔记。有想尝试的可以自己编译一下。
安装Ubuntu
Horizon Clang 是在 Ubuntu 22.04 + glibc 2.35 的环境下编译的,所以需要第一步安装22.04.3 LTS系统。
Ubuntu 22.04:https://ubuntu.com/download/desktop
安装Ubuntu教程省略,可以在网上找教程。
安装基础软件包
sudo apt-get install libncurses5-dev libncurses-dev libssl-dev device-tree-compiler bc cpio lib32ncurses5-dev lib32z1 build-essential binutils bc bison build-essential ccache curl flex g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5 libncurses5-dev libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev git
Horizon需要安装python2
sudo apt install python2
安装基础包我这也会出现编译错误,如果出现错误下方再安装一遍
#更新安装列表:
apt-get update
#安装gcc:
apt install gcc
#安装make:
apt-get install make
安装库:
sudo apt install bison
sudo apt install flex
sudo apt install libssl-dev
编译方法
内核源自大佬:https://blog.xzr.moe/archives/313
首先,创建工作空间,获取内核本体代码:
mkdir workspace
cd workspace
git clone https://github.com/libxzr/android_kernel_oneplus_sm8250 -b oos11/final
然后,获取内核压缩包的代码:
git clone https://github.com/libxzr/AnyKernel3 -b op8/11
获取编译工具链,此处推荐 Horizon Clang ,R18 版本是基于其 16.x 版本编译测试的。
工具链在解压后放在 workspace 的 clang 目录处,不可有额外的目录嵌套,即需要确保 workspace/clang/bin/clang 是编译器的可执行文件。
Horizon Clang下载地址
百度网盘:https://pan.baidu.com/s/1fueWlqRpNDjY9LyCPqQR2w 提取码:x698
天翼云盘:https://cloud.189.cn/t/yABBreVZfUFf 提取码:9bp9
下载之后复制到workspace/目录下
确保命令行在workspace,开始解压
mkdir clang
tar -xJvf Horizon-Clang-<版本>.tar.xz -C clang
然后,获取内核本体中的 submodules:
cd android_kernel_oneplus_sm8250
git submodule init
git submodule update
开启kernel su支持
安卓开启kernel su支持
拉取内核源码,进入你的内核源码文件夹,执行以下命令
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
修改文件内核配置文件。
修改内核源码:/workspace/android_kernel_oneplus_sm8250/arch/Arm64/configs/op8-perf_defconfig
//将这部分注释掉
#CONFIG_MODULE_SIG_FORCE=y //这个参数是验证内核驱动,需要关掉,不然会出现无法触摸、屏幕不工作、黑屏等问题
//开启kernel su的开关
CONFIG_KPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_KPROBE_EVENTS=y
//强制加载内核驱动模块,不加载内核模块会直接G掉
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
//SELinux默认是Permissive状态
CONFIG_SECURITY_SELINUX_DEVELOP=y
//关闭AVB验证
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_AVB=y
主要是要改四个地方:
- do_faccessat,通常位于
fs/open.c
- do_execveat_common,通常位于
fs/exec.c
- vfs_read,通常位于
fs/read_write.c
- vfs_statx,通常位于
fs/stat.c
修改内核源码/workspace/android_kernel_oneplus_sm8250/fs/exec.c文件
//addcode start
extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
void *envp, int *flags);
//addcode end
static int do_execveat_common(int fd, struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
//addcode
ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags);
//addcode end
return __do_execve_file(fd, filename, argv, envp, flags, NULL);
}
修改内核源码/workspace/android_kernel_oneplus_sm8250/fs/read_write.c文件
//addcode start
extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
size_t *count_ptr, loff_t **pos);
//addcode end
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
//addcode start
ksu_handle_vfs_read(&file, &buf, &count, &pos);
//addcode end
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
return -EFAULT;
修改内核/workspace/android_kernel_oneplus_sm8250/fs/stat.c文件
//addcode start
extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
//addcode end
/**
* vfs_statx - Get basic and extra attributes by filename
* @dfd: A file descriptor representing the base dir for a relative filename
* @filename: The name of the file of interest
* @flags: Flags to control the query
* @stat: The result structure to fill in.
* @request_mask: STATX_xxx flags indicating what the caller wants
*
* This function is a wrapper around vfs_getattr(). The main difference is
* that it uses a filename and base directory to determine the file location.
* Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink
* at the given name from being referenced.
*
* 0 will be returned on success, and a -ve error code if unsuccessful.
*/
int vfs_statx(int dfd, const char __user *filename, int flags,
struct kstat *stat, u32 request_mask)
{
struct path path;
int error = -EINVAL;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
//addcode start
ksu_handle_stat(&dfd, &filename, &flags);
//addcode end
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
return -EINVAL;
修改内核/workspace/android_kernel_oneplus_sm8250/fs/open.c
//addcode start
extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *flags);
//addcode end
long do_faccessat(int dfd, const char __user *filename, int mode)
{
const struct cred *old_cred;
struct cred *override_cred;
struct path path;
struct inode *inode;
struct vfsmount *mnt;
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
//addcode start
ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
//addcode end
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
override_cred = prepare_creds();
if (!override_cred)
return -ENOMEM;
KernelSU 内置安全模式 drivers/input/input.c和kernel/module.c文件
修改内核/workspace/android_kernel_oneplus_sm8250/drivers/input/input.c 中的 input_handle_event 方法:
//addcode start
extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value);
//addcode end
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = input_get_disposition(dev, type, code, &value);
//addcode start
ksu_handle_input_handle_event(&type, &code, &value);
//addcode end
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
add_input_randomness(type, code, value);
修改内核/workspace/android_kernel_oneplus_sm8250/kernel/module.c文件
第一处:
static int try_to_force_load(struct module *mod, const char *reason)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
if (!test_taint(TAINT_FORCED_MODULE))
pr_warn("%s: %s: kernel tainted.\n", mod->name, reason);
add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE);
return 0;
#else
return -ENOEXEC;
#endif
}
#ifdef CONFIG_MODVERSIONS
//这里改成0,始终为true
#if 0
static u32 resolve_rel_crc(const s32 *crc)
{
第二处:
static int load_module(struct load_info *info, const char __user *uargs,
int flags)
{
struct module *mod;
long err = 0;
char *after_dashes;
//addcode加入这两个flags,跳过内核模块验证,强制加载
flags |= MODULE_INIT_IGNORE_MODVERSIONS;
flags |= MODULE_INIT_IGNORE_VERMAGIC;
//addcode end
err = elf_header_check(info);
if (err)
goto free_copy;
编译内核
参考的编译脚本:
horizon_build.sh
#!/bin/bash
set -e
DIR="$( cd "$( dirname "$0" )" &&cd ..&& pwd )"
source="$( cd "$( dirname "$0" )" && pwd )"
CLANG_PATH="${DIR}/clang"
args="-j$(nproc --all) \
O=out \
ARCH=arm64 \
CLANG_TRIPLE=aarch64-linux-gnu- \
CROSS_COMPILE=${CLANG_PATH}/bin/aarch64-linux-gnu- \
CC=${CLANG_PATH}/bin/clang \
CROSS_COMPILE_COMPAT=${CLANG_PATH}/bin/arm-linux-gnueabi- \
AR=${CLANG_PATH}/bin/llvm-ar \
NM=${CLANG_PATH}/bin/llvm-nm \
LLVM_AR=${CLANG_PATH}/bin/llvm-ar \
LLVM_NM=${CLANG_PATH}/bin/llvm-nm \
OBJCOPY=${CLANG_PATH}/bin/llvm-objcopy \
OBJDUMP=${CLANG_PATH}/bin/llvm-objdump \
STRIP=${CLANG_PATH}/bin/llvm-strip \
LD=${CLANG_PATH}/bin/ld.lld "
device="all"
clean="false"
action="build"
version="`date +"%m%d%H%M"`"
release="false"
print (){
case ${2} in
"red")
echo -e "\033[31m $1 \033[0m";;
"blue")
echo -e "\033[34m $1 \033[0m";;
"yellow")
echo -e "\033[33m $1 \033[0m";;
"purple")
echo -e "\033[35m $1 \033[0m";;
"sky")
echo -e "\033[36m $1 \033[0m";;
"green")
echo -e "\033[32m $1 \033[0m";;
*)
echo $1
;;
esac
}
input=${*}
for i in ${input}
do
case ${i} in
"op8")
device="op8";;
"op8p")
device="op8p";;
"op8t")
device="op8t";;
"all")
device="all";;
"--clean"|"-c"|"clean")
clean="true";;
*)
did="false"
if [[ $i =~ "-r=" ]];then
release="true"&&version="${i#*r=}"&&did="true"
fi
if [[ $i =~ "-v=" ]];then
version="${i#*v=}"&&did="true"
fi
if [ $did == "false" ]
then
print "Error input" red&&exit
fi
;;
esac
done
mkzip (){
if [ "${release}" == "true" ];then
zipname="(${1})Horizon-Kernel-R${version}.zip"
else
zipname="(${1})Horizon-Kernel-${version}.zip"
fi
cp -f out/arch/arm64/boot/Image.gz ${DIR}/AnyKernel3
#find ${source}/out/arch/arm64/boot/dts/vendor/qcom -name '*.dtb' -exec cat {} + > ${DIR}/AnyKernel3/dtb
cp ${source}/out/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dtb ${DIR}/AnyKernel3/dtb
#cp ${source}/out/arch/arm64/boot/dts/vendor/qcom/instantnoodle-t0.dtb ${DIR}/AnyKernel3/dtb
cp ${source}/out/arch/arm64/boot/dtbo.img ${DIR}/AnyKernel3
cd ${DIR}/AnyKernel3
zip -r "${zipname}" *
cp -f "${zipname}" ${DIR}
rm -f "${zipname}"
cd ${source}
print "All done.Find it at ${DIR}/$zipname" green
}
build_op8(){
print "Building Kernel for op8..." blue
make $args instantnoodle_defconfig&&make $args
mkzip "op8${1}"
}
build_op8p(){
print "Building Kernel for op8p..." blue
make $args instantnoodlep_defconfig&&make $args
mkzip "op8p${1}"
}
build_op8t(){
print "Building Kernel for op8t..." blue
make $args kebab_defconfig&&make $args
mkzip "op8t${1}"
}
bclean(){
rm -rf ${source}/out/arch/arm64/boot
}
clean(){
if [ "${clean}" == "true" ]
then
print "Doing cleanups" red
make ${args} mrproper
else
bclean
fi
}
if [ "${action}" == "build" ]
then
if [ $release == "true" ]
then
print "You are building a release version:R${version}" green
args+="LOCALVERSION=-R${version} "
else
print "You are building a snapshot version:${version}" yellow
args+="LOCALVERSION=-${version} "
fi
if [ ${device} == "all" ]
then
git reset --hard
clean
build_op8t "-OOS"
bclean
git apply lineage.diff
build_op8t "-Lineage"
git reset --hard
bclean
build_op8p "-OOS"
bclean
git apply lineage.diff
build_op8p "-Lineage"
git reset --hard
bclean
git apply lineage.diff
build_op8 "-Lineage"
git reset --hard
bclean
build_op8 "-OOS"
elif [ ${device} == "op8" ]
then
clean
build_op8
elif [ ${device} == "op8p" ]
then
clean
build_op8p
elif [ ${device} == "op8t" ]
then
clean
build_op8t
fi
fi
脚本要求的目录结构如下:
workspace
├── AnyKernel3
├── android_kernel_oneplus_sm8250
│ ├── horizon_build.sh
│ ├── KernelSU
├── clang
│ ├── bin
│ │ ├── clang
workspace 的目录名称是无所谓的,只需要确保 AnyKernel3
和 clang
在内核源码文件夹的同级目录下即可,编译脚本则放在内核源码文件夹中。
cd workspace/android_kernel_oneplus_sm8250
然后在内核源码文件夹中执行命令即可:
# 编译所有机型/系统的版本
./horizon_build.sh
# 编译所有机型/系统的版本(干净编译)
./horizon_build.sh -c
# 编译一加 8 的版本(仅氢氧)
./horizon_build.sh op8
# 编译一加 8 的版本(仅氢氧)(干净编译)
./horizon_build.sh op8 -c
# 编译一加 8P 的版本(仅氢氧)
./horizon_build.sh op8p
# 编译一加 8P 的版本(仅氢氧)(干净编译)
./horizon_build.sh op8p -c
# 编译一加 8T 的版本(仅氢氧)
./horizon_build.sh op8t
# 编译一加 8T 的版本(仅氢氧)(干净编译)
./horizon_build.sh op8t -c
最后文件输出到目录/workspace/(op8t)Horizon-Kernel-{version}.zip
刷入前先用TWRP刷入官方Boot,之后无需重启直接刷入内核刷机包即可
如果感觉麻烦也可以使用乐享网编译的直接刷入即可
- 最新
- 最热
只看作者