Wireshark Generic Dissector

Decoder

This feature :
- is complex to use
- has some/many limitations
- has performance issue (especially on raw(*) or string())

Decoder does not apply to insproto/subproto.
Decoder apply to raw data, but the displayed data is not decoded.


Sometimes, the input data is NOT directly usable (using int16, string ...) because it is encoded.
It is necessary to decode the input data before use it.
With decoder command, you can provide a function which decode the data following your rules.

The function must be defined like this :

function void  <function_name> (in frame  frame, in uint32   nb_of_bits_needed)
{
  ... read some data (using hide)
  ... do some computation to decode data
  # Add a decoded data which size is <= 8 bits 
  # It is mandatory that the <decoded_value_on_1_byte_only>
  #  have type = uintX with X <= 8
  call frame_append_data (frame, <decoded_value_on_1_byte_only>);
  ...
}


The function must append inside frame the number of bits asked <nb_of_bits_needed>.
Then you must specify when using the function :

struct  xxx
{
  ...                  # the function is NOT called
  decoder  <function_name>;
  uint16   field_a;    # the function will be called with nb_of_bits_needed = 16
  uint8    field_b;    # the function will be called with nb_of_bits_needed =  8
   int24   field_c;    # the function will be called with nb_of_bits_needed = 24
  decoder  nil;
  ...                  # the function is NOT called
  string{decoder=<function_name>}(5)  str5;    # the function will be called with nb_of_bits_needed = 40
  string{decoder=<function_name>}     str;     # the function will be called many times with nb_of_bits_needed = 8
  ...                  # the function is NOT called
}

Example : 0x10

Decoding rule :
Each time there is a byte which equal 0x10,
it must be ignored and
we must take the following byte ^ 0x20.

Decoding function :

function void  decode_stream_0x10 (in frame  frame, in uint32   nb_of_bits_needed)
{
  # ATTENTION, following divide is possible only because I'm sure, in this example,
  #  that nb_of_bits_needed is a multiple of 8
  hide var uint32   nb_of_bytes_needed = nb_of_bits_needed / 8;
  while (nb_of_bytes_needed > 0)
  {
    hide uint8  byte1;
    if (byte1 == 0x10)
    {
      hide uint8  byte2;
      set byte1 = byte2 ^ 0x20;
    }
    call frame_append_data (frame, byte1);
    set nb_of_bytes_needed = nb_of_bytes_needed - 1;
  }
}


Using decoding function

struct xxx
{
  uint8      field_before;  # decode_stream_0x10 is not called
  
  decoder    decode_stream_0x10;
  uint16     field_a;      # decode_stream_0x10 will be called with nb_of_bits_needed = 16
  enum8      field_b;      # decode_stream_0x10 will be called with nb_of_bits_needed =  8
  string(3)  field_c;      # decode_stream_0x10 will be called with nb_of_bits_needed = 24
  decoder    nil;

  uint16     field_after;  # decode_stream_0x10 is not called
}


Example of data to read using the struct xxx :
0x10 0x23 0x10 0xa4 0xd1 0x02 0x03 0x10 0xc2 0x23 0x34
Will give the following result/sequence :

- field_before = 0x10  decode_stream_0x10 not called
- field_a
    decode_stream_0x10 is called with nb_of_bits_needed = 16
      read byte1 = 0x23, append it to frame
      read byte1 = 0x10,
        read byte2 = 0xa4
        set  byte1 = 0xa4 ^ 0x20 = 0x84, append it to frame
  field_a = 0x23 0x84
- field_b
    decode_stream_0x10 is called with nb_of_bits_needed = 8
      read byte1 = 0xd1, append it to frame
  field_b = 0xd1
- field_c
    decode_stream_0x10 is called with nb_of_bits_needed = 24
      read byte1 = 0x02, append it to frame
      read byte1 = 0x03, append it to frame
      read byte1 = 0x10,
        read byte2 = 0xc2
        set  byte1 = 0xc2 ^ 0x20 = 0xe2, append it to frame
  field_c = 0x02 0x03 0xe2
- field_after = 0x23 0x34  decode_stream_0x10 not called

Hexa-dump highlight possible problem

In the previous example, the hexa-dump highlight is working well.
We have the following scheme :
- what I want to read : <field_a><field_b><field_c>
- the real data format : <--field_a--><--field_b--><--field_c-->
Even if the size of the real data is NOT the same, the sequence is identic.

If the sequence is different, the hexa-dump highlight will not work.

Example : Unicode UTF16

Want to read an UTF16 string ?
Wsgd manage only ansi string.
But a decode function could transform UTF16 string to ansi string.
NB: all characters > 255 will be displayed as "."

# this is only an example, this function is now built-in
# decoder_utf16be (for Big Endian) is also built-in
function void  decoder_utf16le (in frame  frame, in uint32   nb_of_bits_needed)
{
  if ((nb_of_bits_needed % 8) != 0)
  {
    fatal "Only entire byte";
    return;
  }

  while (nb_of_bits_needed > 0)
  {
    hide uint8  byte1;
    hide uint8  byte2;
 
    if (byte2 != 0)
    {
      set byte1 = 46; # means "." to say unknow char

      if ((byte2 & 0xfc) == 0xd8)
      {
        hide uint8  byte3;
        hide uint8  byte4;        
      }
    }
   
    call frame_append_data (frame, byte1);
    set nb_of_bits_needed = nb_of_bits_needed - 8;
  }
}

alias stringUtf16le  string{decoder=decoder_utf16le};

Then you can use stringUtf16le where you have a string with UTF16 (little endian) encoding.

Example : Unicode UTF8

Want to read an UTF8 string ?
Wsgd manage only ansi string.
But a decode function could transform UTF8 string to ansi string.
NB: all characters > 127 will be displayed as "."

# this is only an example, this function is now built-in
function void  decoder_utf8 (in frame  frame, in uint32   nb_of_bits_needed)
{
  if ((nb_of_bits_needed % 8) != 0)
  {
    fatal "Only entire byte";
    return;
  }

  while (nb_of_bits_needed > 0)
  {
    hide uint8  byte1;
  
    if ((byte1 & 0x80) != 0)
    {
      if ((byte1 & 0xF0) == 0xF0)
      {
        hide uint8  byte2;
        hide uint8  byte3;
        hide uint8  byte4;
      }
      else
      {
        if ((byte1 & 0xE0) == 0xE0)
        {
          hide uint8  byte2;
          hide uint8  byte3;
        }
        else
        {
          hide uint8  byte2;
        }
      }
  
      set byte1 = 46; # means "." to say unknow char
    }
    
    call frame_append_data (frame, byte1);
    set nb_of_bits_needed = nb_of_bits_needed - 8;
  }
}

alias stringUtf8  string{decoder=decoder_utf8};

Then you can use stringUtf8 where you have a string with UTF8 encoding.

Example : Decoding functions which decode nothing

Silly and useless examples.

# Read each bit and simply put it into the frame
function void  decode_stream_nothing_bit (in frame  frame, in uint32   nb_of_bits_needed)
{
  while (nb_of_bits_needed > 0)
  {
    hide uint1  bit1;
    call frame_append_data (frame, bit1);
    set nb_of_bits_needed = nb_of_bits_needed - 1;
  }
}

# Read each byte and simply put it into the frame
function void  decode_stream_nothing_byte (in frame  frame, in uint32   nb_of_bits_needed)
{
  # ATTENTION, following divide is possible only if you are sure
  #  that nb_of_bits_needed is a multiple of 8
  hide var uint32   nb_of_bytes_needed = nb_of_bits_needed / 8;
  while (nb_of_bytes_needed > 0)
  {
    hide uint8  byte1;
    call frame_append_data (frame, byte1);
    set nb_of_bytes_needed = nb_of_bytes_needed - 1;
  }
}
CSS Template by Rambling Soul