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
需要注意的是我安装的时候还需要额外安装utility里面的U2D(unixtodos)包。

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消息了

0 0
原创粉丝点击