parsing binary protocols

parsing - Nombrame un analizador binario. Un analizador de datos binarios



binary protocols (8)

Lectura en ASN.1. Si puede describir los datos binarios en sus términos, puede usar varios kits disponibles. No para los débiles de corazón.

Entonces, estoy obteniendo esta información. Desde el conector de red, o desde un archivo. Estoy improvisando un código que interpretará los datos. Lea algunos bytes, revise algunos indicadores y algunos bytes indican la cantidad de datos que sigue. Lee en esa cantidad de datos, enjuaga, repite.

Esta tarea me recuerda mucho a analizar el código fuente. Estoy cómodo con lex / yacc y antlr, pero no están a la altura de esta tarea. No puedes especificar bits y bytes crudos como tokens (bueno, tal vez podrías, pero no sabría cómo), y no puedes convertirlos en "leer dos bytes, convertirlos en un entero de 16 bits sin signo, llámalo n , y luego leer n bytes. ".

Por otra parte, cuando la especificación del formato de protocolo / datos se define de manera sistemática (no todos son), debe haber una forma sistemática de leer en los datos formateados de acuerdo con el protocolo. ¿Derecha?

Tiene que haber una herramienta que lo haga.


Ver también buffers de protocolo de google.




La iniciativa Kaitai Struct surgió recientemente para resolver exactamente esa tarea: generar analizadores binarios a partir de una especificación. Puede proporcionar un esquema para la serialización de la estructura de datos arbitraria en un formato basado en YAML / JSON como ese:

meta: id: my_struct endian: le seq: - id: some_int type: u4 - id: some_string type: str encoding: UTF-8 size: some_int + 4 - id: another_int type: u4

compilarlo usando ksc (proporcionan una implementación del compilador de referencia), y, voila, tienes un analizador en cualquier lenguaje de programación compatible, por ejemplo, en C ++:

my_struct_t::my_struct_t(kaitai::kstream *p_io, kaitai::kstruct *p_parent, my_struct_t *p_root) : kaitai::kstruct(p_io) { m__parent = p_parent; m__root = this; m_some_int = m__io->read_u4le(); m_some_string = m__io->read_str_byte_limit((some_int() + 4), "UTF-8"); m_another_int = m__io->read_u4le(); }

o en Java:

private void _parse() throws IOException { this.someInt = this._io.readU4le(); this.someString = this._io.readStrByteLimit((someInt() + 4), "UTF-8"); this.anotherInt = this._io.readU4le(); }

Después de agregar eso a su proyecto, proporciona una API muy intuitiva como esa (un ejemplo en Java, pero admiten más idiomas):

// given file.dat contains 01 00 00 00|41 42 43 44|07 01 00 00 MyStruct s = MyStruct.fromFile("path/to/file.dat"); s.someString() // => "ABCD" s.anotherInt() // => 263 = 0x107

Es compatible con diferentes endianness, estructuras condicionales, subestructuras, etc., y mucho más. Se pueden analizar estructuras de datos bastante complejas, como el formato de archivo de imagen PNG o el ejecutable PE .


Ciertamente, no hay nada que te impida escribir un analizador decente recursivo, digamos, para datos binarios de la misma manera que lo harías con la herramienta manual de un analizador de texto. Si el formato que necesita leer no es demasiado complicado, esta es una forma razonable de proceder.

Por supuesto, si el formato es muy simple, puede consultar el archivo binario de lectura definido por una estructura y una pregunta similar.

No conozco ningún generador de analizadores para la entrada de texto, aunque también son posibles.

En el caso de que no esté familiarizado con los analizadores de codificación a mano, la pregunta SO canónica es Aprender a escribir un compilador . El tutorial de Crenshaw (y en PDF ) es una lectura rápida.


Puede intentar utilizar Boost.Spirit (v2) que recientemente obtuvo herramientas de análisis binario , analizadores nativos y mixtos compatibles con endianness

// This is not a complete and useful example, but just illustration that parsing // of raw binary to real data components is possible typedef boost::uint8_t byte_t; byte_t raw[16] = { 0 }; char const* hex = "01010000005839B4C876BEF33F83C0CA"; my_custom_hex_to_bytes(hex, raw, 16); // parse raw binary stream bytes to 4 separate words boost::uint32_t word(0); byte_t* beg = raw; boost::spirit::qi::parse(beg, beg + 16, boost::spirit::qi::dword, word))

ACTUALIZACIÓN: Encontré una pregunta similar, donde Joel de Guzman confirma en su respuesta la disponibilidad de analizadores binarios: ¿se puede utilizar Boost Spirit para analizar datos de transmisión de bytes?


El analizador de construcciones , escrito en Python, ha realizado un trabajo interesante en este campo.

El proyecto ha tenido varios autores y períodos de estancamiento, pero a partir de 2017 parece estar más activo de nuevo.