逆向工程解析排队显示协议:BCD4编码与进位校验算法
一位工程师在没有文档的情况下,成功逆向解析了一套专有的排队显示协议。该协议采用BCD4编码,每个数据位占用一个完整字节,以增强在1200波特率长距离RS-232线路上的抗噪能力。数据包结构为33字节,包含起始标记、数字位、窗口号和带进位机制的校验和字段。
BCD4:确保可靠传输的编码方案
该协议采用硬件级抗噪方法:每个数字(0-15)的比特位被编码为一个字节。0x7F表示1(七个1形成清晰脉冲),0x00表示0。这样就将一个4位值扩展为4字节。
编码示例:
| 数字 | 比特位 | BCD4字节序列 |
|------|--------|--------------|
| 0 | 0000 | 00 00 00 00 |
| 1 | 0001 | 7F 00 00 00 |
| 2 | 0010 | 00 7F 00 00 |
| 5 | 0101 | 7F 00 7F 00 |
| 9 | 1001 | 7F 00 00 7F |
| 12 | 1100 | 00 00 7F 7F |
Python实现代码:
def _bcd4(value: int) -> bytes:
return bytes([0x7F if value & (1 << i) else 0x00 for i in range(4)])
print(_bcd4(5).hex(' ')) # 7f 00 7f 00
print(_bcd4(9).hex(' ')) # 7f 00 00 7f
1200波特率在保证可靠性的同时牺牲了传输速率。
数字显示的数据包结构
33字节数据包用于在窗口显示数字:
- 字节0:
0x55— 起始标记 - 字节1-4:模式头
- 字节5-8:BCD4(个位数字)
- 字节9-12:BCD4(十位数字)
- 字节13-16:BCD4(百位数字)
- 字节17-20:BCD4(窗口个位数字)
- 字节21-24:BCD4(窗口十位数字)
- 字节25-28:BCD4(c1) — 校验和低位部分
- 字节29-32:BCD4(c2) — 带进位的高位部分
示例:在19号窗口显示数字487:
55 00 7F 00 00 # 头部
7F 7F 7F 00 # BCD4(7)
00 00 00 7F # BCD4(8)
00 00 7F 00 # BCD4(4)
7F 00 00 7F # BCD4(9)
7F 00 00 00 # BCD4(1)
[校验和字段]
带进位机制的校验和计算
校验和字段c1和c2构成8位值,采用进位机制:
- 计算原始c1值作为数据包字段的线性组合
- 如果原始c1 ≥ 16:进位 = 1,c1 = 原始c1 - 16
- 否则:进位 = 0,c1 = 原始c1
- c2根据其他字段的进位计算
进位发生在80-90等数字,具体取决于窗口编号。AI(Claude)通过30个数据包样本验证了该模式:两个4位半字节采用类似算术运算的进位机制。
“所有窗口”模式(25字节)无进位,计算公式更简单。
窗口编程模式使用两个独立的进位链,包含乘法和常数:
- 链A:从W_lo计算原始A,进位_A = 原始A >> 4,字段_A1 = 原始A & 0xF,字段_A2从W_hi和进位_A计算
- 链B:类似处理另一个线性函数
数据包组装与发送
数据包组装函数:
def build_window_packet(window: int, number: int) -> bytes:
d1 = number % 10
d2 = (number // 10) % 10
d3 = (number // 100) % 10
w_lo = window % 10
w_hi = window // 10
c1, c2 = _checksum(d1, d2, d3, w_lo, w_hi)
packet = bytearray(b'\x55\x00\x7F\x00\x00')
packet += _bcd4(d1) + _bcd4(d2) + _bcd4(d3)
packet += _bcd4(w_lo) + _bcd4(w_hi)
packet += _bcd4(c1) + _bcd4(c2)
assert len(packet) == 33
return bytes(packet)
数据包通过COM端口发送。
集成到Web系统
Python服务器接收HTTP POST请求:
POST / {"window": 5, "ticket": "487"}
服务器解析JSON,构建数据包并写入端口。心跳机制维持连接:
- 正常时60秒间隔
- 错误时10秒重试
def _heartbeat_loop():
while True:
ok = _try_register(...)
was = _server_state['connected']
_server_state['connected'] = ok
if not was and ok:
print("[OK] 连接已恢复")
elif was and not ok:
print("[警告] 连接丢失")
time.sleep(60 if ok else 10)
核心要点
- BCD4编码将1比特扩展为1字节,在1200波特率下提供抗噪能力
- 校验和采用c1/c2半字节间的进位机制
- 结合精确假设和数据包样本,AI辅助逆向工程效果显著
- 服务器实现使传统设备无缝集成到Web系统
- 协议规范:33字节,起始标记0x55,数字+窗口+校验和
— Editorial Team
暂无评论。