nRF52系列电压故障注入(补档)
本文针对nRF52840进行电压故障注入,这也是本人故障注入的入门固件。
一、信息收集
- 芯片:Nordic nRF52840(ARM Cortex-M系列,没有BootROM),广泛应用于USB dongle、AirTag、智能手环等设备。
- 目的:绕过芯片的固件读保护。
- 方法:使用电压故障注入重新开启已被关闭的SWD调试接口,在调试器下读出固件。
二、工具使用
1.J-Flash
J-link的SWD标准接线如下:
连接到J-Flash软件后,将编译好的 hex 格式固件如blink.hex(闪灯效果)烧写到USB dongle中。烧录后须重新上电显示效果。
2.nrfjprog
芯片擦除:nrfjprog -f NRF52 --eraseall
固件烧录:nrfjprog -f nRF52 --program blink.hex --chiperase --verify
读取内存:nrfjprog -f nRF52 --memrd 0x10001208
写入内存:nrfjprog -f nRF52 --memwr 0x10001208 --val 0xFFFFFF00
三、APPROTECT 固件读保护机制
调试器访问芯片内部资源完成调试的原理如下:
其中DP 作为调试器与芯片之间的桥梁,处理通信和选择具体的 AP;AP 执行实际的调试操作,访问内存、寄存器等资源。
UICR开关保护原理:
AHB-AP 与 DAP bus 之间存在一个类似开关的装置 ,芯片根据 UICR 中 APPROTECT 的值来决定它们通信的开/关,关闭时不能读取flash。而解除保护的recover的原理是通过CTRL-AP擦除固件内容,此时固件可读但无实际内容。
既然 APPROTECT 是一个由用户配置的寄存器,芯片肯定要在上电后读取寄存器的值来判断是否开启保护。可以在芯片读取寄存器值时注入一个故障,使其判断出错或跳过该逻辑,达到绕过固件读保护的目的。
四、电压故障注入实践
1.物理毛刺位置
2.毛刺时间位置
3.问题总结
- 如何控制设备重启:通过 PowerShorter 的 GPIO 为 Dongle 供电,Python 代码控制 GPIO;
- 打哪个地方的电压、如何打:打 DEC1,短接 DEC1 和 GND 使其电压短暂拉低;
- 什么时候打故障:以 GPIO 供电上升沿作为触发,设置延时,故障打在 DEC1 下降沿附近(设置延时的目的是因为从GPIO 供电到保护判断逻辑处有时间差);
- 怎么判断是否打成功了:openocd 连接 SWD 读取固件,dump 成功则故障注入成功(openocd的使用需要先将jlink 驱动替换为winUSB)。
# 指定定调试器为jlink、调试接口为 SWD、调试芯片为 nrf52 系列
openocd -f interface/jlink.cfg -c "transport select swd" -f target/nrf52.cfg
# 指定dump的固件起始地址0x0与大小0x1000,并提取出来
openocd -f interface/jlink.cfg -c "transport select swd" -f target/nrf52.cfg -c "init;dump_image nrf_flash.bin 0x0 0x1000;exit"
4.接线图
另外需要示波器接到DEC1处用以显示波形。
5.故障注入
jupyter lab中利用python代码实现故障注入,需要powershell端口、毛刺延时范围、毛刺宽度范围,直到打出如下波形即为成功:
五、总结
- 上电执行的代码是我们写在Flash中的代码,因此配置保护的逻辑是由硬件实现的。
- 通过编写代码拉高GPIO得到了软件执行的时间位置,以此定位了硬件逻辑执行的时间范围,再结合芯片电磁功耗分析,确定了可能的读取UICR 配置固件读保护的硬件逻辑时间点。