搞网络开发的时候,涉及到很多私有协议。方便是方便,不过抓包分析问题就麻烦了,wireshark是不可能会为我们自己的网络协议开发分析工具的,唯有自己开发协议分析插件。在私有协议方面,google protobuf是一个类似与IDL的语言,用于定义消息接口,并且支持很多语言,原生支持C++、Java和python,而且还有很多第三方的支持,基本上支持C、C#、object-c,AS3,PHP等.目前protobuf的解析并不是wireshark内置支持的,不排除以后的版本会支持。当前网络上有一个工程可以支持protobuf的解析(protobuf-wireshark),但是该插件原生支持的只有linux版本,而且还只支持UDP解析。经本人改造,已经可以支持windows,并且同时支持TCP和UDP解析。TCP时,需要在protobuf之上加上一个4字节的数据长度,用于支持后续的protobuf消息的大小。
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
消息长度 protobuf二进制消息内容
消息长度的值只包含protobuf消息的大小,不包含自己4个字节的长度。例如protobuf长度为12字节时, 消息长度里面的值,应该是 00 00 00 0c,总的数据长度为16个字节.(如果无法解析数据长度,调换一下网络字节序)
另外对protobuf消息的定义也有一定的限制,必须有一个顶层的消息,例如Message1 和Message2如果是并列的消息,需要有一个Message来包含Message1和Message2.
【配置】
protobuf的配置文件放在C:\Program Files\Wireshark\protobuf目录下面,C:\Program Files\Wireshark\为wireshark在电脑上的安装目录。protobuf文件夹默认是没有的,自己创建。
把附件 *.proto;*.conf放在protobuf目录下面,把dll放在plugins\1.8.6目录下面。
protobuf-wireshark 插件下载, 测试包下载
插件代码:(代码基于google 上面的protobuf-wireshark 修改)
packet-protobuf.h
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gmodule.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/emem.h>
#include <epan/dissectors/packet-tcp.h>
#include <epan/filesystem.h>
#include <errno.h>
#include <string.h>
/* TCP数据包的固定头大小*/
#define FRAME_HEADER_LEN 4
void proto_register_protobuf();
void proto_reg_handoff_protobuf();
static void dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
static void dissect_protobuf_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
/* Define version if we are not building ethereal statically */
#ifndef ENABLE_STATIC
G_MODULE_EXPORT const gchar version[] = "0.0";
#endif
static int proto_protobuf = -1;
static dissector_handle_t protobuf_handle;
// Protocol field variables - START
static int hf_protobuf = -1;
// Protocol field variables - END
int wireshark_pb_process_protobuf(void *tree_root, int srcport, int dstport, int item_id, void *tvb, void *buf, int buf_size);
void wireshark_pb_process_protobuf_register_proto( int proto, const char* dirname );
void wireshark_pb_process_protobuf_register_ports();
void wireshark_pb_process_protobuf_register_subtree( int proto, const char* name,
int *handle, int ** tree_handle );
void wireshark_pb_process_protobuf_register_field( int proto, int type,
const char* name, const char * fullName,
int *handle );
/* Register plugin - START */
#ifndef ENABLE_STATIC
G_MODULE_EXPORT void
plugin_register(void) {
/* register the new protocol, protocol fields, and subtrees */
if (proto_protobuf == -1) { /* execute protocol initialization only once */
proto_register_protobuf();
}
}
G_MODULE_EXPORT void
plugin_reg_handoff(void){
proto_reg_handoff_protobuf();
}
#endif
void proto_register_protobuf(void) {
module_t *protobuf_module;
char* dirname;
if (proto_protobuf == -1) {
proto_protobuf = proto_register_protocol (
"protobuf ",/* name */
"protobuf",/* short name */
"protobuf"/* abbrev */
);
}
protobuf_module= prefs_register_protocol(proto_protobuf, proto_reg_handoff_protobuf);
/*char**/ dirname = get_persconffile_path("protobuf", FALSE, FALSE);
if( test_for_directory( dirname ) != EISDIR )
{
/* Although dir isn't a directory it may still use memory */
g_free( dirname );
dirname = get_datafile_path("protobuf");
if( test_for_directory( dirname ) != EISDIR )
{
g_free( dirname );
dirname = NULL;
}
}
wireshark_pb_process_protobuf_register_proto( proto_protobuf, dirname );
}
void proto_reg_handoff_protobuf (void) {
static int Initialized=FALSE;
unsigned int i = 0;
if (!Initialized) {
protobuf_handle = create_dissector_handle(dissect_protobuf, proto_protobuf);
wireshark_pb_process_protobuf_register_ports();
}
}
/* Register plugin - END */
/* 解析一个TCP数据包,wireshark会自动做分包和合并处理,此数据是一个完成的数据包,包含包头的内容*/
static void dissect_protobuf_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* TODO: implement your dissecting code */\
if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "protobuf-tcp");
}
/* Clear out stuff in the info column */
if(check_col(pinfo->cinfo,COL_INFO)){
col_clear(pinfo->cinfo,COL_INFO);
}
if (tree) { /* we are being asked for details */
/* Always make sure that offset is LESS than maxOffset */
gint data_len = tvb_get_ntohl(tvb, 0);
proto_item * ti = NULL;
tvbuff_t * next_tvb = tvb_new_subset_remaining (tvb,4);
gint maxOffset = tvb_length(next_tvb);
ti = proto_tree_add_item(tree,proto_protobuf,tvb,0,4,ENC_NA);
proto_item_append_text(ti, ", Length %d",data_len);
wireshark_pb_process_protobuf((void *) tree, pinfo->srcport, pinfo->destport, hf_protobuf,
(void *)next_tvb, (void *)tvb_get_ptr(next_tvb,0,data_len), data_len);
}
}
/* TCP数据包的总长度,包含包头长度 */
static guint get_protobuf_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
{
/* TODO: