Ingeniería Inversa de un Protocolo de Visualización de Colas: Codificación BCD4 y Aritmética de Acarreo
Un ingeniero realizó ingeniería inversa de un protocolo propietario de visualización de colas sin documentación. El protocolo utiliza codificación BCD4, donde cada bit de datos ocupa un byte completo para inmunidad al ruido en líneas RS-232 largas a 1200 baudios. La estructura del paquete es de 33 bytes con un marcador, dígitos numéricos, número de ventana y campos de suma de verificación con acarreo.
BCD4: Codificación para Transmisión Confiable
El protocolo emplea un método de hardware para protección contra ruido: cada bit de un número (0–15) se codifica como un byte. 0x7F denota 1 (siete unos para un pulso claro), 0x00 denota 0. Esto expande un valor de 4 bits a 4 bytes.
Ejemplos de codificación:
| Número | Bits | Bytes 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 |
Implementación en 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
La velocidad de 1200 baudios garantiza confiabilidad a costa del rendimiento.
Estructura del Paquete para Visualización de Números
Un paquete de 33 bytes muestra un número en una ventana:
- Byte 0:
0x55— marcador de inicio. - Bytes 1–4: cabecera de modo.
- Bytes 5–8: BCD4(dígito de unidades).
- Bytes 9–12: BCD4(dígito de decenas).
- Bytes 13–16: BCD4(dígito de centenas).
- Bytes 17–20: BCD4(dígito de unidades de ventana).
- Bytes 21–24: BCD4(dígito de decenas de ventana).
- Bytes 25–28: BCD4(c1) — parte inferior de la suma de verificación.
- Bytes 29–32: BCD4(c2) — parte superior con acarreo.
Ejemplo para el número 487 en la ventana 19:
55 00 7F 00 00 # cabecera
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)
[campos de suma de verificación]
Cálculo de la Suma de Verificación con Acarreo
Los campos de suma de verificación c1 y c2 forman un valor de 8 bits con mecánica de acarreo:
- Calcular raw_c1 como una combinación lineal de los campos del paquete.
- Si raw_c1 >= 16: acarreo = 1, c1 = raw_c1 - 16.
- De lo contrario: acarreo = 0, c1 = raw_c1.
- c2 se calcula con acarreo de otros campos.
El acarreo ocurre con números como 80–90 dependiendo de la ventana. La IA (Claude) identificó el patrón a partir de 30 ejemplos de paquetes después de refinar la hipótesis: dos nibbles de 4 bits con acarreo como en aritmética.
Para el modo "todas las ventanas" (25 bytes), no hay acarreo y la fórmula es más simple.
El modo de programación de ventanas utiliza dos cadenas de acarreo independientes con multiplicación y constantes:
- Cadena A: raw_A desde W_lo, carry_A = raw_A >> 4, field_A1 = raw_A & 0xF, field_A2 desde W_hi y carry_A.
- Cadena B: similar para otra función lineal.
Ensamblado y Envío del Paquete
Función de ensamblado de paquetes:
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)
El paquete se envía a un puerto COM.
Integración en un Sistema Web
Un servidor Python acepta HTTP POST:
POST / {"window": 5, "ticket": "487"}
Analiza JSON, construye el paquete y escribe en el puerto. Un mecanismo de latido restaura la conexión:
- Intervalo de 60 segundos cuando está OK.
- 10 segundos en error.
def _heartbeat_loop():
while True:
ok = _try_register(...)
was = _server_state['connected']
_server_state['connected'] = ok
if not was and ok:
print("[OK] Conexión restaurada")
elif was and not ok:
print("[WARN] Conexión perdida")
time.sleep(60 if ok else 10)
Conclusiones Clave
- La codificación BCD4 expande 1 bit a un byte para inmunidad al ruido a 1200 baudios.
- La suma de verificación utiliza acarreo entre nibbles c1/c2.
- La ingeniería inversa con IA es efectiva con hipótesis precisas y ejemplos de paquetes.
- El servidor permite integración fluida de equipos heredados con la web.
- Protocolo: 33 bytes, marcador 0x55, dígitos + ventana + suma de verificación.
— Editorial Team
Aún no hay comentarios.