调用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来把解析结果显示给用户,就像下面这样(我写的工具的截图):

 

posted @ 2013-05-11 17:10  赵子清  阅读(9670)  评论(2编辑  收藏  举报