Wireshark-protobuf编译小结
来源:互联网 发布:windows设备管理器在哪 编辑:程序博客网 时间:2024/05/19 18:48
需要进行抓包分析,由于不支持自定义协议,因此需要做wireshark的protobuf插件开发。
wireshark 插件开发有两种,
一种是用lua开发,挂在wireshark上。
另一种是通过c插件编译出dll文件,将dll文件挂在wireshark上。
软件版本:
vs2008
python 2.7
protobuf 2.6.1
wireshark 1.8.6
主要参考帖子:
wireshark protobuf 插件
protobuf-wireshark编译小结
Wireshark 插件开发整体解决方案
其中前两个是最主要的 ,第三个是前期环境配置的主要问题。
1、环境搭建。
1.1 安装vs2008(不需要拷贝vsc**.*等环境配置文件,用vs2008 commond promot运行nmake命令相当于配好了环境)
1.2 安装最新版本的cgwin,并配置:
- Archive/unzip (not needed if using CMake)
- Devel/bison (or install Win flex-bison - see Chocolatey below)
- Devel/flex (or install Win flex-bison - see Chocolatey below)
- Devel/git (recommended - see discussion about using Git below)
- Interpreters/perl
- Utils/patch (only if needed) (may be Devel/patch instead)
- Web/wget (not needed if using CMake)
- Text/asciidoc
- Text/docbook-xml45
1.3 下载wireshark源码。
http://www.Wireshark.org/download/src/all-versions/
我用的版本是wireshark 1.8.6
1.4 编译config.nmake文件
(1)WIRESHARK_LIBS: 设置编译wireshark所需要的库所在的目录。默认即可(因此不需要Wireshark 插件开发整体解决方案中的第5部.)
(2)PROGRAM_FILES:设置本机程序安装目录,默认即可。
(3)MSVC_VARIANT我使用的是VS2008,所以在这里把值为MSVC2008的那一行前面的#去掉,其余MSVC_VARIANT项保持不变。
(4)CYGWIN_PATH将其设置为Cygwin的bin目录,例如C:\Cygwin\bin.
(5)PYTHON及其后的PATH将其修改为本机python.exe和其安装目录的位置,例如:C:\Python27\Python.exe
(6)MSVCR_DLL如果VS不是安装在C盘,请在这里相应的地方用绝对路径表示,而不要去修改前面的PROGRAM_FILES。如果是在c盘,
则不能使用绝对路径。若是安装在c盘,此项不需要修改。
(7)MAKENSIS 如果你没有安装NSIS安装程序制作工具,用#注释掉此行
(8)HHC_DIR如果没有安装HTMLHelpWorkshop(chm帮助文件制作工具),注释掉此行
(9)注释掉HHC_EXE
1.5
在vs2008中cmd中cd到wireshark 源码的目录。
执行nmake -f makefile.nmake verify_tools,检查工具。全部成功如下图。
执行nmake -f makefile.nmake setup
执行nmake -f makefile.nmake distclean
执行nmake -f makefile.nmake all。
protobuf插件开发主要就是前两个链接。
1. 首先要先搭建好wireshark编译环境,参见前面参考。
2. 下载protobuf-wireshark代码,下载protobuf-wireshark-runtime-0.1.tar.gz文件点击打开链接
3. 解压protobuf-wireshark-runtime-0.1.tar.gz文件后,修改 wireshark.conf配置文件。设置wireshark的源代码和安装目录,本人配置如下
wireshark_src_dir : /cygdrive/h/wireshark-1.8.6
wireshark_install_dir : /cygdrive/c/Program Files/Wireshark
wireshark_version : 1.8.6
4. 启动cygwin终端,并切换到protobuf-wireshark-runtion-0.1的目录下面,本人地址为;/cygdrive/h/a/protobuf-wireshark-runtime-0.1
5. 执行$ ./make_wireshark_plugin.py wireshark.conf
注意:编译是通不过的,因为该工程是针对linux的,而我们要的是windows的版本。
执行后,在wireshark\plusins目录下会创建protobuf目录,并且生成了moduleinfo.h、Makefile.am、packet-protobuf.c三个文件
同时在protobuf-wireshark-runtime-0.1源代码目录下也会生成2个c++文件wireshark-glue-protobuf.h和wireshark-glue-protobuf.cc,把这2个文件拷贝到plugins\protobuf目录下面。
6. 切换到plugins\protobuf目录,并从其他插件目录拷贝 Makefile.common、moduleinfo.nmake、Makefile.nmake、plugin.rc.in 4个文件,对5和6中的文件做修改。
wireshark的所有源代码都是基于c语言的,但是protobuf插件多了c++文件。
修改6中的三个文件内容。
makefile.common 文件内容:
# Makefile.common for protobuf plugin# Contains the stuff from Makefile.am and Makefile.nmake that is# a) common to both files and# b) portable between both files## $Id: Makefile.common 27491 2009-02-21 16:33:48Z jake $## Wireshark - Network traffic analyzer# By Gerald Combs <gerald@wireshark.org># Copyright 1998 Gerald Combs## This program is free software; you can redistribute it and/or# modify it under the terms of the GNU General Public License# as published by the Free Software Foundation; either version 2# of the License, or (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.# the name of the pluginPLUGIN_NAME = protobuf# the dissector sources (without any helpers)DISSECTOR_SRC = \packet-protobuf.cDISSECTOR_SRCC = \wireshark-glue-protobuf.cc# corresponding headersDISSECTOR_INCLUDES =\wireshark-glue-protobuf.h\moduleinfo.h\# Dissector helpers. They're included in the source files in this# directory, but they're not dissectors themselves, i.e. they're not# used to generate "plugin.c".DISSECTOR_SUPPORT_SRC =
moduleinfo.nmake文件内容:
# # $Id: moduleinfo.nmake 20157 2006-12-19 22:23:22Z jake $ # # The name PACKAGE=protobuf # The version MODULE_VERSION_MAJOR=0 MODULE_VERSION_MINOR=0 MODULE_VERSION_MICRO=1 MODULE_VERSION_EXTRA=0 # # The RC_VERSION should be comma-separated, not dot-separated, # as per Graham Bloice's message in # # http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html # # "The RC_VERSION variable in config.nmake should be comma separated. # This allows the resources to be built correctly and the version # number to be correctly displayed in the explorer properties dialog # for the executables, and XP's tooltip, rather than 0.0.0.0." # MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA) RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA)
Makefile.nmake文件内容:
# Makefile.nmake # nmake file for Wireshark plugin # # $Id: Makefile.nmake 42971 2012-06-01 14:08:12Z wmeier $ # PROTOBUF_DIR=F:\protobuf-2.6.1\srcPROTOBUF_LIB=F:\protobuf-2.6.1\vsprojects\Release\libprotobuf.libinclude ..\..\config.nmake include moduleinfo.nmake PLUGIN_NAME=protobuf DISSECTOR_SRC=packet-protobuf.c DISSECTOR_SRCC=wireshark-glue-protobuf.cc DISSECTOR_SUPPORT_SRC= DISSECTOR_INCLUDES=wireshark-glue-protobuf.h moduleinfo.h CFLAGS=$(WARNINGS_ARE_ERRORS) $(STANDARD_CFLAGS) /I../.. $(GLIB_CFLAGS) /I$(PROTOBUF_DIR) .c.obj:: $(CC) $(CFLAGS) -Fd.\ -c $< .cc.obj:: $(CC) $(CFLAGS) -Fd.\ -c $< LDFLAGS = $(PLUGIN_LDFLAGS) !IFDEF ENABLE_LIBWIRESHARK LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib ..\..\wsutil\libwsutil.lib $(PROTOBUF_LIB) CFLAGS=/D_NEED_VAR_IMPORT_ $(CFLAGS) DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj) DISSECTOR_OBJECTSS = $(DISSECTOR_SRCC:.cc=.obj) DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj) OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) $(DISSECTOR_OBJECTSS) RESOURCE=$(PLUGIN_NAME).res all: $(PLUGIN_NAME).dll $(PLUGIN_NAME).rc : moduleinfo.nmake sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ -e s/@RC_VERSION@/$(RC_VERSION)/ -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ -e s/@PACKAGE@/$(PACKAGE)/ -e s/@VERSION@/$(VERSION)/ -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ < plugin.rc.in > $@ $(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE) link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) $(GLIB_LIBS) $(RESOURCE) # # Build plugin.c, which contains the plugin version[] string, a # function plugin_register() that calls the register routines for all # protocols, and a function plugin_reg_handoff() that calls the handoff # registration routines for all protocols. # # We do this by scanning sources. If that turns out to be too slow, # maybe we could just require every .o file to have an register routine # of a given name (packet-aarp.o -> proto_register_aarp, etc.). # # Formatting conventions: The name of the proto_register_* routines an # proto_reg_handoff_* routines must start in column zero, or must be # preceded only by "void " starting in column zero, and must not be # inside #if. # # DISSECTOR_SRC is assumed to have all the files that need to be scanned. # # For some unknown reason, having a big "for" loop in the Makefile # to scan all the files doesn't work with some "make"s; they seem to # pass only the first few names in the list to the shell, for some # reason. # # Therefore, we have a script to generate the plugin.c file. # The shell script runs slowly, as multiple greps and seds are run # for each input file; this is especially slow on Windows. Therefore, # if Python is present (as indicated by PYTHON being defined), we run # a faster Python script to do that work instead. # # The first argument is the directory in which the source files live. # The second argument is "plugin", to indicate that we should build # a plugin.c file for a plugin. # All subsequent arguments are the files to scan. # !ENDIF clean: rm -f $(OBJECTS) $(RESOURCE) *.pdb *.sbr $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc distclean: clean maintainer-clean: distclean checkapi: # TODO: Fix api's :) # $(PERL) ../../tools/checkAPIs.pl -g abort -g termoutput -build $(DISSECTOR_SRC) $(DISSECTOR_INCLUDES)
8修改packet-protobuf.c,wireshark-glue-protobuf.cc
packet-protobuf.c内容:
#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 /*这个值在本程序中没有使用。本身他的作用是用来合并TCP包的时候,传入的包头固定大小,由于自定义协议中前面有13字节固定长度,后面有两个字节固定长度,本程序中没有合并TCP包。*/#define FRAME_HEADER_LEN 11 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数据包*/ static void dissect_protobuf_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /*先进行数据包判断,如果数据长度小于7,则是继续向后偏移,直到取得大于7的长度,进入下一步。或者数据长度==0,或者偏移量达到最大偏移,则退出。*/proto_item * ti = NULL; proto_item * pi =NULL;tvbuff_t * next_tvb=NULL; gint maxOffset = 0;gint msg_id =0;gint msglen=0;gint offect=0; if (tree) { /* we are being asked for details */ /* Always make sure that offset is LESS than maxOffset */ gint data_len = tvb_get_letohs(tvb,2); if ( data_len==0)return ; msglen= tvb_length(tvb); offect=data_len+6; while(data_len <7){if(data_len==0 ||offect>=msglen)return ;tvb= tvb_new_subset_remaining(tvb,6+data_len);data_len = tvb_get_letohs(tvb,2); offect+=data_len+6;} /* 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); } /*ti 取得是数据长度,(eb 91 ** ** eb 91 之后的长度)。pi 取得是数据类型。从字节流开始偏移 9个字节。*/ //proto_item *pi=NULL; //tvbuff_t * next_tvb = tvb_new_subset_remaining (tvb,4); next_tvb = tvb_new_subset_remaining(tvb,13); maxOffset = tvb_length(next_tvb); msg_id = tvb_get_ntohs(tvb, 9); //ti = proto_tree_add_item(tree,proto_protobuf,tvb,0,4,ENC_NA); ti = proto_tree_add_item(tree,proto_protobuf,tvb,2,2,ENC_NA); pi = proto_tree_add_item(tree,proto_protobuf,tvb,9,2,ENC_NA); proto_item_append_text(ti, ", Length %d",data_len); proto_item_append_text(pi, ", Message type:%d",msg_id); wireshark_pb_process_protobuf((void *) tree, pinfo->srcport, pinfo->destport, hf_protobuf, msg_id, (void *)next_tvb, (void *)tvb_get_ptr(next_tvb,0,data_len-9), data_len-9); } } /* TCP数据包的总长度,包含包头长度 */ static guint get_protobuf_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { /* TODO: change this to your needs */ //return (guint)tvb_get_ntohl(tvb, offset)+4; /* e.g. length is at offset 4 */ /*这个函数没有使用,但继续4的原因是,字节长度是包含最后两个校验位的长度,因此要减2,再加上报文头的长度,即+6,因此还是+4.*/return (guint)tvb_get_letohs(tvb,2)+4; /* e.g. length is at offset 10 */ } /* Generate the main dissector function - START */ static void dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { if( pinfo->tcp_tree == NULL) //进入解析UDP数据包 { dissect_protobuf_udp(tvb,pinfo,tree); }else { //进入解析TCP数据包。//没有经过并包处理,直接进行解析TCP数据。 dissect_protobuf_message(tvb, pinfo,tree); //tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN, // get_protobuf_message_len, dissect_protobuf_message); } } static void dissect_protobuf_udp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "protobuf-udp"); } /* 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 maxOffset = tvb_length(tvb); wireshark_pb_process_protobuf((void *) tree, pinfo->srcport, pinfo->destport, hf_protobuf, (void *)tvb, (void *)tvb_get_ptr(tvb,0,maxOffset), maxOffset); } } //dissect_protobuf_udp /* Generate the main dissector function - END */ /** Called from PB to add msg_str to tree_root */ int wireshark_pb_add_protobuf(void* tree_root, void* tvb, int item_id, char* msg_str) { proto_tree_add_none_format ((proto_tree *) tree_root, item_id, (tvbuff_t*) tvb, 0, -1, msg_str); return 0; } void wireshark_pb_process_protobuf_register_subtree( int proto, const char* name, int *handle, int ** p_tree_handle ) { hf_register_info message_info = { handle, { (char*)name, (char*)name, FT_NONE, BASE_NONE, NULL, 0, "", HFILL } }; hf_register_info *hf_info = malloc(sizeof( hf_register_info ) ); *hf_info = message_info; proto_register_field_array( proto, hf_info, 1 ); proto_register_subtree_array( p_tree_handle, 1 ); } void wireshark_pb_process_protobuf_register_field( int proto, int type, const char* name, const char * fullName, int *handle ) { int base = ( ( type == FT_UINT32 ) || ( type == FT_UINT64 ) ) ? BASE_HEX : ( ( type == FT_INT32 ) || ( type == FT_INT64 ) ) ? BASE_DEC : BASE_NONE; hf_register_info message_info = { handle, { (char*)fullName, (char*)name, type, base, NULL, 0, "", HFILL } }; hf_register_info *hf_info = malloc(sizeof( hf_register_info ) ); *hf_info = message_info; proto_register_field_array( proto, hf_info, 1 ); } void wireshark_pb_process_protobuf_dissector_add( const char* name, int port ) { dissector_add( name, port, protobuf_handle ); }
wireshark-glue-protobuf.cc文件内容:
#include "wireshark-glue-protobuf.h" #include <iostream> #include <dirent.h> #include <fstream> #include <windows.h>#include <wchar.h>#include <google/protobuf/text_format.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/wire_format_lite.h> #include <google/protobuf/wire_format_lite_inl.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/compiler/importer.h> #include <google/protobuf/dynamic_message.h> using namespace std; using namespace google; using namespace protobuf; using namespace internal; extern "C" { static HandleMap* handleMap = NULL; static MessageConfigList messageConfigList; static google::protobuf::compiler::Importer* importer = NULL; static MaptoMesConfig maptoMesconfig;//static logger mylog;static void * _tvb = NULL; static const char ARRAY_FORMAT[] = "%s[%d]"; /*添加Utf8ToString,将utf8数据转为string。希望解决中文显示问题,暂未成功。*/std::string Utf8ToString(const std::string &str){int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0); wchar_t * pwBuf = new wchar_t[nwLen + 1];memset(pwBuf, 0, nwLen * 2 + 2); MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen); int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL); char * pBuf = new char[nLen + 1]; memset(pBuf, 0, nLen + 1); WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL); std::string retStr = pBuf; delete []pBuf; delete []pwBuf; pBuf = NULL; pwBuf = NULL; return retStr; }/** * @param buf The message contents * @param buf_size The length of message contents in buf * @param tree_root The WireShark tree to which this message is to be added. * @param item_id Internal wireshark id to refer to this FT_NONE datatype. */ /*当某一个port满足要求时,修改了以前的做法,从第一个MessageConfigList对象开始反序列化,这会导致利用错误的protobuf_MessageConfig解析数据问题。修改:增加MaptoMesConfig对象,这是一个map,key为数据类型,value 为protobuf_MessageConfig。通过字节流的数据类型,去MaptoMesConfig中取相应的protobuf_MessageConfig进行解析。for循环应该是可以去掉的。保留了for循环的考虑是尽量少减小代码修改。*/int wireshark_pb_process_protobuf(proto_tree* tree_root, int srcport, int dstport, int item_id, int msg_id ,tvbuff_t* tvb, void* buf, int buf_size) { for( MessageConfigList::iterator it = messageConfigList.begin(); it != messageConfigList.end(); it++ ) { if( (*it)->matchesSrcPort( srcport ) || (*it)->matchesDestPort( dstport ) ) { //mylog.debug("DEBUG",msg_id); MaptoMesConfig::iterator index=maptoMesconfig.find(msg_id); if(index!=maptoMesconfig.end()) *it=maptoMesconfig[msg_id]; return (*it)->dissect( tree_root, item_id, tvb, buf, buf_size ); } } DBG_ERR("Failed to find match"); wireshark_pb_add_protobuf(tree_root,tvb,item_id,"Failed to find match"); return -1; } void wireshark_pb_process_protobuf_register_subtree_( int proto, const std::string& name, const std::string& full_name ) { Handles *handles = new Handles(); wireshark_pb_process_protobuf_register_subtree( proto, name.c_str(), &(handles->handle), &(handles->tree_handle) ); handleMap->insert( StringHandlePair( full_name, handles ) ); } int wireshark_pb_process_protobuf_get_type( FieldDescriptor::CppType type ) { struct ftmap_t { FieldDescriptor::CppType cpp_type; ftenum fttype; int length; }; static ftmap_t ftmap[] = { { FieldDescriptor::CPPTYPE_UINT32, FT_UINT32 }, { FieldDescriptor::CPPTYPE_INT32, FT_INT32 }, { FieldDescriptor::CPPTYPE_UINT64, FT_UINT64 }, { FieldDescriptor::CPPTYPE_INT64, FT_INT64 }, { FieldDescriptor::CPPTYPE_DOUBLE, FT_DOUBLE }, { FieldDescriptor::CPPTYPE_FLOAT, FT_FLOAT }, { FieldDescriptor::CPPTYPE_BOOL, FT_BOOLEAN }, { FieldDescriptor::CPPTYPE_ENUM, FT_INT32 }, { FieldDescriptor::CPPTYPE_STRING, FT_STRING } }; for( int i =0; i < sizeof(ftmap)/sizeof(ftmap_t); i++ ) { if( ftmap[i].cpp_type == type ) { return ftmap[i].fttype; } } DBG_ERR( "Couldnt find type for cpp type " << type ); return FT_NONE; } void wireshark_pb_process_protobuf_register_ports() { for( MessageConfigList::iterator it = messageConfigList.begin(); it != messageConfigList.end(); it++ ) { (*it)->register_ports(); } } void wireshark_pb_process_protobuf_register_proto( int proto, const char* dirname ) { if( dirname == NULL ) { DBG_ERR( "couldnt get dirname "); return; } DIR* dir = opendir( dirname ); if( dir == NULL ) { DBG_ERR( "couldnt open " << dirname ); return; } dirent* dp; std::string configFileExtension( ".conf" ); std::string protoFileExtension( ".proto" ); while( ( dp = readdir( dir ) ) != NULL ) { std::string filename( dp->d_name ); size_t i = filename.rfind( configFileExtension ); if( ( i != std::string::npos ) && ( i == filename.length() - configFileExtension.length() ) ) { protobuf_MessageConfig* messageConfig = new protobuf_MessageConfig( filename, dirname ); if( messageConfig->isValid() ) { messageConfigList.push_back( messageConfig ); messageConfig->register_proto( proto ); //mylog.debug("add to maptomes",messageConfig->message_selfid);maptoMesconfig[messageConfig->message_selfid]=messageConfig;//mylog.debug("add to maptomes, size ",maptoMesconfig.size());//mylog.debug(" messageConfigList size ", messageConfigList.size()); } } //const FileDescriptor* fileDesc = importer->Import( filename ); // //for( int i = 0; i < fileDesc->message_type_count(); i++ ) //{ // const Descriptor* desc = fileDesc->message_type( i ); // std::string configFileName = desc->name() + ".config"; // // // check if desc->name() | .config exists TBD // messageConfigList.push_back( new protobuf_MessageConfig( configFileName, desc ) ); //} } closedir( dir ); } protobuf_Dissector::protobuf_Dissector() : _leaf( NULL ), _len( -1 ), _message( NULL ), _offset( 0 ), _prefix_len( -1 ), _reflection( NULL ) { } protobuf_Dissector::protobuf_Dissector( proto_tree* tree, int offset, const Message* message, const FieldDescriptor* field, int index ) : _leaf( NULL ), _len( -1 ), _message( message ), _offset( offset ), _prefix_len( 0 ), _reflection( _message->GetReflection() ) { bool is_root = ( field == NULL ); const std::string& label = ( is_root ) ? _message->GetDescriptor()->name() : field->name(); const std::string& fullname = _message->GetDescriptor()->full_name(); int data_size = _message->ByteSize(); int total_size = data_size; // if not root field then prefix_len needs to be computed if( !is_root ) { _prefix_len = WireFormat::TagSize( _message->GetDescriptor()->index(), FieldDescriptor::TYPE_MESSAGE ); _prefix_len+= io::CodedOutputStream::VarintSize32( data_size ); total_size+= _prefix_len; } _len = total_size; // construct subtree here itself rather than in dissect method otherwise // all repeated fields and messages are pushed to end of current tree // regardless of their current position HandleMap::iterator it = handleMap->find( fullname ); if( it == handleMap->end() ) { DBG_ERR( "couldnt find handle for " << fullname ); return; } Handles *handles = it->second; // add a subtree for current message proto_item* item; if( index == -1 ) { item = proto_tree_add_none_format( tree, handles->handle, _tvb, _offset, _len, label.c_str() ); } else { item = proto_tree_add_none_format( tree, handles->handle, _tvb, _offset, _len, ARRAY_FORMAT, label.c_str(), index ); } _leaf = proto_item_add_subtree( item, *(handles->tree_handle) ); } void protobuf_Dissector::dissect( DissectorList& dissectorList ) { //DBG( "Dissecting " << _message->GetDescriptor()->name() // << " of length " << _len // << " prefix len " << _prefix_len ); if( !_leaf ) { DBG_ERR( "Couldnt find leaf node for current message" ); return; } _offset+= _prefix_len; // now loop through all the field in current message FieldDescriptorList fields ; _reflection->ListFields( *_message, &fields ); for( FieldDescriptorList::iterator it = fields.begin(); it!=fields.end(); it++ ) { const FieldDescriptor* field = *it; bool is_message = ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) ; if( field->is_repeated() ) { if( field->options().packed() ) { int data_size = WireFormat::FieldDataOnlyByteSize( field, *_message ); if (data_size > 0) { _offset += WireFormat::TagSize( field->number(), FieldDescriptor::TYPE_STRING ); _offset += io::CodedOutputStream::VarintSize32( data_size ); } } int size = _reflection->FieldSize( *_message, field ); for( int i = 0; i < size; i++ ) { if( is_message ) { const Message& subMessage = _reflection->GetRepeatedMessage( *_message, field, i ); protobuf_Dissector dissector( _leaf, _offset, &subMessage, field, i ); dissectorList.push_back( dissector ); _offset+= dissector.messageLength(); } else { dissectRepeatedField( field, i ); } } } else if( is_message ) { const Message& subMessage = _reflection->GetMessage( *_message, field ); protobuf_Dissector dissector( _leaf, _offset, &subMessage, field ); dissectorList.push_back( dissector ); _offset+= dissector.messageLength(); } else // plain simple field. process it immediately { dissectField( field ); } } } void protobuf_Dissector::dissectField( const FieldDescriptor* field ) { int len = WireFormat::FieldByteSize( field, *_message ); //DBG( "Dissecting field " << field->name() << " " << len ); HandleMap::iterator it = handleMap->find( field->full_name() ); if( it == handleMap->end() ) { DBG_ERR( "Couldnt find handle for " << field->full_name() ); return; } Handles *handles = it->second; const EnumValueDescriptor* enumDesc = NULL; std::string Fromutf8tostring=""; switch( field->cpp_type() ) { case FieldDescriptor::CPPTYPE_UINT32: proto_tree_add_uint( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetUInt32( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_INT32: proto_tree_add_int( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetInt32( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_FLOAT: proto_tree_add_float( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetFloat( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_UINT64: proto_tree_add_uint64( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetUInt64( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_INT64: proto_tree_add_int64( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetInt64( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_DOUBLE: proto_tree_add_double( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetDouble( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_BOOL: proto_tree_add_boolean( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetBool( *_message, field ) ); break; case FieldDescriptor::CPPTYPE_ENUM: enumDesc = _reflection->GetEnum( *_message, field ); proto_tree_add_int_format_value( _leaf, handles->handle, _tvb, _offset, len, //mawu enumDesc->number(), "%d ( %s )", enumDesc->number(), enumDesc->name().c_str() ); //Fromutf8tostring= Utf8ToString(enumDesc->name());//mylog.debug("Fromutf8tostring",Fromutf8tostring);// proto_tree_add_int_format_value( _leaf, handles->handle, _tvb, _offset, len, // enumDesc->number(), "%d ( %s )", enumDesc->number(), // Fromutf8tostring.c_str()); // Fromutf8tostring=""; break; case FieldDescriptor::CPPTYPE_STRING: //proto_tree_add_string( _leaf, handles->handle, _tvb, _offset, len, //mawu // _reflection->GetString( *_message, field ).c_str() ); //std::string ConvertString= Utf8ToString(_reflection->GetString( *_message, field ));//mylog.debug("befor convert ",_reflection->GetString( *_message, field ));//mylog.debug("befor convert size",_reflection->GetString( *_message, field ).size() );//mylog.debug("len is ",len);Fromutf8tostring = Utf8ToString(_reflection->GetString( *_message, field ));//mylog.debug("Fromutf8tostring1",Fromutf8tostring);//mylog.debug("Fromutf8tostring1.size",Fromutf8tostring.size());//mylog.debug("1temp.size:",temp.size());proto_tree_add_string( _leaf, handles->handle, _tvb, _offset, len, Fromutf8tostring.c_str()); Fromutf8tostring=""; break; default: proto_tree_add_item( _leaf, handles->handle, _tvb, _offset, len, true ); }; _offset+=len; } void protobuf_Dissector::dissectRepeatedField( const FieldDescriptor* field, int index ) { int len = 0; string scratch; if( !field->options().packed() ) { len+= WireFormat::TagSize( field->number(), field->type() ); } //DBG( "Dissecting field " << field->name() << " " << len ); HandleMap::iterator it = handleMap->find( field->full_name() ); if( it == handleMap->end() ) { DBG_ERR( "Couldnt find handle for " << field->full_name() ); return; } Handles *handles = it->second; const EnumValueDescriptor* enumDesc = NULL; std::string Fromutf8tostring="";/*下面所有用了Fromutf8tostring,都是将原utf-8转为string。本来是想解决中文显示问题,没有成功。*/ switch( field->cpp_type() ) { case FieldDescriptor::CPPTYPE_UINT32: if( field->type() == FieldDescriptor::TYPE_FIXED32 ) { len+= WireFormatLite::kFixed32Size; } else { len+= WireFormatLite::UInt32Size( _reflection->GetRepeatedUInt32( *_message, field, index ) ); } proto_tree_add_uint( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedUInt32( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_INT32: if( field->type() == FieldDescriptor::TYPE_SFIXED32 ) { len+= WireFormatLite::kSFixed32Size; } else if( field->type() == FieldDescriptor::TYPE_SINT32 ) { len+= WireFormatLite::SInt32Size( _reflection->GetRepeatedInt32( *_message, field, index ) ); } else { len+= WireFormatLite::Int32Size( _reflection->GetRepeatedInt32( *_message, field, index ) ); } proto_tree_add_int( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedInt32( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_FLOAT: len+= WireFormatLite::kFloatSize; proto_tree_add_float( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedFloat( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_UINT64: if( field->type() == FieldDescriptor::TYPE_FIXED64 ) { len+= WireFormatLite::kFixed64Size; } else { len+= WireFormatLite::UInt64Size( _reflection->GetRepeatedUInt64( *_message, field, index ) ); } proto_tree_add_uint64( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedUInt64( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_INT64: if( field->type() == FieldDescriptor::TYPE_SFIXED64 ) { len+= WireFormatLite::kSFixed64Size; } else if( field->type() == FieldDescriptor::TYPE_SINT64 ) { len+= WireFormatLite::SInt64Size( _reflection->GetRepeatedInt64( *_message, field, index ) ); } else { len+= WireFormatLite::Int64Size( _reflection->GetRepeatedInt64( *_message, field, index ) ); } proto_tree_add_int64( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedInt64( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_DOUBLE: len+= WireFormatLite::kDoubleSize; proto_tree_add_double( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedDouble( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_BOOL: len+= WireFormatLite::kBoolSize; proto_tree_add_boolean( _leaf, handles->handle, _tvb, _offset, len, _reflection->GetRepeatedBool( *_message, field, index ) ); break; case FieldDescriptor::CPPTYPE_ENUM: enumDesc = _reflection->GetRepeatedEnum( *_message, field, index ); len+= WireFormatLite::EnumSize( enumDesc->number() ); proto_tree_add_int_format_value( _leaf, handles->handle, _tvb, _offset, len, ///mawu enumDesc->number(), "%d ( %s )", enumDesc->number(), enumDesc->name().c_str() ); // Fromutf8tostring= Utf8ToString(enumDesc->name()); // mylog.debug("Fromutf8tostring",Fromutf8tostring); // proto_tree_add_int_format_value( _leaf, handles->handle, _tvb, _offset, len, // enumDesc->number(), "%d ( %s )", enumDesc->number(), //Fromutf8tostring.c_str() ); // Fromutf8tostring=""; break; case FieldDescriptor::CPPTYPE_STRING: len+= WireFormatLite::StringSize( _reflection->GetRepeatedStringReference( *_message, field, index, &scratch ) ); //proto_tree_add_string( _leaf, handles->handle, _tvb, _offset, len, // _reflection->GetRepeatedString( *_message, field, index ).c_str() ); ///mawuFromutf8tostring=Utf8ToString (_reflection->GetRepeatedString( *_message, field, index ));//mylog.debug("Fromutf8tostring2",Fromutf8tostring); proto_tree_add_string( _leaf, handles->handle, _tvb, _offset, len, Fromutf8tostring.c_str()); Fromutf8tostring=""; break; default: proto_tree_add_item( _leaf, handles->handle, _tvb, _offset, len, true ); }; _offset+=len; } class ErrorCollector : public protobuf::compiler::MultiFileErrorCollector { // Implementation of MultiFileErrorCollector interface. void AddError(const string & filename, int line, int column, const string & message) { DBG( "Error in file " << filename << " at line/col:" << line << "/" << column << message ); } }; protobuf_MessageConfig::protobuf_MessageConfig() : _desc( NULL ) { } protobuf_MessageConfig::protobuf_MessageConfig( const std::string& filename, const std::string& dirname ) : _desc( NULL ) { parseConfigFile( filename, dirname ); } int protobuf_MessageConfig::dissect(proto_tree* tree_root, int item_id, tvbuff_t* tvb, void* buf, int buf_size) { DynamicMessageFactory factory; Message* msg = factory.GetPrototype( _desc )->New(); if (!msg->ParseFromArray((char *) buf, buf_size)) { wireshark_pb_add_protobuf(tree_root,tvb,item_id,"Failed parse message"); DBG_ERR( "Failed to parse message." ); /* for (int i=0; i < buf_size; i++) { printf("%2x ", ((char *)buf)[i]); } */ /* printf("buf size=%d\n", buf_size); printf("%s\n\n\n", buf); */ return -1; } // store tvb for subsequent calls _tvb = tvb; int offset = 0; DissectorList dissectorList; // we process the message tree breadth wise dissectorList.push_back( protobuf_Dissector( tree_root, offset, msg, NULL ) ); while ( !dissectorList.empty() ) { protobuf_Dissector dissector = dissectorList.front(); dissectorList.pop_front(); // this can add further entries to message dissector list dissector.dissect( dissectorList ); } // while( !dissectorList.empty() ) return 0; } void Tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters = " ") { // Skip delimiters at beginning. std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); // Find first "non-delimiter". std::string::size_type pos = str.find_first_of(delimiters, lastPos); //mylog.debug("tokens content ",str); while (std::string::npos != pos || std::string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // Skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // Find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } } int stringtoint(string s1){int sum=0;for (int i=0 ;i< s1.size();++i){sum=sum*10+s1[i]-'0';}return sum;}bool protobuf_MessageConfig::isValid() { return ( _desc != NULL ); } bool protobuf_MessageConfig::matchesDestPort( int port ) { return matchesPort( _dstPorts, port ); } bool protobuf_MessageConfig::matchesSrcPort( int port ) { return matchesPort( _srcPorts, port ); } bool protobuf_MessageConfig::matchesPort( PortList& portList, int port ) { for( PortList::iterator it = portList.begin(); it != portList.end(); it++ ) { if( *it == port ) return true; } return false; } void protobuf_MessageConfig::parseConfigFile( const std::string& filename, const std::string& dirname ) { std::ifstream infile; infile.open( ( dirname + "/" + filename ).c_str() ); if( infile.fail() ) { DBG_ERR( "Failed to open " << filename << "in dir " << dirname ); return; } std::string line; std::string message_name; while( !infile.eof() ) { std::getline( infile, line ); // skip lines beginning with # if( line[0] == '#' ) continue; std::vector<std::string> tokens; Tokenize( line, tokens, " =" ); //DBG( "Found " << tokens.size() << " tokens" ); // skip lines which have less that 2 tokens if( tokens.size() < 2 ) continue; if( tokens[0] == "name" ) { message_name = tokens[1]; //mylog.debug("message_name",message_name); continue; } if( tokens[0] == "proto_file" ) { if( importer == NULL ) { protobuf::compiler::DiskSourceTree *sourceTree = new protobuf::compiler::DiskSourceTree(); static ErrorCollector* errorCollector = new ErrorCollector(); sourceTree->MapPath( "", dirname ); importer = new protobuf::compiler::Importer( sourceTree, errorCollector ); } DBG( "filename to import " << tokens[1] ); const FileDescriptor* fileDesc = importer->Import( tokens[1] ); //mylog.debug("proto_file", tokens[1] ); if( fileDesc == NULL ) { DBG_ERR("Unable to parse " << tokens[1] ); continue; } DBG( "searching for message " << message_name ); //for( int i = 0; i < fileDesc->message_type_count(); i++ ) //{ // DBG(" message " << fileDesc->message_type( i )->name() ); //} _desc = fileDesc->FindMessageTypeByName( message_name ); continue; } if(tokens[0]=="message_id"){//mylog.debug("message_id", tokens[1] );message_selfid=stringtoint(tokens[1]);//mylog.debug("message_id_ind", message_selfid);} bool src_port = false; bool dst_port = false; bool both_ports = false; src_port = ( tokens[0] == "src_port" ); dst_port = ( tokens[0] == "dst_port" ); both_ports = ( tokens[0] == "port" ); for( int i = 1; i < tokens.size(); i++ ) { int port = atoi( tokens[i].c_str() ); //mylog.debug("port_id ", port); if( src_port || both_ports ) { _srcPorts.push_back( port ); } if( dst_port || both_ports ) { _dstPorts.push_back( port ); } } } infile.close(); if( _desc == NULL ) { DBG_ERR( "Couldnt get descriptor from " << filename ); _dstPorts.clear(); _srcPorts.clear(); } } void protobuf_MessageConfig::register_ports() { register_ports( _srcPorts ); register_ports( _dstPorts ); } void protobuf_MessageConfig::register_ports( PortList& portList ) { for( PortList::iterator it = portList.begin(); it != portList.end(); it++ ) { wireshark_pb_process_protobuf_dissector_add( "tcp.port", *it ); // 注册TCP端口,本人添加 wireshark_pb_process_protobuf_dissector_add( "udp.port", *it ); // 注册UDP端口 } } void protobuf_MessageConfig::register_proto( int proto ) { if( handleMap == NULL ) { handleMap = new HandleMap(); } DescriptorList messageDescriptorList; FieldDescriptorList fieldDescriptorList; // we process the message definition depth first messageDescriptorList.push_back( _desc ); while( !messageDescriptorList.empty() ) { const Descriptor* messageDescriptor = messageDescriptorList.back(); messageDescriptorList.pop_back(); DBG( "Register message ( " << messageDescriptor->name() << " )" ); wireshark_pb_process_protobuf_register_subtree_( proto, messageDescriptor->name(), messageDescriptor->full_name() ); for( int i = 0; i < messageDescriptor->field_count(); i++ ) { const FieldDescriptor* fieldDescriptor = messageDescriptor->field( i ); if( fieldDescriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) { messageDescriptorList.push_back( fieldDescriptor->message_type() ); } else { fieldDescriptorList.push_back( fieldDescriptor ); } } } // process all field descriptors at very end while( !fieldDescriptorList.empty() ) { const FieldDescriptor* fieldDescriptor = fieldDescriptorList.back(); fieldDescriptorList.pop_back(); Handles *handles = new Handles(); DBG( "Register field ( " << fieldDescriptor->name() << " : " << fieldDescriptor->full_name() << " )" ); wireshark_pb_process_protobuf_register_field( proto, wireshark_pb_process_protobuf_get_type( fieldDescriptor->cpp_type() ), fieldDescriptor->name().c_str(), fieldDescriptor->name().c_str(), &(handles->handle) ); handleMap->insert( StringHandlePair( fieldDescriptor->full_name(), handles ) ); } } }
9.修改plugins目录下的Makefile.nmake,增加protobuf工程的编译。重新编译wireshark。
提示:需要下载dirent-1.13.zip,解压后把dirent.h放到VC\Include目录下面,这是一个模拟linux dir相关接口的源代码。
10.把 plugins\protobuf\protobuf.dll 拷贝到wireshark安装目录下plugins\版本号\ 目录下。
11. 在wireshark 安装目录下创建protobuf目录,用于放置protobuf的配置文件和消息定义文件。
12.启动你的wireshark,可以开始抓包分析google protobuf消息了
- protobuf-wireshark编译小结
- Wireshark-protobuf编译小结
- wireshark protobuf 插件
- [ProtoBuf]protobuf编译命令
- 编译 protobuf
- protobuf编译
- protoBuf编译
- 编译wireshark
- C++ ProtoBuf小结
- protobuf-c学习小结
- Wireshark插件开发小结
- wireshark插件开发小结
- Wireshark要点小结
- 交叉编译 google protobuf
- mingw下编译protobuf
- 交叉编译 google protobuf
- ubuntu下编译protobuf
- Protobuf编译原理
- MySQL 5.6 for Windows 解压缩版配置安装
- java pdf转换jpg
- 错误分析之ServletActionContext.getServletContext()标红
- Mac-PHPStorm_下载php7(php5)问题
- springMvc的异常处理
- Wireshark-protobuf编译小结
- 【JQuery】用JQuery来监听浏览器改变窗口大小事件
- hdu4791 Labyrinth
- Hive java编程提交查询语句和配置
- 窗体的生成
- SQL学习笔记8——查询到数据库的值为null在C#中如何判断
- DepthBinaryTree leetcode java python
- Hbase 学习笔记一 》starting from scrath
- Android USER 版本与ENG 版本的差异--MTK官方解释