首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 汽车 游戏 社会热点 开源推荐 医疗健康 归档 标签 关于

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

2026-08-11 1 阅读 约10分钟阅读 WhiteDawn
分享:
字号:
利用系统管理模式进行非常非常非常非常长的中断。事实证明,只需一条极其长时间运行的机器指令,您就可以破解 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 秒,以先发生者为准。 To get a core to execute SMM code while another core stays executing outside SMM, we need that outside core to stay uninterruptible for the entire second — an SMI is taken at an instruction boundary, so any gap between two instructions lets the pending SMI pull the core into SMM.因此,延迟必须是单个指令:一个比一秒交会持续时间更长的不间断操作。有很多方法可以达到禁止的 1 秒指令,具体方法因平台而异。 But, roughly: find a high-latency MMIO address, and then convince the CPU to read from it as slowly as possible — abuse an undocumented region that answers reads at a crawl, use the widest load the ISA will give you to move as many bytes as possible across it in a single instruction, and let the other cores contend for the same bus to slow it further.一次读取、一条指令,CPU 就会卡住它一秒钟的时间。 The provided proof-of-concept is tuned for a Zen 3 Ryzen 7 5800H, where a wide xmm load from slow MMIO at 0xfcc68860 stalls long enough to break the all-cores rendezvous: 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 ); /*
这篇文章对您有帮助吗?

订阅66必读

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