
电磁故障注入EMFI听起来像是实验室里焊台边上那群人才会碰的东西但这些年它在硬件安全圈里已经越来越常见甚至在很多芯片验证、安全评估、故障分析的项目里成了必修课。简单说EMFI 就是用一个瞬时的强电磁脉冲去打一颗芯片的某个局部区域让它在关键时刻“算错一步”。别看这个错只有一瞬间如果打的位置和时间点足够准它可以让安全启动的校验逻辑失效、让密码算法在中间状态跳飞、让 CPU 跳过某条关键比较指令。这几年不少真实设备的安全漏洞和学术论文里的攻击案例都是靠这个手法做出来的。这篇文章就是给想动手做 EMFI 的人看的。不管你是硬件安全研究员、芯片验证工程师还是搞嵌入式开发想了解自己的板子扛不扛打我都会从原理讲到具体操作再把我实际调试中踩过的坑、总结的参数经验一次说清楚。内容会比较长但每一步都有落地的细节不像很多公开资料那样只给个概念图就结束了。1. 先说清楚 EMFI 到底在干什么电磁脉冲怎么就让芯片“抽风”了很多人第一次接触 EMFI 都会问同一个问题一个脉冲打过去芯片怎么就会出错这里的关键不是电压击穿也不是把芯片烧掉而是让芯片内部的逻辑在极短的时间里发生瞬态干扰从而产生一个或多个位翻转。1.1 从物理层面理解故障注入的本质芯片内部处理信息靠的是晶体管和金属走线上的电平变化。正常情况下一个逻辑门的输出要么是高电平代表 1要么是低电平代表 0而这个判断是由供电电压和晶体管阈值共同决定的。当外部来了一个强电磁脉冲根据法拉第电磁感应定律芯片内部的导体回路里会感应出额外电压。这个感应电压叠加在原来的信号电平上如果幅度够大、方向正好就可能让本来该判成 0 的节点被读成 1或者反过来。这个原理跟收音机收到电磁波是一样的只不过收音机接收的是特定频率的调制信号而 EMFI 用的是极短、极强、频带极宽的脉冲目的就是让芯片里最敏感的那几个节点在几纳秒的瞬间出现错误。更通俗地说就像你正在写字有人突然撞了一下你的胳膊笔尖一歪纸上就留了个错字。错字不会让整张纸消失但关键的那个字错了整句话意思可能就变了。1.2 为什么“一次错误”能变成“一个漏洞”单个位翻转本身没什么破坏力但攻击者要的就是这么一次错误出现在不对的地方。典型的利用场景有几种绕过安全检查芯片在启动时读某个寄存器的值判断是否进入安全模式。如果脉冲让这个寄存器的一两位翻转比较结果就变了安全模式被跳过。让循环少跑几轮密码算法里的轮函数如果写了循环计数故障注入可能让计数寄存器被清零或置位导致加密过程少做几轮输出结果就和正常不一样。把公钥搞坏做数字签名验证时如果故障让被比较的摘要数据出现位错误伪造的签名就可能被当成合法签名。改变分支跳转在if (password_check())这类语句里如果故障注入发生在password_check返回值写入寄存器到分支判断之间的窗口返回值可能被改掉。这里要特别强调EMFI 不是玄学它的成功率和很多参数强相关。你不会随随便便扔一个脉冲就能绕过安全启动因为芯片内部成千上万个晶体管一颗芯片裸片又只有指甲盖大小你必须在正确的时间、正确的位置、用正确的能量打出那一击。这也是为什么做 EMFI 的人都要花大量精力做扫描和调参。1.3 EMFI 和其他故障注入方式的对比除了电磁常见的故障注入手段还有电压毛刺Voltage Glitching、时钟毛刺Clock Glitching、激光注入Laser Fault Injection和温度冲击。了解它们的区别能帮你判断在什么场景下选 EMFI 最合适。注入方式空间精度时间精度设备成本是否需要开盖主要适用场景电压毛刺整个芯片供电域高较低通常不需要攻击整个 MCU、绕过简单校验时钟毛刺整个系统时钟高低通常不需要干扰取指和流水线状态电磁注入毫厘级区域中高中部分需要定位特定模块如安全单元、内存控制器激光注入微米级高极高必须开盖精确到单个 SRAM 单元和寄存器温度冲击大面积很低低不一定制造随机错误很少用于定向攻击EMFI 的定位正好卡在“成本可控”和“精度足够”之间。激光注入精度最高但设备贵到飞起而且必须做复杂的芯片开盖和背孔处理电压毛刺便宜但只能对整个芯片供电做文章没法精确打击某个模块。EMFI 用一根几十微米到几百微米的探针线圈可以在不开盖的情况下对某些封装把能量集中到芯片的特定区域同时设备成本比激光低一到两个数量级所以它成了硬件安全实验室里最常用的“重武器”。2. 动手前的准备设备选型、目标选择和基本测试平台搭建EMFI 的入门门槛其实没有想象中那么高但也不是把几个模块拼起来就能马上成功。很多新手第一次搭完台子发现打了几百个脉冲啥变化都没有原因往往是设备搭配不合理或者根本不知道脉冲打在哪了。这一节我把设备选型和平台搭建讲透。2.1 核心设备清单与作用一套完整的 EMFI 测试平台至少需要这么几块高压脉冲源产生几百伏到几千伏的短脉冲核心指标是峰值电压、上升沿速度和脉冲宽度。常见的实现方式有 Marx 发生器、雪崩晶体管阵列和基于 MOSFET/IGBT 的开关电路。自己搭的话雪崩晶体管阵列比较适合几百伏、脉宽纳秒级的场景Marz 发生器则适合放大到几千伏。电磁注入探头就是把脉冲电流转换成空间磁场的换能器。探头由一圈或多圈铜线绕成内部常常加铁氧体磁芯来增强磁场强度。探头的直径决定了注入的空间分辨率线圈越小磁场越集中但能量传输效率也越低。三维定位平台用来把探头精准移动到芯片上方的指定坐标。好的定位平台需要微米级步进最好还能通过电脑程控这样才算实现了自动扫描。示波器和电流探头观察脉冲波形确认实际打到芯片上的脉冲形态。很多新手只看电压源设定值不测实际波形结果发现脉宽、幅度和预期差了很远。触发同步装置把目标板运行的某个状态比如一条指令执行、一个 GPIO 翻转转换成脉冲源的触发信号。这是整个系统里最考验功力的部分后面会专门讲。目标板与观察接口目标板除了正常运行被测功能以外还要能把运行状态和攻击结果导出来通常是串口或者 GPIO。2.2 开源方案与商业方案的取舍我见过不少团队一开始买商业 EMFI 套装一套下来动辄几十万人民币。如果你是刚开始接触这个方向或者只是验证自己板子的安全性完全不需要一上来就上商业设备。比较务实的路线是先基于开源硬件做一套入门平台积累经验之后再决定要不要升级。比较常用的开源参考设计包括 NewAE 的 ChipWhisperer 系列以及相关社区衍生出的电磁注入探头驱动器。ChipWhisperer 主要做嵌入式安全研究和侧信道分析它配套的硬件里也有故障注入相关的模块和示例工程。社区里还有不少自己做的 Marx 发生器或者基于汽车点火线圈改装的脉冲源脉冲能量很足但波形一致性差只适合探测哪些区域对电磁敏感不适合做精细的重复实验。我的建议是分三步走先用信号发生器加功率放大器模拟弱脉冲摸清触发同步和扫描流程这一步的目的是打通软件链路。搭一个简单的雪崩晶体管脉冲源输出 300V 到 800V、脉宽 5ns 到 50ns 的脉冲配合 5mm 到 10mm 直径的探头试试能不能让简单 MCU 的某个循环计数器出错。再逐步提高脉冲电压、缩小探头直径、引入三维自动扫描往精确攻击的方向优化。2.3 目标芯片的选择和前期准备做 EMFI 测试不是随便拿一块开发板就能开始的。你要先想清楚自己想在芯片上验证什么故障模型以及什么样的芯片适合入门。入门目标建议选这样几类STM32F1/F4 系列开发板资料多、调试接口丰富、芯片裸片位置容易确定社区里大量现成例子可以参考。简单 8 位 MCU比如 ATmega328P逻辑简单对电磁干扰的响应比较直观适合观察故障注入后的系统状态变化。带安全特性的评估板比如带 TrustZone 或安全启动的高端 MCU这类板子才真正能体现 EMFI 绕过的价值。目标板准备好之后有一步容易被忽略确定芯片裸片在封装里的实际位置。很多封装芯片的裸片并不在正中央比如 QFP 封装的裸片通常偏在某个角上BGA 封装更是只能靠 X 光或者数据手册判断。如果探头对着一块封装塑料打能量会被塑封材料和引线框架吸收一部分可能根本没有有效耦合到裸片。入门前可以通过打磨封装、开盖或者看 X 光图来确定位置这样扫描起来才能少走弯路。2.4 最小测试平台的接线和验证我自己搭的第一套测试平台大概是这样一个目标 MCU 板通过 USB 转串口上报状态GPIO 引脚在每次执行到目标函数前拉高函数返回后拉低。示波器的一个通道监测这个 GPIO用它的上升沿触发脉冲源延迟若干微秒后把脉冲打到芯片上方。接线顺序看起来简单但有一个非常大的坑触发延迟的控制。如果脉冲到达的时间比目标处理敏感数据的窗口晚太多那你打到的就是已经结束的逻辑周期什么都不会发生。需要先用示波器确认真实时序把“GPIO 拉高”到“敏感操作开始”之间的延迟测出来再把它设置到脉冲源的触发延迟里。平台搭好以后第一次“真刀真枪”的验证建议选一个非常简单的目标让 MCU 循环翻转某个 GPIO然后用探头在芯片上方扫描看能不能用脉冲让某个周期的翻转丢失。这个实验的反馈周期短能快速验证探头位置、脉冲参数和触发链路是否都正常。我第一次做这个实验时前 200 个脉冲都没效果后来发现是探头离芯片表面太远差了有七八毫米线圈能量都散在空气里了。把探头降到离芯片封装表面 1mm 以内后第二个脉冲就让翻转丢失了一次。3. 实战操作全流程从扫描到精确定位的完整步骤这一节是整个文章的核心我会把从零开始做一次 EMFI 攻击的完整过程拆开讲包括参数怎么设、如何判断故障是否注入成功、如何从随机命中进化到定点打击。3.1 规划和编写目标程序EMFI 实验最忌讳的就是在目标板上跑巨大复杂的系统然后指望脉冲一击就出现你想要的错。你应该先用一个专门为故障注入设计的裸机程序把敏感操作放在固定位置并且通过串口把每个阶段的执行结果发出来。以 STM32 为例一个特别适合入门的目标程序是这样的程序启动后把某个全局变量state初始化为 0x00000000。主循环里先检查state是否等于 0x12345678如果等于就输出“ACCESS_ALLOWED”并进入死循环如果不等于就输出“ACCESS_DENIED”并继续循环。关键改造手法是在检查之前用一段数据密集型的运算来延长窗口比如循环做一个 SHA-256 的中间运算这样攻击窗口能拉长更容易被脉冲命中。程序准备好之后用示波器连上一个 GPIO 引脚确保它的跳变沿和“检查 比较”这段代码的执行严格对齐。这个 GPIO 同时作为脉冲源的触发信号这样整个系统就能知道攻击窗口什么时候开始。3.2 脉冲参数的初始设置第一次扫描时建议从比较保守的参数开始。我常用的初始参数如下参数初始值说明脉冲峰值电压300V如果打不中再逐步加不要一上来就上高压脉冲宽度20ns过宽容易损坏芯片过窄可能能量不足触发延迟按实测时序设定从 GPIO 拉高到比较指令执行之间探头直径10mm覆盖面积大适合初扫探头高度0.5mm越近效果越强但注意不要压到引脚短路扫描步距1mm先粗扫找敏感区域这个参数组合下大多数目标是“能感觉到干扰但不会轻易挂掉”的状态。如果扫描了整片芯片都没有触发任何异常优先加电压而不是收窄脉宽。我一般每轮增加 100V直到出现以下三种情况之一目标程序输出异常比如打印了错误状态目标程序卡死或复位串口完全无响应表明芯片可能程序跑飞。出现第一种情况说明“软故障”注入成功了出现第二种说明故障足够强但可能打偏了模块出现第三种则要小心说明脉冲能量对系统影响太大长期这么打可能会损坏芯片。3.3 二维扫描找敏感区域粗扫的目标是画出“电磁敏感度地图”。把目标芯片的封装表面划分成网格每个网格点打几十次脉冲每次改变触发延迟或者相位然后记录每次是否触发软故障、是哪种故障模式。扫描这一步手动操作会累到怀疑人生。一个 10mm x 10mm 的芯片用 0.5mm 步距就是 400 个点每个点打 50 次脉冲一共两万次实验这还只是一组参数。所以尽量从一开始就做自动化用 Python 或者 MATLAB 控制定位平台和脉冲源实时把结果记录到数据库里。扫描完成后把故障率高的点标出来。你通常会发现敏感区域并不是芯片几何中心而是集中在某个角落或边缘——那里往往对应着 CPU 核心、SRAM 阵列或者电源分配网络的关键走线。把地图和芯片 die 图叠加起来定位的准确度就会大幅提升。我做过一次真实扫描STM32F407 的敏感区域明显偏向封装的一角跟手册上 CPU 内核的位置吻合。用 1mm 探头在那个位置打脉冲目标程序约 40% 的概率会跳过state比较直接输出“ACCESS_ALLOWED”。但是同样的脉冲打到芯片中央成功率几乎为零。3.4 从“打到敏感区”到“精确命中目标指令”二维扫描只能告诉你哪里敏感但还不能告诉你脉冲是否命中了你想打的那条指令。要做到定点打击需要同时优化两个方面时间维度和空间维度。时间维度上用示波器观察触发 GPIO 和目标指令执行之间的精确微时序。比如你知道“state 比较”那条指令在 GPIO 拉高后的第 12 个时钟周期执行而时钟是 16MHz那么你就要把触发延迟设在 750ns 左右。为了更精确可以在汇编层面调整代码顺序把敏感操作放在一个固定不变的位置然后用不同延迟反复测试找到故障率最高的那个时间窗。空间维度上把探头从 10mm 换成 3mm 或更小的线圈然后在敏感区域附近以 0.1mm 到 0.2mm 步距做精细扫描。小线圈的能量更集中对“打某个寄存器”这种精细操作至关重要。注意小线圈带来的副作用是注入能效下降所以往往需要同步提高脉冲电压。当某组“空间位置 触发延迟 脉冲参数”能稳定让目标程序出现预期错误比如稳定输出“ACCESS_ALLOWED”你就实现了真正意义上的定向故障注入。这时候可以把故障率统计一下通常能做到 10% 到 60% 的单次成功率。多次重复时如果目标没有损坏就可以继续做更高阶的利用。4. 常见问题与排查实录调试 EMFI 平台的那些糟心事EMFI 平台调试的难点在于问题可能出在任何一个环节硬件连接、软件时序、脉冲源性能、探头机械位置、目标程序状态。下面我按自己实际踩过的坑整理成一份速查表再挑几个典型问题详细讲。4.1 故障注入问题速查表现象可能原因初查方法解决方向完全没有任何反应探头离芯片太远用高度规确认探头到封装间距把高度降到 1mm 以内完全没有任何反应触发链路没工作示波器看脉冲源是否收到触发信号检查触发线、阻抗匹配完全没有任何反应脉冲能量太低用电流探头测脉冲峰值提高电压或降低探头直径目标板重启但不报错脉冲打到了复位电路或电源域对比扫描地图缩小探针位置避开复位引脚区域目标程序卡死故障注入到了程序计数器或取指路径观察卡死时的 PC 导出降低电压寻找软故障窗口故障率时高时低触发延迟抖动严重示波器看触发信号抖动用硬件触发减少软件延迟芯片彻底没反应电流异常芯片损坏测量供电电流换芯片降低脉冲电压4.2 排查实录一触发同步的隐蔽延迟第一次做 STM32 实验时我在 GPIO 拉高后设了 800ns 的触发延迟理论上正好打在敏感指令上但打了三百个脉冲都没效果。后来用示波器把触发信号和 GPIO 信号同时抓下来才发现从脉冲源收到触发到实际放电中间还有大约 300ns 的内部延迟。这 300ns 就是脉冲源里高压开关电路本身的导通时间如果没算进去你的时间窗口就完全偏了。解决方案是先用示波器测出这个“固有延迟”把它从预设的触发延迟里减掉。比如你实际想延迟 800ns示波器测出固有延迟 300ns那你在软件里的触发延迟就要设成 500ns。这类延迟会因为温度、电压波动而变化所以严谨的做法是在实验过程中周期性用示波器校验实际脉冲时刻。4.3 排查实录二探头碰到封装引脚造成短路用大直径探头扫描时很容易压到芯片周围的引脚尤其是 QFP 这类有外露引脚的封装。引脚被金属探头接触到后如果脉冲电压够高可能直接通过引脚放电到芯片内部轻则让程序跑飞重则击穿引脚驱动电路。我后来习惯在探头表面贴一层极薄的绝缘胶带既不影响磁场耦合又能避免直接接触和放电。如果你发现扫描过程中目标板电流异常波动或者某个 GPIO 引脚驱动能力变弱了九成是探头接触过引脚造成微损坏。4.4 排查实录三高压脉冲源的稳定性自制的雪崩晶体管阵列在高重复频率下会出现波形不一致的问题。比如你设置脉冲频率 10Hz前 10 个脉冲是 300V后面突然变成 250V这种不稳定性会让扫描结果充满噪声。解决方法是把重复频率降低到 1Hz 到 2Hz并且在每次实验前后各抓一次波形记录到日志里。如果脉冲幅度波动超过 5%就要检查高压电源的纹波、晶体管的工作温度或者把储能电容换成低 ESR 的型号。不要小看这一条我在做自动化扫描时有相当长一段时间就是被脉冲源的不稳定坑了导致同一位置打出来的故障率忽高忽低根本没法分析。5. 从攻击思路到防御对策EMFI 在真实世界里的价值很多人以为 EMFI 只是黑客用来制造攻击的真实情况远不止如此。在芯片设计、车规电子、金融终端、智能门锁这些领域EMFI 已经成为实验室安全验证的标准科目。理解攻击手段最终是为了知道怎么防御所以这一节我会同时讲讲攻击视角和防御对策。5.1 典型应用场景一安全启动绕过安全启动Secure Boot的目标是保证 CPU 只执行被签名的固件。常见实现方式是 BootROM 先读取固件头部的签名和公钥验签通过后再跳转执行。攻击者的目标就是让“验签通过”这个判定在特定时刻变成“真”。实际做的时候攻击者会在签名校验函数返回后、跳转指令执行前注入一次电磁故障。如果脉冲让标志寄存器的 Z 位或结果寄存器发生翻转BootROM 就可能把无效签名当成有效签名。这个攻击在多个真实 MCU 上都复现过防御措施包括在签名校验结果上做双重冗余校验、使用带硬件错误检测的状态机、对关键标志位加 ECC 保护。5.2 典型应用场景二加密算法的故障输出在 AES 或其他分组密码执行过程中注入故障可以诱导出错误密文。如果攻击者能拿到同一明文在正常和故障两种状态下的密文通过差分故障分析DFA可能把密钥恢复出来。这类攻击对时间精度的要求很高因为故障必须在某一轮加密中注入太早或太晚都无效。EMFI 攻击者会先分析密码实现的时序找到关键轮的循环计数位置然后用触发同步精准注入。防御思路大多围绕“结果校验”展开加密后再解密一次或者运行两次加密两次结果不一致就抛出错误。这个方法在低成本芯片里很常见但代价是性能和多一倍的能耗。5.3 缓解 EMFI 的工程化措施从防御方角度来说完全消除 EMFI 风险是几乎不可能的因为任何物理芯片都对外部电磁场有响应。工程上要做的是把攻击难度提高到攻击者不愿承受的程度。屏蔽层在芯片封装或 PCB 上增加金属屏蔽罩可以大幅衰减外部电磁场耦合。很多安全芯片内部就会做一层金属屏蔽层覆盖敏感模块的走线和存储单元。故障传感器在芯片内部放置检测电磁干扰的传感器比如测量电源电流突变的电路、检测时钟抖动的监控器。传感器一旦触发芯片就执行安全复位或者擦除密钥。冗余执行与交叉校验对安全关键的判定执行两次以上结果必须全部一致才继续。这样可以有效应对单点故障注入但会增加时间开销。随机化时序把敏感操作的时间打散让攻击者难以预判注入窗口。这个方法的有效性取决于随机源的熵如果随机源太弱攻击者多采样几次还是能推算出来。程序层面的防御在比较密钥或签名时使用常数时间比较并且把“验证通过/失败”的状态分散在多个寄存器中不要用单一布尔变量。作为研究人员如果你在做自己的产品安全测试我的建议是至少跑一轮 EMFI 扫描把敏感区域地图和故障注入成功率记录下来归档到产品安全文档里。很多安全标准比如支付行业的 PCI 相关规范或者车规的 ISO 21434 里的部分要求其实都对物理攻击测试有要求提前积累数据会省很多后续合规的功夫。6. 我的实操建议与进阶方向文章写到这最后分享几个我在实际使用中总结出来的经验和后续可以继续深入的方向。第一个建议是永远从最简单的目标开始验证系统链路。我不止一次见过有人花大价钱买了高级设备结果一上来就打复杂的手机 SoC连脉冲有没有真正到达裸片都说不清楚折腾几个月在原点打转。先用几十块钱的 MCU 验证好整个平台再挑战更高难度的目标这个顺序能省下大量时间。第二个建议是记录一切。包括脉冲参数、探头坐标、目标程序版本、触发延迟、故障现象、芯片编号。我通常用 CSV 文件或者 SQLite 数据库记录每一次实验。EMFI 实验的重复性没有纯软件实验那么高同一个位置打两次结果可能不一样只有靠足够多的样本和完整的元数据才能得出可靠结论。第三个建议是多尝试不同的触发策略。很多人习惯用 GPIO 边沿触发但在某些目标上芯片的调试接口或电源电流曲线反而能提供更稳定、更隐蔽的触发点。如果你对精确时间窗口的要求极高可以在汇编层面对目标程序做插桩增加一个专门的同步指令窗口比如 NOP 指令这样窗口时间更容易对齐。后续进阶方向我建议关注这几个方向3D 电磁场仿真用仿真软件对探头和芯片封装建模预测脉冲耦合到内部节点的强度这会大幅降低盲扫成本。自动攻击平台把二维扫描、参数搜索和故障分类全部用机器学习算法自动优化。比如用贝叶斯优化来寻找“最容易让目标出错”的参数组合效率和手动调参完全不是一个量级。不同封装的注入策略QFP、BGA、CSP 各不一样BGA 由于被球形焊点遮挡注入难度更高要研究背孔或侧面注入的可能。组合攻击把 EMFI 和电压毛刺、侧信道分析组合起来。比如先用侧信道分析获取密钥部分信息再通过故障注入跳过剩余的校验环节这种组合思路在高级安全评估里很常见。如果让我总结一句最想对新入门的人说的话EMFI 是一个高度工程化的领域别把它想成玄学也别指望一次就成功。你需要的是系统性的实验方法、精确的观测手段和足够的耐心。把上面这些参数、流程、排查思路吃透你基本就有能力在实验室里复现出漂亮的故障注入效果了。