测试机型是 Honor 50 SE 内核版本是 4.14.186 已解锁 BootLoader 通过 Magisk 27 管理 root
前段时间需要测试 4 系内核的一个外设驱动,打算用这台机器,编译好了驱动才发现有签名校验.网上一搜几乎都是小米和一加的教程,大意就是,先用 find_load_module.exe 在内核中搜索 load_module 函数位置,然后用 ida 修补了其中的几行汇编就搞定了.无奈我手中的的二进制看上去和教程中的完全不一样,压根无从改起,只好自己动手,这才有了这篇文档
从官网搜索对应的机型下载源码,解压后进到 Code_Opensource/kernel 找到 kernel/module.c, load_module 函数的相关代码基本上都在这里,下面贴一小段主要逻辑
可以看到签名校验部分都在 module_sig_check 中,我一看这还不手拿把掐嘛, nop 掉一个 bl 指令就能收工啦
打开 ida 后尝试搜索了几个字符串,很快就定为到了 load_module, 部分反汇编代码如下
emm...这种情况怎么说呢,算不上好但也不是无解,我尝试了直接跳转当然是失败了哈哈.编译内核时 module_sig_check 甚至 mod_verify_sig 都被内联进了 load_module, 没有函数调用就没有弹栈寄存器恢复现场,所以只好手动分析汇编,看看哪些寄存器会被后面的代码用到
机器码如下

好在编译器没给我更上强度,在一番试错后也是终于顺利进入系统,只需做如下修改
这部分和其他的 4 系内核差不多,简单说明一下,除了上面用到的内核源代码,还得下载 gcc 和 clang 工具链,地址如下
编译时最好是用 Ubuntu 20.04 x64 系统,我没有用机器自带的 /proc/config.gz 也成功了,只编译内核模块的话应该没那么多讲究
上面的脚本 PATH 和 defconfig 按需修改就行,测试代码如下
Makefile
hello.c
KDIR 是编译好的头文件目录,如果是新开的终端要重新添加 PATH, 将以上两个文件放到同一个目录下 make 即可
完事收工!
| 文件偏移 |
原指令 |
原机器码 |
新指令 |
新机器码 |
作用 |
| 0x2B267C |
CBNZ W2,loc_2B26FC |
02 04 00 35 |
NOP |
1F 20 03 D5 |
绕过 flags 校验 |
| 0x2B2688 |
CMP X8,#0x1D |
1F 75 00 F1 |
MOV X22,X1 |
F6 03 01 AA |
保存必要寄存器值 |
| 0x2B268C |
B.CC loc_2B26FC |
83 03 00 54 |
MOV X20,X30 |
F4 03 1E AA |
同上 |
| 0x2B2690 |
ADD X9,X0,X8 |
09 00 08 8B |
B 0x2B2780 |
3C 00 00 14 |
跳过验证函数 |
getprop ro.boot.slot_suffix
ls -al /dev/block/by-name/ | grep boot
dd if=/dev/block/sdc64 of=./boot.img
./magiskboot unpack ./boot.img
./libmagiskboot.so unpack ./boot.img
static int load_module(struct load_info *info, const char __user *uargs,
int flags)
{
struct module *mod;
long err;
char *after_dashes;
err = module_sig_check(info, flags);
if (err)
goto free_copy;
err = elf_header_check(info);
if (err)
goto free_copy;
mod = layout_and_allocate(info, flags);
if (IS_ERR(mod)) {
err = PTR_ERR(mod);
goto free_copy;
}
audit_log_kern_module(mod->name);
err = add_unformed_module(mod);
if (err)
goto free_module;
#ifdef CONFIG_MODULE_SIG
mod->sig_ok = info->sig_ok;
if (!mod->sig_ok) {
pr_notice_once("%s: module verification failed: signature "
"and/or required key missing - tainting "
"kernel\n", mod->name);
add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
}
#endif
... 以下省略 ...
}
static int module_sig_check(struct load_info *info, int flags)
{
int err = -ENOKEY;
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
const void *mod = info->hdr;
if (flags == 0 &&
info->len > markerlen &&
memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
info->len -= markerlen;
err = mod_verify_sig(mod, &info->len);
}
if (!err) {
info->sig_ok = true;
return 0;
}
#ifdef CONFIG_HUAWEI_PROC_CHECK_ROOT
saudit_log(MOD_SIGN, STP_RISK, 0, "result=%d,", err);
#endif
if (err == -ENOKEY && !sig_enforce)
err = 0;
return err;
}
v6 = a1;
v575 = &off_0;
v8 = (const char *)(a1 + 8);
v7 = *(_QWORD *)(a1 + 8);
if ( a3
|| (v10 = (const char **)(v6 + 16), v9 = *(_QWORD *)(v6 + 16), v9 < 0x1D)
|| *(_QWORD *)(v7 + v9 - 28) ^ 0x20656C75646F4D7ELL
| *(_QWORD *)(v7 + v9 - 20) ^ 0x727574616E676973LL
| *(_QWORD *)(v7 + v9 - 12) ^ 0x646E657070612065LL
| *(unsigned int *)(v7 + v9 - 4) ^ 0xA7E6465LL )
{
v11 = -126;
LABEL_5:
sub_68939C(10, 1, 0, "result=%d,", v11);
v12 = v11;
goto LABEL_6;
}
v4 = a2;
v3 = v5;
*v10 = (const char *)(v9 - 28);
v11 = sub_2B82E0();
if ( v11 )
goto LABEL_5;
v15 = *(_QWORD *)(v6 + 16);
*(_BYTE *)(v6 + 76) = 1;
if ( v15 < 0x40
|| (v16 = *(_DWORD **)v8, **(_DWORD **)v8 != 1179403647)
|| *((_WORD *)v16 + 8) != 1
|| *((_WORD *)v16 + 9) != 183
|| *((_WORD *)v16 + 29) != 64
|| (v17 = *((_QWORD *)v16 + 5), v18 = v15 > v17, v19 = v15 - v17, !v18)
|| v19 < (unsigned __int64)*((unsigned __int16 *)v16 + 30) << 6 )
{
v12 = -8;
goto LABEL_6;
}