3、ChipWhisperer入门:架构、固件烧录与SPA基础

好,咱们今天来聊聊ChipWhisperer。这东西在硬件安全圈子里,基本算是人手一套的入门利器了。我当年第一次接触侧信道攻击,就是拿ChipWhisperer Lite开的刀。说实话,它把很多复杂的射频、模拟前端问题都给封装好了,让你能专注于攻击逻辑本身。

这一节,我会带你走一遍ChipWhisperer的核心架构、怎么给它烧固件、怎么捕获目标板的通信,最后再上手一个最简单的功耗分析——SPA。嗯,咱们一步步来。

3.1 ChipWhisperer架构:它到底是个啥?

ChipWhisperer本质上是一套开源的侧信道攻击与故障注入平台。它不是一个单一的工具,而是一个生态。核心硬件是那个带FPGA的板子,比如CW1173(Lite)或者CW1200(Pro)。

它的架构可以拆成三块:

  • 目标板接口:用来连接你要攻击的芯片,比如AVR、ARM或者FPGA。它提供时钟、电源和通信引脚。
  • 模拟采集前端:这是灵魂。它负责把目标芯片的功耗波动(通过串联电阻上的电压降)放大、滤波,然后送给ADC(模数转换器)。ChipWhisperer Lite用的是10位ADC,采样率能到20MS/s左右。
  • FPGA与USB桥接:FPGA负责实时控制采样时序,把数据打包通过USB发给电脑。电脑上的Python库(cw库)再解析这些数据。

我个人习惯把ChipWhisperer理解成一个“示波器+逻辑分析仪+电源”的三合一设备,只不过它专门为侧信道攻击做了优化。

核心知识点: 你不需要自己搭运放电路,ChipWhisperer的模拟前端已经帮你做了信号调理。你只需要把目标板插上去,配置好采样率就行。

下面这张图是我画的ChipWhisperer与目标板交互的简化流程,你看一眼就明白了:

ChipWhisperer 与目标板交互流程 电脑端 Python cw库 USB ChipWhisperer FPGA + ADC 模拟前端(放大/滤波) 时钟/触发控制 CLK/DATA/TRIG 目标板 AVR / ARM / FPGA 串行通信(UART/SPI) 捕获到的功耗轨迹示例 时间 (采样点) 电压 (功耗)

3.2 固件烧录:让目标板跑起来

拿到ChipWhisperer之后,第一件事不是抓数据,而是给目标板烧固件。ChipWhisperer套件里通常带一块目标板,比如XMEGA或者STM32F3。你得先把你的攻击代码(比如一个简单的AES加密程序)烧进去。

烧录方式有两种:

  • 通过ChipWhisperer直接烧录:它自带一个编程接口,可以当调试器用。你只需要在Python脚本里调用 cw.program_target() 就行。
  • 用外部编程器:比如J-Link或者AVR ISP。我个人更推荐用ChipWhisperer自带的,省事。

举个例子,烧录一个AES固件到XMEGA目标板:

import chipwhisperer as cw

# 连接ChipWhisperer
scope = cw.scope()
target = cw.target(scope)

# 烧录固件
fw_path = "firmware/simpleserial-aes-CW303.hex"
cw.program_target(scope, cw.programmers.XMEGA, fw_path)

print("固件烧录完成!")

小提示: 烧录前记得检查目标板的跳线。XMEGA板子上有个VTarget跳线,如果没接好,烧录会失败。我曾经在这上面卡了半小时,后来发现是跳线帽松了。

烧录完成后,目标板就会开始运行你的程序。它通常会在串口上等待你的明文输入,然后返回密文。ChipWhisperer的Python库会自动处理这些握手协议。

3.3 捕获目标板通信:抓取功耗轨迹

固件跑起来了,接下来就是捕获。说白了,就是让ChipWhisperer在目标板执行加密操作时,同步采集它的功耗波动。

捕获流程大致如下:

  1. 配置采样参数:设置采样率(比如20MS/s)、采样点数(比如5000个点)、触发条件。
  2. 发送明文:通过串口把明文发给目标板。
  3. 等待触发:目标板收到明文后,会拉高一个GPIO引脚(触发信号)。ChipWhisperer检测到这个上升沿,就开始采集。
  4. 读取轨迹:采集完成后,把数据从FPGA的缓冲区读回电脑。

代码实现起来很简洁:

# 配置scope
scope.gain.gain = 45  # 放大倍数
scope.adc.samples = 5000  # 采样点数
scope.adc.offset = 0  # 偏移
scope.clock.clkgen_freq = 7.37e6  # 目标板时钟频率

# 捕获一条轨迹
target.simpleserial_write('p', plaintext)  # 发送明文
scope.arm()  # 准备触发
target.simpleserial_wait_ack()  # 等待目标板响应
trace = scope.capture()  # 捕获功耗轨迹

print(f"捕获到 {len(trace)} 个采样点")

注意: 触发信号的时序很关键。如果触发早了,你会抓到一堆空闲功耗;触发晚了,加密操作已经结束了。我建议你先用示波器看一下目标板的触发引脚,确认它在你想要的时间点拉高。

3.4 简单功耗分析(SPA)基础:一眼看穿操作

SPA,全称Simple Power Analysis,简单功耗分析。它不依赖统计,而是直接观察单条功耗轨迹的形状,来推断芯片内部执行了什么操作。

为什么能看出来?因为不同的指令消耗的电流不一样。比如:

  • 乘法指令加法指令功耗高。
  • 条件跳转(if-else)会导致功耗轨迹出现明显的分叉。
  • 查表操作(比如AES的S盒)会有一连串规律性的尖峰。

我举个例子。你看下面这条轨迹,是AES加密的第一轮:

# 绘制轨迹
import matplotlib.pyplot as plt
plt.plot(trace)
plt.xlabel("采样点")
plt.ylabel("功耗 (ADC值)")
plt.title("AES第一轮功耗轨迹")
plt.show()

你会看到一串重复的波形,每个波形对应一个字节的S盒查表操作。如果你数一下波峰的数量,正好是16个——对应AES的16字节状态矩阵。

实战经验: 我在一次测试中,发现目标芯片的SPA轨迹里多了一个波峰。后来排查发现,是固件里多了一个没必要的循环。你看,SPA不仅能用来攻击,还能用来逆向固件的执行流程。

SPA的局限性也很明显:它只能看到宏观的操作序列,看不到具体的数值。比如你能看出芯片在执行S盒查表,但看不出查的是哪个值。要提取密钥,还得靠DPA(差分功耗分析)或者CPA(相关功耗分析)。

不过,SPA是入门侧信道攻击的第一步。你想想看,如果你连功耗轨迹都抓不稳,后面的统计分析就更无从谈起了。

3.5 避坑指南:我踩过的几个坑

最后,分享几个我当年入门时踩过的坑:

  • 采样率不够:如果目标板时钟是7.37MHz,你的采样率至少要到20MS/s,否则抓不到细节。我一开始用10MS/s,结果轨迹糊成一团。
  • 触发信号没接:ChipWhisperer默认用目标板的触发引脚。如果你没接这根线,它永远不会开始采集。嗯,这个我犯过两次。
  • 电源噪声干扰:目标板如果用USB供电,噪声会很大。我建议用外部稳压电源,或者加一个LC滤波器。

好了,这一节的内容就到这。你只要把ChipWhisperer的架构搞明白,固件烧录走一遍,再亲手抓几条轨迹看看,SPA的基础就算打牢了。

专注资料整理