题目3:目标板设置——SimpleSerial协议、固件烧录、通信验证
好,到了第三个题目。前面我们把ChipWhisperer开发环境搭好了,也跑通了第一个捕获脚本。但说实话,那会儿你手里的目标板可能还是个“裸板”——没烧固件,也没确认通信是否正常。
这一章,我们就来解决这个问题。我会带你走一遍目标板的设置流程:先搞懂SimpleSerial协议是怎么回事,然后把固件烧进去,最后验证通信是否畅通。嗯,这三步走完,你的目标板才算真正“活”了。
3.1 SimpleSerial协议——侧信道攻击的“通用语言”
先聊聊SimpleSerial协议。你可能会问:为什么ChipWhisperer要用一个自己的协议?直接用UART不行吗?
其实说白了,SimpleSerial就是一套轻量级的通信约定。它定义了三件事:
- 命令格式:主机怎么发指令给目标板
- 响应格式:目标板怎么回数据给主机
- 同步机制:如何保证收发双方步调一致
我个人习惯把SimpleSerial理解成“侧信道攻击的通用语言”。不管目标板是AVR、ARM还是RISC-V,只要它支持SimpleSerial,ChipWhisperer就能跟它对话。
核心命令格式:
主机发送:p\x00\x01\x02...\n(p开头,后面跟明文数据,换行结束)
目标板回复:r\x00\x01\x02...\n(r开头,后面跟密文数据,换行结束)
举个例子。假设我们要加密一个16字节的明文:
# 主机发送
p\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\n
# 目标板回复
r\x3c\x4d\x5e\x6f...\n
你看,格式非常简单。p代表“plaintext”(明文),r代表“response”(响应)。换行符\n是结束标志。
小技巧:我在项目中遇到过一个问题——目标板回复总是丢字节。后来发现是换行符没处理好。SimpleSerial要求必须用\n(0x0A),不能用\r\n。这个坑我踩过,你注意一下。
3.2 固件烧录——让目标板“开口说话”
协议搞懂了,接下来就是把支持SimpleSerial的固件烧进目标板。ChipWhisperer官方提供了现成的固件,我们直接用就行。
3.2.1 选择正确的固件
ChipWhisperer的固件放在chipwhisperer/hardware/victims/firmware/目录下。针对不同的目标板,有不同的子目录:
| 目标板型号 | 固件目录 | 说明 |
|---|---|---|
| CW308T-AVR | avr/ | ATmega328P,最常用 |
| CW308T-STM32F | stm32f/ | STM32F303,ARM Cortex-M4 |
| CW308T-XMEGA | xmega/ | ATxmega128D4 |
我建议初学者先用AVR版本。为什么?因为AVR的SimpleSerial固件最成熟,文档也最全。我自己第一次做侧信道攻击时,就是用AVR起步的。
3.2.2 烧录步骤
烧录固件有两种方式:
- 通过ChipWhisperer的编程器(推荐)
- 通过外部编程器(比如AVR ISP)
这里我重点讲第一种,因为最方便。
# 1. 连接目标板到ChipWhisperer
# 确保跳线设置正确:VTarget、GND、编程接口
# 2. 打开ChipWhisperer的编程工具
import chipwhisperer as cw
scope = cw.scope()
target = cw.target(scope)
# 3. 烧录固件
cw.program_target(scope, cw.programmers.AVRProgrammer,
"chipwhisperer/hardware/victims/firmware/avr/simpleserial-aes.hex")
烧录过程中,你会看到LED闪烁。如果一切顺利,终端会打印“Programming successful”。
注意:烧录前一定要确认目标板的供电电压。ChipWhisperer默认输出3.3V,但有些目标板需要5V。我曾经因为电压不匹配,烧坏过一块AVR芯片。嗯,从那以后我每次都会先量一下VTarget。
3.3 通信验证——确认目标板“在线”
固件烧好了,怎么知道它真的在工作?我们需要做一次通信验证。
3.3.1 手动发送测试命令
最简单的验证方式:用Python脚本发一条SimpleSerial命令,看目标板是否回复。
import chipwhisperer as cw
scope = cw.scope()
target = cw.target(scope)
# 设置通信参数
scope.io.hw_baud = 38400 # 波特率,与固件一致
target.baud = 38400
# 发送测试命令
test_plaintext = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'
target.simpleserial_write('p', test_plaintext)
# 读取回复
resp = target.simpleserial_read('r', 16)
print(f"收到回复: {resp.hex()}")
如果输出类似收到回复: 3c4d5e6f...,说明通信正常。如果超时或报错,那就得排查问题了。
3.3.2 常见问题排查
通信失败时,别慌。我列几个最常见的坑:
- 波特率不匹配:固件默认38400,但有些修改过的固件可能用115200。检查一下。
- 接线松动:TX/RX/GND三根线,缺一不可。我遇到过GND没接好,数据全乱码。
- 固件版本不对:确认你烧的是SimpleSerial固件,不是其他测试固件。
- 目标板没上电:这个听起来很蠢,但我真的犯过。检查LED是否亮起。
调试技巧:如果通信不稳定,可以用示波器看TX/RX引脚的波形。正常的数据帧应该清晰可见,波特率误差不超过2%。我习惯先用逻辑分析仪抓一下,确认物理层没问题,再查软件层。
3.4 本章知识体系
为了让你更直观地理解本章内容,我画了一张流程图:
这张图把本章的三个核心环节串起来了。从左到右,先理解协议,再烧固件,最后验证通信。验证通过,目标板就绪;验证失败,回到排查环节。
3.5 实战小结
这一章的内容,说白了就是三件事:
- SimpleSerial协议:p发明文,r收密文,\n结尾。记住这个格式就行。
- 固件烧录:选对固件,接好线,跑
program_target。注意电压和波特率。 - 通信验证:发一条命令,看回复。不行就查接线、波特率、固件版本。
我个人觉得,通信验证这一步最容易出问题,但也最容易解决。你只要记住:先查物理层(接线、电压),再查协议层(波特率、格式),最后查固件层(版本、配置)。按这个顺序排查,90%的问题都能搞定。
嗯,目标板设置好了,接下来就可以真正开始捕获电磁辐射信号了。不过那是下一章的事,咱们先把眼前这步走扎实。