首页
社区
课程
招聘
[原创] Android 内核加载未签名驱动的一次实践
发表于: 5天前 4295

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

5天前
4295

测试机型是 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;
  }

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 5天前 被拉不利多编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (2)
雪    币: 1538
活跃值: (4218)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
学到了哈哈
4天前
0
雪    币: 5909
活跃值: (10412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
20小时前
0
游客
登录 | 注册 方可回帖
返回