zoukankan      html  css  js  c++  java
  • 调用wireshark(一):初次尝试

    众所周知,wireshark是一款强大的开源抓包与协议分析工具。wireshark是一个巨大的宝库:通过研究它的协议解析器代码,我们可以加深对协议的理解;通过调用它的导出函数,我们可以在自己的程序中添加协议解析、协议过滤等功能。

    这一系列文章就将一步步介绍在Windows平台上如何调用wireshark dll中提供的导出函数。

    wireshark导出函数

    windows版的wireshark在安装后,在安装根目录下有一个30多MB(视版本不同有所变化)的libwireshark.dll,没错,它就是我们将要调用的dll了。使用Dependency Walker打开它,如下图所示:

    红色框标出来的那个函数val_to_str, 我们接下来要用到。

    除了从这里查看wireshark的导出函数外,还可以查看 <wireshark源码目录>\epan\libwireshark.def 这个文件,来看特定版本的wireshark导出哪些变量和函数。

    环境配置与准备

    OK,接下来让我们写一点代码,来调用wireshark提供给我们的val_to_str函数。

    调用某个函数前,最好看看它的wireshark源码,以便我们能在自己的代码中声明此函数。比如这个val_to_str,它在<wireshark源码目录>\epan\value_string.h 中声明:

    /* Tries to match val against each element in the value_string array vs.
       Returns the associated string ptr on a match.
       Formats val with fmt, and returns the resulting string, on failure. */
    extern const gchar* val_to_str(const guint32 val, const value_string *vs, const char *fmt);

    那么这个value_string又是什么东东呢?其实它的声明也在这个文件里:

    /* Struct for the val_to_str, match_strval_idx, and match_strval functions */
    
    typedef struct _value_string {
      guint32  value;
      const gchar   *strptr;
    } value_string;

    呵呵,可见val_to_str函数的作用,就是返回value_string数组vs中value为val的项的字符串strptr。如果发生错误,则用fmt格式化val并返回。

    我们使用Win32 Console工程。首先必须做一些琐碎的准备工作,比如添加glib和wireshark的一些头文件和库,再比如把libwireshark.dll和它所依赖的各种dll拷贝到你的程序所在目录,随便你怎么做,总之,要让你的程序找得到libwireshark.dll和它的依赖项。比如我设置了:

    C/C++ - 常规 - 附加包含目录:
    "E:\dev\WiresharkDev1.8.4\gtk+-bundle_2.24.10-2.7_win32ws\include\glib-2.0";
    "E:\dev\WiresharkDev1.8.4\gtk+-bundle_2.24.10-2.7_win32ws\lib\glib-2.0\include";
    "E:\dev\wireshark-1.8.4"

    链接器 - 常规 - 附加库目录
    "E:\dev\WiresharkDev1.8.4\gtk+-bundle_2.24.10-2.7_win32ws\lib"

    链接器 - 输入 - 附加依赖项
    glib-2.0.lib

    然后,我把wireshark安装目录下,几乎所有dll拷贝到了我的工程的debug或release目录。

    开发代码

    其实代码很简单,主要过程就是:

    加载libwireshark.dll -> 从DLL实例中获取函数val_to_str的地址 -> 调用val_to_str。

    代码如下:

     1 /*
     2  * 调用wireshark的一个小函数
     3  *
     4  * Copyright (c) 2013 赵子清, All rights reserved.
     5  *
     6  */
     7 
     8 
     9 #include <Windows.h>
    10 #include <stdio.h>
    11 #include "epan/value_string.h"
    12 
    13 
    14 const value_string vs[] =  
    15 {  
    16     {1, "C++"},  
    17     {2, "java"},  
    18     {3, "php"}  
    19 };  
    20 
    21 typedef void (*f_emem_init) (void);
    22 typedef void (*f_ep_free_all) (void);  
    23 typedef const gchar* (*f_val_to_str) (guint32 val, const value_string *vs, const char *fmt);  
    24 
    25 
    26 int main(int argc, char* argv[])  
    27 {  
    28     HINSTANCE  hDLL;  
    29     f_emem_init     ws_emem_init;
    30     f_ep_free_all   ws_ep_free_all;  
    31     f_val_to_str    ws_val_to_str;  
    32 
    33     hDLL = ::LoadLibrary("libwireshark.dll");  
    34     if(!hDLL)  
    35     {  
    36         printf("Can't load DLL!\n");  
    37     }  
    38     else  
    39     {  
    40         ws_emem_init = (f_emem_init)::GetProcAddress(hDLL, "emem_init");
    41         ws_ep_free_all = (f_ep_free_all)::GetProcAddress(hDLL, "ep_free_all");
    42         ws_val_to_str = (f_val_to_str)::GetProcAddress(hDLL, "val_to_str");  
    43         if(!hDLL)  
    44         {  
    45             ::FreeLibrary(hDLL);  
    46             printf("Can't get function!\n");  
    47         }  
    48         else  
    49         {  
    50             const gchar* ret;  
    51             const gchar* fmt = "item not exist: %d";
    52             ws_emem_init();
    53             ret = ws_val_to_str(2, vs, fmt); 
    54             printf("%s\n", ret);
    55             ret = ws_val_to_str(9, vs, fmt); 
    56             printf("%s\n", ret);
    57             ret = ws_val_to_str(2, NULL, fmt);
    58             printf("%s\n", ret);
    59             ws_ep_free_all();
    60         }  
    61     }  
    62 
    63     system("PAUSE");  
    64     return 0;  
    65 }  


    有同学可能要问了:不是说好调用val_to_str的吗?为什么还要调用emem_init和ep_free_all?

    是这样的,前面提到过,当val_to_str函数各种失败时,它就用fmt格式化val,并返回。而返回的是一个字符串指针,那么它的内存需要由wireshark内部来进行分配,所以,就用到emem_init了,它在wireshark启动时调用一次,初始化内部的内存分配机制。而ep_free_all,好吧,是擦屁股的。。。

    写完收工,运行之,如下:

  • 相关阅读:
    队列分类梳理
    停止线程
    Docker和Kubernetes
    Future、Callback、Promise
    Static、Final、static final
    线程池梳理
    TCP四次挥手
    http1.0、http1.x、http 2和https梳理
    重排序
    java内存模型梳理
  • 原文地址:https://www.cnblogs.com/zzqcn/p/3072362.html
Copyright © 2011-2022 走看看