再探Alti-2高度表:通信协议还原与月计数器溢出BUG
上一篇逆向分析记录里,通过MITM串口桥抓到了Alti-2高度表和PC之间的加密通信流量,确认了跳伞日志数据没有丢失。
这次还原了整个通信协议,写了一个跨平台的Python库 pyaltitool,可以直接在macOS/Linux/Windows上连接高度表读取数据。顺便也搞清楚了2025年8月开始困扰所有Alti-2用户的那个BUG到底是怎么回事。
通信协议
Alti-2的Atlas系列高度表通过FTDI芯片提供USB串口通信,物理层参数是57600 baud, 8N1, RTS/CTS硬件流控。整个通信过程分五步:
1. DTR唤醒
高度表插入USB后默认只充电,处于休眠状态。PC侧需要Toggle DTR信号线来唤醒设备进入通信模式。
2. ASCII握手
唤醒后发送ASCII握手串018080,设备响应一个32字节的Type 0 Record,包含产品型号、固件版本、序列号、总跳数、Logbook内存起始地址等关键信息。
3. Session Key协商
Session Key的派生基于Type 0 Record和产品型号对应的预置seed。具体来说是取Type 0中的特定字段,与seed组合后生成一组16字节XTEA密钥。这个过程完全在PC侧完成,设备侧用同样的算法从自己的数据派生出相同的密钥,不需要额外的密钥交换通信。
上一篇提到的”旧协议解密失效”就是因为新型号更换了seed,算法本身没有变。从官方固件更新工具的反编译结果中可以直接得到新的seed值。
4. 加密通信
后续所有指令都是32字节的XTEA加密包,逐字节发送,每发一字节都要polling CTS流控信号。指令集沿用了旧的CATI-2协议格式,包括READ_MEMORY、WRITE_MEMORY、读取设备时钟等。数据区域是FRAM,Logbook的每条跳伞记录占22字节,按地址顺序排列。
XTEA解密后的指令结构很简单,以上一篇抓到的那条READ_MEMORY为例:
1 | 07 A0 0E 00 00 00 02 B0 00 00 00 00 00 00 00 00 ... |
5. 退出
发送\x01EXIT结束会话,设备回到充电休眠模式。
设备有10-15秒的空闲超时,超时后断开通信。pyaltitool在后台跑了一个keepalive线程,定期发datetime ping维持连接。大批量读取Logbook时,每100条记录需要主动重连一次,因为持续传输会导致设备串口状态不稳定。
月计数器溢出BUG
这就是2025年8月开始Alti-2高度表集体出问题的根本原因,一个 Y2K like 溢出BUG。
数据结构
每条22字节的跳伞记录中,byte 2的设计是这样的:
1 | byte 2: [bit 7: deleted flag] [bits 6-0: month counter] |
Month counter是一个从2015年1月开始的月份计数器,7-bit范围0-127,对应2015年1月到2025年7月。bit 7被保留为deleted标志位,用于标记记录是否已删除。
问题
固件的写入代码把month counter当作完整的8-bit值写入,完全无视了bit 7的保留用途。当计数器走到128(2025年8月),bit 7被置1:
1 | mc = 127 (2025-07): byte 2 = 0x7F = 0_1111111 → deleted=0, mc=127 ✓ |
于是从2025年8月起,所有新记录都被设备自己当成了”已删除”,日期信息也因为截断到7-bit而错乱。设备尝试显示这些记录时直接crash——大概是mc=0落到了某个无效的数组索引或空指针。这就是为什么在高度表上点View会卡一下然后退回来。
官方修复
1.0.10固件更新修了crash问题,但并没有恢复受影响记录的日期信息——这些记录在官方工具中仍然显示为deleted。
pyaltitool的修复
每条跳伞记录里存了它被记录时的固件版本号。利用这个信息,可以针对不同固件版本做条件解析:
1 | sw_major = (word3 >> 11) & 0x0F # firmware major version from the record |
对旧固件写入的记录,取完整的8-bit值作为month counter,不把bit 7当deleted flag。空记录(jump_number == 0)仍然识别为deleted。这样就能正确恢复所有溢出影响的跳伞日期数据了。
影响窗口
8-bit month counter的范围是0-255,对应2015年1月到2036年3月。如果到那时候这个表还在用,同样的溢出会在month counter 256处再来一次。彻底修复需要扩展字段位宽或者改用其他日期存储格式。
pyaltitool
基于以上协议还原和BUG修复,写了 pyaltitool,纯Python实现,仅依赖pyserial,跨平台支持macOS/Linux/Windows。
功能包括:读取设备信息、导出跳伞日志(支持CSV)、读取设备时钟、读取自定义名称表(飞机、DZ、告警)、原始FRAM内存读写。自动检测串口,后台keepalive,断线自动重连。
下面是从一台Atlas 2上读取到的一条实际跳伞记录,日期和各项数据均已正确恢复:
连上设备后可以直接用交互式命令行:
1 | altitool> info # 设备信息 |
也可以作为库使用:
1 | from pyaltitool import AltitoolDevice, auto_detect_port |
源码和完整文档在 GitHub。
References
5BytesHook. pyaltitool - Alti-2 Altimeter Communication Library. GitHub. https://github.com/5BytesHook/pyaltitool
Lobanov, A. alti2reader - Alti-2 Neptune Data Reader. GitHub. https://github.com/evilwombat/alti2reader
Wheeler, D. & Needham, R. Correction to XTEA. Computer Laboratory, Cambridge University. https://www.movable-type.co.uk/scripts/xxtea.pdf