• 调用wireshark(二):调用协议解析器


    上文【调用wireshark(一):初次尝试 http://www.cnblogs.com/zzqcn/archive/2013/05/11/3072362.html 】已经介绍了调用wireshark的原理,并给出一个简单示例。本文要给出真正调用wireshark协议解析函数的方法和代码。

    本文的讨论和代码基于wireshark 1.8.4版本。

    涉及到的函数与数据结构

    首先我们得知道需要调用哪些函数。通过调试自己编译的wireshark,我发现如果要实现简单的协议解析,主要只需要以下几个函数(源码位置均相对于wireshark源码主目录而言):

    函 数 功 能       源码位置
    epan_init   初始化协议解析库 epan/epan.h
    epan_cleanup 清理协议解析库 同上
    epan_dissect_new 创建协议解析数据结构edt 同上
    epan_dissect_run 执行协议解析 同上
    epan_dissect_free 销毁协议解析数据结构edt 同上
    init_dissection 初始化数据包级协议解析 epan/packet.h
    cleanup_dissection  清理数据包级协议解析  同上

    除此之外,还需要导出一些辅助的函数,如register_all_protocols, register_all_protocol_handoffs,proto_item_fill_label等等。

    不仅如此,还需要熟悉协议解析过程所涉及到的一些数据结构,主要有:

    数据结构 功 能       源码位置
    epan_dissect_t   协议解析信息,保存协议数据及协议解析树 epan/epan.h; epan/epan_dissect.h
    field_info 协议字段信息 epan/proto.h
    header_field_info 协议首部字段信息 同上
    proto_tree/proto_node 协议树 同上
    frame_data 单帧(数据包)信息 epan/frame_data.h
    wtap_pseudo_header wtap伪首部,主要是链路层协议信息 wiretap/wtap.h

    以上就是一些主要的函数及数据结构。实际的协议解析过程中,可能会涉及到更多的函数及数据结构,这里就不多说了,具体可以查看wireshark源码。如果对于某些函数,或者解析过程有不了解的,也可以自己编译wireshark,然后调试它。

    代码实现

    知道原理及所需的函数后,就可以编码实现了。环境的配置等基础知识,本系列前一篇已经讲过了。

    我继续用Win32 Console工程来写这个示例。我这个示例代码分为两个部分:

    一、wireshark导出函数及简单的封装;
    二、实际解析代码

    第一个部分分成wireshark.h和wireshark.cpp两个文件。第二部分为dissector.cpp,其中也包括了main函数。

    wireshark导出函数及简单封装

    没什么好说的,主要就是所需函数的声明,以及动态调用代码。

    wireshark.h:

     1 /*
     2  * wireshark协议解析相关的导出函数声明,以及简单函数封装
     3  *
     4  * Copyright (c) 2013 赵子清, All rights reserved.
     5  *
     6  */
     7 
     8 
     9 #ifndef  __WIRESHARK_H__
    10 #define  __WIRESHARK_H__
    11 
    12 // see \wireshark-1.8.4\CMakeLists.txt, #481
    13 #define WS_VAR_IMPORT       __declspec(dllimport) extern
    14 // see \wireshark-1.8.4\CMakeLists.txt, #482
    15 #define WS_MSVC_NORETURN    __declspec(noreturn)
    16 
    17 #ifdef  TRY
    18 #undef  TRY 
    19 #endif
    20 #ifdef  CATCH
    21 #undef  CATCH
    22 #endif
    23 #ifdef  CATCH_ALL
    24 #undef  CATCH_ALL 
    25 #endif
    26 #ifdef  THROW
    27 #undef  THROW
    28 #endif
    29 
    30 
    31 // wireshark源码头文件
    32 #include "epan/epan.h"
    33 #include "epan/epan_dissect.h"
    34 #include "epan/proto.h"
    35 #include "epan/packet_info.h"
    36 #include "epan/frame_data.h"
    37 #include "epan/packet.h"
    38 #include <Windows.h>
    39 
    40 
    41 #define CHECK(x) if(!(x)) return FALSE;
    42 
    43 
    44 /* \register.h -------------------------------------------------------------------------*/
    45 typedef void (*register_cb) (register_action_e action, const char *message, gpointer client_data);
    46 typedef void (*f_register_all_protocols) (register_cb cb, gpointer client_data);
    47 typedef void (*f_register_all_protocol_handoffs) (register_cb cb, gpointer client_data);
    48 typedef void (*f_register_all_tap_listeners)(void);
    49 /*--------------------------------------------------------------------------------------*/
    50 
    51 /* \epan\packet.h ----------------------------------------------------------------------*/
    52 typedef void (*f_init_dissection) (void);
    53 typedef void (*f_cleanup_dissection) (void);
    54 /*--------------------------------------------------------------------------------------*/
    55 
    56 /* \epan\epan.h -------------------------------------------------------------------------*/
    57 typedef void (*f_epan_init) (void (*register_all_protocols)(register_cb cb, gpointer client_data),
    58                             void (*register_all_handoffs)(register_cb cb, gpointer client_data),
    59                             register_cb cb,
    60                             void *client_data,
    61                             void (*report_failure)(const char *, va_list),
    62                             void (*report_open_failure)(const char *, int, gboolean),
    63                             void (*report_read_failure)(const char *, int));
    64 typedef void (*f_epan_cleanup) (void);
    65 typedef epan_dissect_t* (*f_epan_dissect_new) (gboolean create_proto_tree, 
    66                                             gboolean proto_tree_visible);
    67 typedef void (*f_epan_dissect_run) (epan_dissect_t *edt, void* pseudo_header,
    68                             const guint8* data, frame_data *fd, column_info *cinfo);
    69 typedef void (*f_epan_dissect_free) (epan_dissect_t* edt);
    70 typedef void (*f_epan_dissect_fill_in_columns) (epan_dissect_t *edt);
    71 /*--------------------------------------------------------------------------------------*/
    72 
    73 /* \epan\proto.h -----------------------------------------------------------------------*/
    74 typedef void (*f_proto_item_fill_label) (field_info *fi, gchar *label_str);
    75 /*--------------------------------------------------------------------------------------*/
    76 
    77 extern f_epan_init                            ws_epan_init;
    78 extern f_epan_cleanup                        ws_epan_cleanup;
    79 extern f_register_all_protocols                ws_register_all_protocols;
    80 extern f_register_all_protocol_handoffs        ws_register_all_protocol_handoffs;
    81 extern f_init_dissection                    ws_init_dissection;
    82 extern f_cleanup_dissection                    ws_cleanup_dissection;
    83 extern f_epan_dissect_new                    ws_epan_dissect_new;
    84 extern f_epan_dissect_run                    ws_epan_dissect_run;
    85 extern f_epan_dissect_free                    ws_epan_dissect_free;
    86 extern f_proto_item_fill_label                ws_proto_item_fill_label;
    87 
    88 
    89 HINSTANCE  LoadWiresharkDLL(const TCHAR* szDLLPath);
    90 BOOL  FreeWiresharkDLL(HMODULE hModule);
    91 BOOL  GetWiresharkFunctions(HMODULE hDLL);
    92 
    93 #endif /* WIRESHARK_H_ */


    wireshark.cpp:

     1 /*
     2 * wireshark协议解析相关的导出函数声明,以及简单的函数封装
     3 *
     4 * Copyright (c) 2013 赵子清, All rights reserved.
     5 *
     6 */
     7 
     8 
     9 #include "wireshark.h"
    10 
    11 f_epan_init                                ws_epan_init;
    12 f_epan_cleanup                            ws_epan_cleanup;
    13 f_register_all_protocols                ws_register_all_protocols;
    14 f_register_all_protocol_handoffs        ws_register_all_protocol_handoffs;
    15 f_init_dissection                        ws_init_dissection;
    16 f_cleanup_dissection                    ws_cleanup_dissection;
    17 f_epan_dissect_new                        ws_epan_dissect_new;
    18 f_epan_dissect_run                        ws_epan_dissect_run;
    19 f_epan_dissect_free                        ws_epan_dissect_free;
    20 f_proto_item_fill_label                    ws_proto_item_fill_label;
    21 
    22 HINSTANCE  LoadWiresharkDLL(const TCHAR* szDLLPath)
    23 {
    24     return ::LoadLibrary(szDLLPath);
    25 }
    26 
    27 BOOL  FreeWiresharkDLL(HMODULE hModule)
    28 {
    29     return ::FreeLibrary(hModule);
    30 }
    31 
    32 BOOL  GetWiresharkFunctions(HMODULE hDLL)
    33 {
    34     CHECK(ws_epan_init = (f_epan_init)::GetProcAddress(hDLL, "epan_init"));
    35     CHECK(ws_epan_cleanup = (f_epan_cleanup)::GetProcAddress(hDLL, "epan_cleanup"));
    36     CHECK(ws_register_all_protocols = (f_register_all_protocols)
    37                     ::GetProcAddress(hDLL, "register_all_protocols"));
    38     CHECK(ws_register_all_protocol_handoffs = (f_register_all_protocol_handoffs)
    39                     ::GetProcAddress(hDLL, "register_all_protocol_handoffs"));
    40     CHECK(ws_init_dissection = (f_init_dissection)::GetProcAddress(hDLL, "init_dissection"));
    41     CHECK(ws_cleanup_dissection = (f_cleanup_dissection)::GetProcAddress(hDLL, "cleanup_dissection"));
    42     CHECK(ws_epan_dissect_new = (f_epan_dissect_new)::GetProcAddress(hDLL, "epan_dissect_new"));
    43     CHECK(ws_epan_dissect_run = (f_epan_dissect_run)::GetProcAddress(hDLL, "epan_dissect_run"));
    44     CHECK(ws_epan_dissect_free = (f_epan_dissect_free)::GetProcAddress(hDLL, "epan_dissect_free"));
    45     CHECK(ws_proto_item_fill_label = (f_proto_item_fill_label)::GetProcAddress(hDLL, "proto_item_fill_label"));
    46 
    47     return TRUE;
    48 }

    实际解析代码

    以下代码调用wireshark协议解析库,解析了一段数据。这段数据,如注释里所说,是我上网时随便用wireshark抓的。解析完成后,把结果输出到控制台。

    主要的流程是:

    动态调用所需的wireshark函数 -> 初始化协议解析库 -> 解析数据 -> 将解析结果按协议层次输出到控制台 -> 清理协议解析库。

    解析的结果主要是一个树形结构,因为我写了一个递归函数print_tree来遍历此树。

      1 /*
      2  * 调用wireshark解析库完成数据解析
      3  *
      4  * Copyright (c) 2013 赵子清, All rights reserved.
      5  *
      6  */
      7 
      8 #include "wireshark.h"
      9 #include <stdio.h>
     10 #include <tchar.h>
     11 
     12 #define DATA_LEN 73
     13 #define WIRESHARK_DLL_PATH  _T("E:\\dev\\wireshark-1.8.4\\release\\libwireshark.dll")
     14 
     15 // 帧数据, 不包括PCAP文件头和帧头
     16 // 数据为ethernet - ipv4 - udp - DNS, 上网时随便捕获的.
     17 const guchar data[DATA_LEN] = 
     18 {
     19 0x7E, 0x6D, 0x20, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
     20 0x00, 0x3B, 0x5F, 0x15, 0x00, 0x00, 0x40, 0x11, 0xF1, 0x51, 0x73, 0xAB, 0x4F, 0x08, 0xDB, 0x8D,
     21 0x8C, 0x0A, 0x9B, 0x90, 0x00, 0x35, 0x00, 0x27, 0xEF, 0x4D, 0x43, 0x07, 0x01, 0x00, 0x00, 0x01,
     22 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x74, 0x04, 0x73, 0x69, 0x6E, 0x61, 0x03, 0x63, 0x6F,
     23 0x6D, 0x02, 0x63, 0x6E, 0x00, 0x00, 0x01, 0x00, 0x01
     24 };
     25 
     26 
     27 void print_tree(proto_tree* tree, int level)
     28 {
     29     if(tree == NULL)
     30         return;
     31 
     32     for(int i=0; i<level; ++i)
     33         printf("    ");
     34 
     35     gchar field_str[ITEM_LABEL_LENGTH + 1] = {0};
     36     if(tree->finfo->rep == NULL)
     37         ws_proto_item_fill_label(tree->finfo, field_str);
     38     else
     39         strcpy_s(field_str, tree->finfo->rep->representation);
     40 
     41     if(!PROTO_ITEM_IS_HIDDEN(tree))
     42         printf("%s\n", field_str);   
     43 
     44     print_tree(tree->first_child, level+1);
     45     print_tree(tree->next, level);
     46 }
     47 
     48 void try_dissect()
     49 {
     50     frame_data  *fdata;
     51     epan_dissect_t  *edt;
     52     union wtap_pseudo_header  pseudo_header;
     53     pseudo_header.eth.fcs_len = -1;
     54 
     55     fdata = (frame_data*)g_new(frame_data, 1);
     56 
     57     memset(fdata, 0, sizeof(frame_data));
     58     fdata->pfd  = NULL;
     59     fdata->num = 1;
     60     fdata->interface_id = 0;
     61     fdata->pkt_len  = DATA_LEN;
     62     fdata->cap_len  = DATA_LEN;
     63     fdata->cum_bytes = 0;
     64     fdata->file_off = 0;
     65     fdata->subnum = 0;
     66     fdata->lnk_t = WTAP_ENCAP_ETHERNET;
     67     fdata->flags.encoding = PACKET_CHAR_ENC_CHAR_ASCII;
     68     fdata->flags.visited = 0;
     69     fdata->flags.marked = 0;
     70     fdata->flags.ref_time = 0;
     71     fdata->color_filter = NULL;
     72     fdata->abs_ts.secs = 0;
     73     fdata->abs_ts.nsecs = 0;
     74     fdata->opt_comment = NULL;
     75     
     76     edt = ws_epan_dissect_new(TRUE, TRUE);
     77     ws_epan_dissect_run(edt, &pseudo_header, data, fdata, NULL);
     78     print_tree(edt->tree->first_child, 0);
     79     ws_epan_dissect_free(edt);
     80     g_free(fdata);
     81 }
     82 
     83 
     84 int main(int argc, char** argv)
     85 {
     86     HINSTANCE hDLL = NULL;
     87     BOOL ret = FALSE;
     88     void* addr = NULL;
     89 
     90     hDLL = LoadWiresharkDLL(WIRESHARK_DLL_PATH);
     91     if(hDLL)
     92     {
     93         ret = GetWiresharkFunctions(hDLL);
     94         if(ret)
     95         {
     96             ws_epan_init(ws_register_all_protocols, ws_register_all_protocol_handoffs, 
     97                             NULL, NULL, NULL, NULL, NULL);
     98             ws_init_dissection();
     99             try_dissect();
    100             ws_cleanup_dissection();
    101             ws_epan_cleanup();
    102         }
    103         else
    104             fprintf(stderr, "某些导出函数获取失败!\n");
    105         FreeWiresharkDLL(hDLL);
    106     }
    107     else
    108         fprintf(stderr, "无法加载DLL!\n");
    109     
    110 
    111     system("PAUSE");
    112     return 0;
    113 }

     解析结果

     编译运行以上代码,控制台输出的解析结果如下:

    Frame 1: 73 bytes on wire (584 bits), 73 bytes captured (584 bits)
        WTAP_ENCAP: 1
        Frame Number: 1
        Frame Length: 73 bytes (584 bits)
        Capture Length: 73 bytes (584 bits)
        Frame is marked: False
        Frame is ignored: False
        Protocols in frame: eth:ip:udp:dns
    Ethernet II, Src: 01:00:01:00:00:00 (01:00:01:00:00:00), Dst: 7e:6d:20:00:01:00 (7e:6d:20:00:01:00)
        Destination: 7e:6d:20:00:01:00 (7e:6d:20:00:01:00)
            Address: 7e:6d:20:00:01:00 (7e:6d:20:00:01:00)
            .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
            .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        Source: 01:00:01:00:00:00 (01:00:01:00:00:00)
            Expert Info (Warn/Protocol): Source MAC must not be a group address: IEEE 802.3-2002, Section 3.2.3(b)
                Message: Source MAC must not be a group address: IEEE 802.3-2002, Section 3.2.3(b)
                Severity level: Warn
                Group: Protocol
            Address: 01:00:01:00:00:00 (01:00:01:00:00:00)
            .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
            .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
        Type: IP (0x0800)
    Internet Protocol Version 4, Src: 115.171.79.8 (115.171.79.8), Dst: 219.141.140.10 (219.141.140.10)
        Version: 4
        Header length: 20 bytes
        Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
            0000 00.. = Differentiated Services Codepoint: Default (0x00)
            .... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
        Total Length: 59
        Identification: 0x5f15 (24341)
        Flags: 0x00
            0... .... = Reserved bit: Not set
            .0.. .... = Don't fragment: Not set
            ..0. .... = More fragments: Not set
        Fragment offset: 0
        Time to live: 64
        Protocol: UDP (17)
        Header checksum: 0xf151 [correct]
            Good: True
            Bad: False
        Source: 115.171.79.8 (115.171.79.8)
                    Destination: 219.141.140.10 (219.141.140.10)
                    Source GeoIP: Unknown
        Destination GeoIP: Unknown
    User Datagram Protocol, Src Port: 39824 (39824), Dst Port: 53 (53)
        Source port: 39824 (39824)
        Destination port: 53 (53)
                Length: 39
            Checksum: 0xef4d [validation disabled]
            Good Checksum: False
            Bad Checksum: False
    Domain Name System (query)
        Transaction ID: 0x4307
        Flags: 0x0100 Standard query
            0... .... .... .... = Response: Message is a query
            .000 0... .... .... = Opcode: Standard query (0)
            .... ..0. .... .... = Truncated: Message is not truncated
            .... ...1 .... .... = Recursion desired: Do query recursively
            .... .... .0.. .... = Z: reserved (0)
            .... .... ...0 .... = Non-authenticated data: Unacceptable
        Questions: 1
        Answer RRs: 0
        Authority RRs: 0
        Additional RRs: 0
        Queries
            t.sina.com.cn: type A, class IN
                Name: t.sina.com.cn
                Type: A (Host address)
                Class: IN (0x0001)


    我们当然也可以在自己的GUI界面上,使用TreeCtrl来把解析结果显示给用户,就像下面这样(我写的工具的截图):

  • 相关阅读:
    win10 ubuntu 双系统启动顺序设置
    关于memset的使用
    POJ 2533 最小上升子序列
    Did Pong Lie? (差分系统 判负环)
    HDU 5828 Rikka with Sequence(线段树 开根号)
    SCU
    北邮校赛 I. Beautiful Array(DP)
    北邮校赛 H. Black-white Tree (猜的)
    北邮校赛 F. Gabriel's Pocket Money(树状数组)
    HDU 5862 Counting Intersections(离散化 + 树状数组)
  • 原文地址:https://www.cnblogs.com/zzqcn/p/3072909.html
Copyright © 2020-2023  润新知