最近在网上看到有人卖垃圾电子墨水价签,个位数人民币一个,看上去还不错,就买了一堆。
Hanshow Stellar-M
网上能搜索到一些关于这个价签的资料,已经有人尝试自己重写 MSP430 固件的方法把它用了起来,也有人直接拆了 EPD 出来自己画驱动板来使用,不过并没有关于原厂固件下私有 2.4G 通信协议的资料。
为了更方便的使用这些灵车 ESL,我们几个小伙伴一拍即合,开始了对这个无线协议进行逆向工程。由于我这里没有能调试 MSP430 的调试器,所以固件导出、分析的工作就交给了别人。而我,则先开始对 ESL 的空口进行分析。
Use Logic Analyzer to sniff the SPI between MSP430 and A7106
首先,我们先用逻辑分析仪抓取了无线芯片初始化的流程,了解了私有协议的工作频率,速率,模式等。给我们向 ESL 下发数据提供的基础参数。
RX 频率 | 2480.5Mhz |
RX 速率 | 500Kbps |
RX 调制方式 | FSK |
RX 窗口 | 每 8192ms 有 3ms 接收窗口 |
IO1 | 0:待机;1:发射或接收 |
IO2 | 0:待机;1:收到数据且 ID 正确 |
之后,经过长时间抓取 SPI 总线,发现了 ESL 每隔大约 180 秒会对外向特定 ID 发射包含自身接收消息使用的 ID 的消息。抓取多个 ESL 的 SPI 后,发现发送时设置的 ID 是相同的。
Second frame received at ~182.6s
之后,设置抓 SPI 的示波器触发为看到启用发射模式的命令,同时使用它的触发输出,去触发另一台示波器。另一台示波器直接接 A7106 的 RF 输出口。
Trigger Point
2.4G RF Out Direct Sampling
FFT
采集到原始 RF 信号后,对数据进行 FFT,可以看到发射频率中心在 2.401Ghz 左右。然后将数据导入 GNU Octave,把 2.401Ghz 信号 DDC 到 0Hz,把 20GSps 信号 Decimate 到 10MSps,然后导出 IQ。然后将 IQ 数据导入 Universal Radio Hacker 进行 Demodulation 和分析。
原始数据可以(点击下载),HDF5 格式,可以 Matlab 或者 GNU Octave 进行处理和分析。不想预处理数据想直接用 URH 来玩的可以(点击下载)处理后的数据。
Universal Radio Hacker
从 URH 得到的数据和分析 SPI 总线预测的数据相同,格式相同。
接下来使用 URH 构造了一个 ID 和 Checksum 正确的数据,使用 USRP 将数据发给了 ESL。ESL 在被 A7106 唤醒后,会直接清除掉触发,然后设置 RX 长度为 2,重新进入 RX 模式等待数据。
在再一次构造了一个 Payload 长度 2 Bytes 的数据后,在合适的窗口发送了两遍,可以看到 ESL CPU 使用 SPI 从 A7106 将第二遍的数据 Payload 取回。
Successfully make MSP430 to get RF data from A7106 RX FIFO
接下来就需要猜测这两个 Bytes 的作用了。目前的思路一个是 Fuzz 数据,然后看行为。但是芯片的 RX Window 很窄,导致如果要这么测试需要很多设备的配合。比如示波器做 SPI 关键词触发,找到 RX Window,然后控制 USRP 发射数据,接下来观测 SPI 上是否有进一步行为。如果没有,控制电源断电重新上电,再次测试。另外的思路就是逆向分析固件。因为根据目前分析的一些行为,可以很容易在固件中找到对应特征,找到对应的 Subroutine。目前固件已经成功 Dump 出,有小伙伴已经开始逆向。
目前来说,已经大致搞清楚了每 3 分钟的 Beacon 的格式,如下:
Bytes | Example 1 | Example 2 | Function |
---|
0 | C0 | 0C | UNKNOWN |
1 | 40 | 40 | UNKNOWN |
2 | 50 | 50 | RECEIVER ID BYTE 1 |
3 | 41 | 41 | RECEIVER ID BYTE 2 |
4 | 83 | 81 | RECEIVER ID BYTE 3 |
5 | 66 | 66 | RECEIVER ID BYTE 4 |
6 | 53 | 50 | ESL ID BYTE 1 |
7 | A4 | C4 | ESL ID BYTE 2 |
8 | FE | 23 | ESL ID BYTE 3 |
9 | 0A | 0B | ESL ID BYTE 4 |
10 | A1 | A1 | CHANNEL ID |
11 | 22 | 31 | UNKNOWN |
12 | 1E | 21 | VOLTAGE |
13 | 00 | 00 | UNKNOWN |
14 | BA | 61 | CRC-16/XMODEM LOW BYTE |
15 | A3 | 49 | CRC-16/XMODEM HIGH BYTE |
ESL Periodic Beacon Format
其中 RECEIVER ID 和 CHANNEL ID 用于从基站给 ESL 的下行通信,A7106 会使用 RECEIVER ID 去 Filter RX 数据,CHANNEL ID 为 下行频率,计算方法为 2400Mhz + 0.5Mhz * CHANNEL ID。然后 ESL ID 为标签硬件序列号的后十位数字转换成 HEX 的结果。VOLTAGE 为电池电压,直接从 HEX 转换为 DEC 后除以 10 可以得出当前电池电压。CRC-16 为小端序,使用 XMODEM 的计算参数。