针对打包BCD的Wireshark解剖器编码

时间:2018-01-03 07:54:27

标签: c++ wireshark

用C ++编写Wireshark剖析器插件。我正在尝试解析的协议使用不常见的压缩二进制编码十进制格式来表示其所有整数。

通常,当我想在偏移length处添加长度为offset的项目时,我写道:

proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_LITTLE_ENDIAN);
proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_NA); // big-endian int
proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_ASCII); // string

......等我还需要用以下字段注册字段数组:

proto_register_field_array(handle, field_array, array_length(field_array));

...其中field_arrayhf_register_info的数组,如下所示:

static hf_register_info field_array[] = {
    { &fields.foo, { "Foo Field", "protocol.foo", FT_UINT48, BASE_DEC } },
    // etc. other fields
};

...假设我的例子是一个6字节的打包BCD(能够容纳12位十进制数字)。

当我解析通过网络发送uint32,ASCII,int64等的合理协议时,这一切都很好用。但似乎没有针对压缩BCD的内置Wireshark编码。

我可以看到一个hacky解决方法将其解析为原始数据,然后编写一个函数将原始数据转换为正确的值,然后使用proto_item_set_text将项目设置为我想要的表示。

有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

答案 1 :(得分:1)

无需特殊编码即可使Wireshark很好地显示该值。二进制编码的十进制就像一个普通的整数,除了需要将值翻译成十进制。

因此,例如56(十进制值)将被传输(假设线路上的大端/网络字节顺序)为0000 0000 0101 01100056(十六进制)。所需要的只是将字段注册为FT_UINTX(例如,UINT32用于4字节压缩BCD,UINT40用于5字节等),并使用BASE_HEX表示。

static hf_register_info field_array[] = {
    { &fields.foo, { "Foo Field", "protocol.foo", FT_UINT48, BASE_HEX } },
    // etc. other fields
}; // works for 6-byte packed BCD

在解剖功能本身中,添加项目:

proto_tree_add_item(body, fields.foo, tvb, offset, length, ENC_NA);

至于实际将BCD字节转换为整数,我们可以编写一个函数将BCD转换为无符号,例如:

#include <cstdint>

uint64_t bcd_to_uint(const char* start, const size_t bytes)
{
    uint64_t value = 0;
    for (size_t i = 0; i < bytes; ++i)
    {
        uint8_t data = start[i] - '0';
        value += ((data >> 4) * 10 + (data & 0x0f)) * ipow(100, bytes - i - 1);
        // right-shift unsigned will fill with 0s
        // integer promotion will prevent overflow up to UINT_MAX
        // ipow(base, exp) returns base to the power of exp, returns uint64
    }
    return value;
}