首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 归档 标签 关于

利用具有很长中断的系统管理模式

2026-08-10 1 阅读 约8分钟阅读 WhiteDawn
分享:
字号:
smiiiiiiiiiiiiiiii 利用系统管理模式,产生非常非常非常非常长的中断。概述 事实证明,只需一条极其长时间运行的机器指令,您就可以破解 SMM(在每个 x86 CPU 后台隐形运行的安全、超特权执行环境)。 SMM 要求所有内核同时处于 SMM 或处于 SMM 之外。如果没有这个,它的安全模型就无法工作——当一个线程进入 SMM 时,它会让所有其他线程也进入。为了打破这个局面,我们所需要的就是有人太忙而没有注意到他们应该加入 SMM。它的工作原理如下:核心 0 - 开始一条长指令 | | | core 1 - 邀请core 0 参加smm | | |核心 1 - 输入 smm | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 等待核心 0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |核心 1 - 放弃 核心 1 - 做秘密 SMM 的事情 核心 1 - 完成 SMM | | | core 0 - join smm 此时,核心 1 退出 SMM,而核心 0 进入,让核心 1 攻击核心 0。这里有一个问题:要实现这一点,我们需要一条非常、非常、非常长的指令——比任何指令都应该花费的时间还要长。现代 CPU 上的大多数机器指令都很快:add 需要 1 个周期。为了让核心 1 放弃等待核心 0,我们需要在核心 0 上执行一条指令,该指令需要大约 4,000,000,000 个周期——超过 1 秒的挂钟时间。当 CPU 内核进入 SMM 时,一秒超时 x86 固件会运行以下代码: for ( Timer = StartSyncTimer (); !IsSyncTimerTimeout ( Timer , mTimeoutTicker ) && SyncNeeded ; ) { mSmmMpSyncData -> AllApArrivedWithException = AllCpusInSmmExceptBlockedDisabled (); } if ( mSmmMpSyncData -> AllApArrivedWithException ) { 中断 ; } CPU暂停();代码等待所有核心进入 SMM,或等待最多 1 秒,以先发生者为准。为了让一个核心执行 SMM 代码,而另一个核心在 SMM 外部继续执行,我们需要该外部核心在整个秒内保持不间断 - SMI 是在指令边界处获取的,因此两条指令之间的任何间隙都是待处理的 SMI 穿过以将核心拖入的门。因此,延迟必须是单个指令:一个比一秒交会更持久的不间断操作。概念验证 有很多方法可以达到禁止的 1 秒指令,具体方法因平台而异。但是,粗略地说:找到一个高延迟的 MMIO 地址,然后说服 CPU 尽可能慢地读取它——滥用一个无记录的区域来快速响应读取,然后使用 ISA 提供的最宽负载,用一条指令在该地址上传输一堆可笑的字节,理想情况下,当其他内核都挤到同一条总线上时,整个事情就会在争用中呼啸而过。一次读取、一条指令,CPU 就会卡住它一秒钟的时间。所提供的概念验证针对 Zen 3 Ryzen 7 5800H 进行了调整,其中来自 0xfcc68860 处慢速 MMIO 的宽 xmm 负载停顿时间足以破坏全核交会: mov $ 0xfcc68860 , % rsi ;目标MMIO地址vmovdqu(%rsi),%xmm0;非常非常长的负载 PoC 通过让两个核心相互竞争来利用这一点。一个核心被长指令保留在 SMM 之外 - 非常慢的负载上的紧密循环: /* 受害核心:在大约 1 秒的负载上旋转,太忙而无法应答 SMI */ for (;;) asm 易失性 ( "vmovdqu (%0), %%xmm0" :: "r" ( mmio ) : "xmm0" );同时,另一个核心武装每核心 SMI 计数器: #define MSR_PERF_CTL0 0xc0010200 /* AMD 核心性能事件选择 MSR */ #define MSR_PERF_CTR0 0xc0010201 /* 配对的 48 位计数器 */ for ( int cpu = 0 ; cpu < ACTIVE_CPUS ; cpu ++ ) { msr_write ( cpu , MSR_PERF_CTL0 , 0x43002b ); /* EN |操作系统 |苏联 |事件 0x2b */ msr_write ( cpu , MSR_PERF_CTR0 , 0 ); /* 将计数归零 */ } 然后引发 SMI 风暴: asm volatile ( "outb %%al, $0xb2" :: "a" ( 0 )); /* 启动端口 0xb2 -> #SMI */ 并读取每个核心的计数: /* ...引发风暴,然后读取每个核心的计数... */ uint64_t delta = smi_max - smi_min ; if ( delta ) put ( "!!!一个核心在 SMM 之外运行" );计数器讲述了这个故事。如果它们出现分歧,一个核心将继续在 SMM 之外运行,而其他核心则被拉入——它通过 SMI 生存,其余核心则通过 SMI 进行服务。
这篇文章对您有帮助吗?

订阅66必读

每日精选科技资讯,直达你的邮箱