用于包装BCD的Wireshark剖析器编码

Wireshark dissector encoding for packed BCD

本文关键字:剖析器 编码 Wireshark 包装 BCD 用于      更新时间:2023-10-16

在C++编写一个 Wireshark 剖析器插件。我尝试解析的协议对其所有整数使用不常见的打包二进制编码十进制格式。

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

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_array是一个hf_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 等的合理协议时,这一切都很好用。但似乎没有内置的Wireshark编码来包装BCD。

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

有没有更好的方法?

也许tvb_bcd_dig_to_wmem_packet_str()对你有用? 有几个剖析器使用它,这应该作为如何使用它的好例子:

$ grep -l tvb_bcd_dig_to_wmem_packet_str packet-*.c


packet-ansi_683.c
packet-ansi_a.c
packet-ansi_map.c
packet-bssap.c
packet-e164.c
packet-e212.c
packet-gsm_a_common.c
packet-gsm_a_dtap.c
packet-gsm_map.c
packet-gtp.c
packet-gtpv2.c
packet-ilp.c
packet-isup.c
packet-lte-rrc.c
packet-meta.c
packet-mip6.c
packet-nas_eps.c
packet-sgsap.c packet-ulp.c

不需要特定的编码来使Wireshark很好地显示值。二进制编码十进制类似于纯整数,只是该值需要像十进制一样转换。

因此,例如56(十进制值(将以0000 0000 0101 01100056(十六进制(的形式传输(假设线路上的大端/网络字节顺序(。所需要做的就是将字段注册为具有BASE_HEX表示的FT_UINTX(例如,UINT32 表示 4 字节打包 BCD,UINT40 表示 5 字节等(。

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;
}