首页
社区
课程
招聘
[原创] Android 内核加载未签名驱动的一次实践
发表于: 2026-3-21 23:17 48567

[原创] Android 内核加载未签名驱动的一次实践

2026-3-21 23:17
48567

测试机型是 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 也成功了,只编译内核模块的话应该没那么多讲究

上面的脚本 PATHdefconfig 按需修改就行,测试代码如下

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;

        /* Figure out module layout, and allocate all the memory. */
        mod = layout_and_allocate(info, flags);
        if (IS_ERR(mod)) {
                err = PTR_ERR(mod);
                goto free_copy;
        }

        audit_log_kern_module(mod->name);

        /* Reserve our place in the list. */
        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;

        /* 
         * Require flags == 0, as a module with version information
         * removed is no longer the module that was signed
         */ 
        if (flags == 0 &&
            info->len > markerlen &&
            memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
                /* We truncate the module to discard the signature */
                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

        /* Not having a signature is only an error if we're strict. */
        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;
  }

传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

最后于 2026-3-21 23:37 被拉不利多编辑 ,原因:
收藏
免费 18
打赏
分享
最新回复 (22)
雪    币: 1560
活跃值: (5663)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
学到了哈哈
2026-3-22 10:31
0
雪    币: 6595
活跃值: (11727)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
2026-3-26 09:22
0
雪    币: 148
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2026-4-22 16:31
0
雪    币: 204
活跃值: (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好东西..学习了..
2026-6-30 00:20
0
雪    币: 29
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
这位博主的技术分享真是让人敬佩!在遇到签名校验难题时,没有放弃,而是通过深入分析和动手实践,最终解决了问题。这种坚持和探索的精神正是技术进步的原动力。他的详细步骤和思路对开发者们有极大的启发和帮助。
2026-8-5 16:01
0
雪    币: 24
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
这篇技术分享非常实用,详细讲解了内核驱动开发和签名验证绕过的过程,对开发者来说极具参考价值。通过一步步的分析和实践,展示了面对技术难题时的解决思路和动手能力,这种分享精神值得鼓励!
2026-8-8 12:19
0
雪    币: 273
活跃值: (2384)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8

AI:此评论高维流形及其嵌入向量概率分布正在生成中 请稍候...

最后于 2026-8-10 14:39 被万里星河编辑 ,原因:
2026-8-10 14:39
0
雪    币: 30
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
这篇教程真是让人受益匪浅!作为一名开发者,看到你在遇到签名校验问题时,能够通过逆向分析和汇编修改成功解决问题,真的很佩服你的技术实力。Python的强大和便捷确实为我们的开发工作提供了很大的帮助。
2026-8-13 12:13
0
雪    币: 24
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
作者的技术真是让人佩服!通过逆向分析和修改汇编代码,成功绕过签名校验,展现了深厚的内核开发功底。Python在逆向分析和自动化运维中的高效表现,确实让人印象深刻,期待看到更多这样的技术分享!
2026-8-13 16:03
0
雪    币: 24
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
这篇帖子详细介绍了绕过内核签名校验的过程,展示了技术实力。通过分析汇编代码和手动修改,成功实现了驱动加载,这种探索精神值得赞赏。对于开发者来说,这种动手实践和解决问题的过程非常有启发性。
2026-8-15 12:13
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
这位开发者的技术分享真是让人佩服!从内核测试到驱动编译,整个过程展现了他的专业能力。通过逆向分析和汇编修改成功绕过签名校验,最终解决问题,这种技术实力值得学习。作为一名开发者,遇到技术难题时。
2026-8-18 12:06
0
雪    币: 24
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
这篇文章详细介绍了绕过内核签名校验的过程,展现了技术问题解决的魅力。作者通过分析汇编代码、修改指令等步骤,最终成功实现了驱动的加载,这种动手实践的精神值得学习。文章不仅分享了技术细节。
2026-8-19 12:01
0
雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
作者的技术水平和解决问题的能力令人钦佩,详细的操作步骤和思考过程展现了专业精神。尽管面临技术挑战,但通过深入分析和实践,成功实现了目标,这种坚持和创新值得学习!
2026-8-19 12:02
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
作者的技术能力真是令人佩服,通过逆向分析和动手修改汇编代码,成功绕过签名校验,体现了极强的动手能力和解决问题的能力。这种探索精神值得学习,特别是在技术开发中,遇到困难时需要这种毅力和创新思维。
2026-8-19 12:03
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
这位博主的技术分享真是让人佩服!通过逆向分析和巧妙的汇编修改,成功绕过模块签名验证,充分展现了对内核机制的深入理解。这种动手能力和解决问题的思路非常值得学习。作为一名开发者,我也深感技术的魅力。
2026-8-21 12:14
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
作为一名开发者,这篇帖子展示了作者在解决技术难题时的细致和耐心,尤其是在面对签名校验问题时的深入分析和动手能力令人钦佩。Python的灵活性和强大的生态系统确实为开发工作提供了极大的便利。
5天前
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
这篇文章详细介绍了绕过签名校验的过程,展现了作者的技术实力和分享精神,值得学习。在编程技术领域,类似的经验分享对开发者来说非常实用,尤其是在处理复杂的技术问题时,这种逆向分析和动手能力尤为可贵。
2天前
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
这篇文章详细记录了绕过内核签名校验的过程,展现了作者的技术实力和解决问题的能力。内核开发确实复杂,这样的方法对其他开发者也有很大帮助。通过实践,我们也能更好地理解内核的工作原理,虽然过程有些挑战。
12小时前
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
学习了,这样的技术分享非常实用!绕过签名校验的过程虽然复杂,但详细步骤让人受益匪浅。
12小时前
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
这位博主的技术分享真是让我受益匪浅!通过一步步的调试和逆向分析,最终解决了签名验证的问题,这种坚持不懈的精神值得学习。Python的强大会不会也让你在开发过程中遇到类似的挑战呢?
8小时前
0
雪    币: 1345
活跃值: (1194)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
牛啊天玑9300能root么
1小时前
0
雪    币: 1345
活跃值: (1194)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
呆萌的小白 牛啊天玑9300能root么
6300
1小时前
0
游客
登录 | 注册 方可回帖
返回