免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 12942 | 回复: 4
打印 上一主题 下一主题

wireshark源码分析问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-04-02 12:27 |只看该作者 |倒序浏览
这几天在看wireshark(ethereal)源代码。看源代码的主要兴趣点是它的分析模块(dissect)。分析之后他的数据存在哪儿,怎么打印的(-V参数)。我想把分析后的数据,提取出来,存在自己定义的数据结构里面,或者按我自己的格式写入文本中。

看了几天,对一些数据结构,似懂非懂,一些流程也是似懂非懂。可能由于经验不足的原因,搞来搞去就在几个函数,结构体里面打转。好几次以为找到切入点,发现又回来原来的起点。
这两天看晕了。有点打击,水平太差劲了。。呵呵。先这边问问,看看有没有熟悉的朋友。指点一下。先谢谢了。


这样问问题可能太细了。感觉也不大合适。
1.        我应该如何来看代码?如何找到突破点?
2.        有wireshark有了解的朋友,说说你们关于源码剖析的体会。
3.        说什么都可以,朋友觉得对我有用,有启发就好。千万别 “我顶,UP啊”。呵呵

论坛徽章:
0
2 [报告]
发表于 2010-04-02 13:15 |只看该作者
我觉得重要的是看
pcap库

论坛徽章:
0
3 [报告]
发表于 2010-04-02 16:31 |只看该作者
本帖最后由 peidright 于 2010-04-02 16:36 编辑

楼上说得对!。
看源代码之前,问下你自己,看代码的目的是什么?

对于 wireshark 来说,你是想学他写界面? 还是抓包? 还是业务逻辑?

界面的话,wireshark 还行
抓包的话,应该看pcap库
业务逻辑的话。不应该看wireshark,看tcpdump.

论坛徽章:
0
4 [报告]
发表于 2011-01-03 08:59 |只看该作者
看下啊,

论坛徽章:
0
5 [报告]
发表于 2011-01-03 10:37 |只看该作者
看看这个也许对你有帮助

添加一个基础的RDP解析器
下面我们将循序渐进地设计一个基础的RDP解析器。它依次包含如下构成要素:

         包类型字段(占用8比特位,可能的值为:1,初始;2,终结;3,数据);
         标志集字段(占用8比特位:0x01,开始包;0x02,结束包;0x04先包);
         序列号字段(占用16比特位);
1.      创建解析器
首先您需要选择解析器的类型:内置型(包含在主程序中)或插件型。 插件是容易编写的,先做一个插件型解析器吧。
例1. 解析器初始设定.
           
            

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <epan/packet.h>
#include <epan/prefs.h>

/* forward reference*/
void proto_register_rdp();
void proto_reg_handoff_rdp();
static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree);

static int proto_rdp=-1;

static dissector_handle_t rdp_handle;
static gint ett_rdp = -1;

define TCP_PORT_RDP 3389

void proto_register_rdp(void)
{
    proto_rdp=proto_register_protocol( "RDP Protocol", "RDP", "rdp");
}

现在来逐一分析这段代码。首先我们有一些常规的包含文件,最好依惯例在文件开始包含进来。随后是一些函数的前置声明,我们稍后定义它们。
接下来我们定义了一个整型变量"proto_rdp"用于记录我们的协议注册信息。它被初始化为"-1",当解析器注册到主程序中后,其值便会得到更新。这样做可保证我们方便地判断是否已经做了初始工作。将所有不打算对外输出的全局变量和函数声明为"static"是一个良好的习惯,因为这可以保证命名空间不被污染。通常这是容易做到的,除非您的解析器非常庞大以致跨越多个文件。
之后的模块变量"TCP_PORT_RDP"则包含了协议使用的TCP端口号,我们会对通过该端口的数据流进行解析。
紧随其后的是解析器句柄"rdp_handle",我们稍后对它进行初始化。
至此我们已经拥有了和主程序交互的基本元素,接下来最好再把那些预声明的函数定义一下,就从注册函数"proto_register_rdp"开始吧。
首先调用函数"proto_register_protocol"注册协议。我们能够给协议起3个名字以适用不同的地方。全名和短名用在诸如"首选项(Preferences)"和"已激活协议(Enabled protocols)"对话框以及记录中已生成的域名列表内。缩略名则用于过滤器。
下面我们需要一个切换函数。
例2. 解析器切换.

void proto_reg_handoff_rdp(void)
{
    static gboolean initialized=FALSE;

     if(!initialized)
     {
       rdp_handle = create_dissector_handle(dissect_rdp, proto_rdp);
       dissector_add("tcp.port", TCP_PORT_RDP, rdp_handle);
       initialized=TRUE;
     }
}
这段代码做了什么呢?如果解析器尚未初始化,则对它进行初始化。首先创建解析器。这时注册了了函数"dissect_rdp"用于完成实际的解析工作。之后将该解析器与TCP端口号相关联,以使主程序收到该端口的UDP数据流时通知该解析器。
至此我们终于可以写一些解析代码了。不过目前我们仅写点儿基本功能占个位置。

例3.解析

static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree)
{
    if(check_col(pinfo->cinfo, COL_PROTOCOL))
    {
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDP");
    }
    /* Clear out stuff in the info column */
    if(check_col(pinfo->cinfo,COL_INFO))
    {
        col_clear(pinfo->cinfo,COL_INFO);
    }
}

该函数用于解析传递给它的数据包。包数据由"tvb"参数指向的特殊缓冲区保管。现在我们已深入到协议的细节,对它们您肯定是了若指掌。包信息结构参数"pinfo"包含了协议的基本数据,以供我们更新。参数"tree"则指明了详细解析发生的地方。
这里我们仅做了保证通过的少量工作。前两行检查UI中"协议(Protocol)"列是否已显示。如果该列已存在,就在这儿显示我们的协议名称。这样人们就知道它被识别出来了。另外,如果"信息(INFO)"列已显示,我们就将它的内容清除。
至此我们已经准备好一个可以编译和安装的基本解析器。不过它目前只能识别和标示协议。
为了编译解析器并创建插件,还需要在解析器代码文件"packet-rdp.c"所在目录下创建一些提供支持的文件:
-          Makefile.am - UNIX/Linux的makefile模板
-          Makefile.common - 包含了插件文件的名称
-          Makefile.nmake - 包含了针对Windows平台的Wireshark插件makefile
-          moduleinfo.h - 包含了插件版本信息
-          moduleinfo.nmake - 包含了针对Windows平台的DLL版本信息
-          packet-rdp.c - 这是您的解析器原代码文件
-          plugin.rc.in - 包含了针对Windows平台的DLL资源模板
"Makefile.common"和"Makefile.am"文件中涉及到相关文件和解析器名称的地方一定要修改正确。"moduldeinfo.h"和"moduleinfo.nmake"文件中的版本信息也需要正确填充。一切准备妥善后就可以将解析器编译为DLL或共享库文件了(使用nmake工具)。在wireshark文件夹下的"plugins"文件夹中,建立"rdp"文件夹。将修改过的Makefile.common,Makefile.am,moduleinfo.nmake,moduldeinfo.h,Makefile.nmake及packet-rdp.c文件考到"rdp"文件夹下,然后进行编译,rdp插件自动生成完整,就可以正常工作了。
1.      解析协议细节
    现在我们已经有了一个可以运用的简单解析器,让我们再为它添点儿什么吧。首先想到的应该就是标示数据包的有效信息了。解析器在这方面给我们提供了支持。
首先要做的事情是创建一个子树以容纳我们的解析结果。这会使协议的细节显示得井井有条。现在解析器在两种情况下被调用:其一,用于获得数据包的概要信息;其二,用于获得数据包的详细信息。这两种情况可以通过树指针参数"tree"来进行区分。如果树指针为NULL,我们只需要提供概要信息;反之,我们就需要拆解协议完成细节的显示了。基于此,让我们来增强这个解析器吧。
例4
static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree)
{
    proto_item *ti=NULLV;
    if(check_col(pinfo->cinfo,COL_PROTOCOL))
    {
       col_set_str(pinfo->cinfo,COL_PROTOCOL,"RDP");
    }
    /* Clear out stuff in the info column */
    if(check_col(pinfo->cinfo,COL_INFO))
    {
       col_clear(pinfo->cinfo,COL_INFO);
    }
    if(tree)
    {
        ti = proto_tree_add_item(tree, proto_rdp, tvb, offset, -1, FALSE);}
    }


这里我们为解析添加一个子树。它将用于保管协议的细节,仅在必要时显示这些内容。
我们还要标识被协议占据的数据区域。在我们的这种情况下,协议占据了传入数据的全部,因为我们假设协议没有封装其它内容。因此,我们用"proto_tree_add_item"函数添加新的树结点,将它添加到传入的协议树"tree"中,用协议句柄"proto_rdp"标识它,用传入的缓冲区"tvb"作为数据,并将有效数据范围的起点设为"0",长度设为"-1"(表示缓冲区内的全部数据)。至于最后的参数"FALSE",我们暂且忽略。
做了这个更改之后,在包明细面板区中应该会出现一个针对该协议的标签;选择该标签后,在包字节面板区中包的剩余内容就会高亮显示。
现在进入下一步,添加一些协议解析功能。在这一步我们需要构建一组帮助解析的表结构。这需要对"proto_register_rdp"函数做些修改。首先定义一组静态数组。
例5     定义数据结构
static hf_register_info hf[]=
{
     {
           &hf_rdp_version,
           {
                "TPKT Header:Version",
                "rdp.version",
                FT_UINT8,
                BASE_DEC,
                NULL,
                0x0,
                "Version, only version 3 is defined",
                HFILL
           }
      },
}


接下来,在协议注册代码之后,我们对这些数组进行注册。
例6     注册数据结构
proto_register_field_array(proto_rdp, hf, array_length(hf));

proto_register_subtree_array(ett, array_length(ett));

例7     解析器全局数据结构
static int hf_rdp_version     = -1;
static gint ett_rdp           = -1;

现在我们就可以对协议细节的显示做一番改善了。
例 8 解析器开始数据解析


static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree)
{
     proto_item *ti=NULL;
     proto_tree *rdp_tree=NULL;

     if(tree)
     {
        version = tvb_get_guint8(tvb, offset); //get version
        if(version == 3)
        {
             ti = proto_tree_add_item(tree, proto_rdp, tvb, offset, -1, FALSE);
             rdp_tree = proto_item_add_subtree(ti, ett_rdp);
              /* Version */
             proto_tree_add_item(rdp_tree, hf_rdp_version, tvb, offset, 1, FALSE);
             offset += 1;
        }
     }
}

我们提取出协议的第一部分。数据包的首字节定义了rdp协议的包类型。
函数"proto_item_add_subtree"的调用在协议树中添加了一个子树,我们就在这里进行细节解析。子树的展开受控于变量"ett_rdp"。当您在协议间切换时,由它记录子树是否展开。正像您从下面的函数调用中看到的那样,随后的所有解析都会添加到该子树中。函数"proto_tree_add_item"用于为子树"rdp_tree"添加项,这次调用使用变量"hf_rdp_version"控制项格式。PDU(协议数据单元)类型是一个单字节数据,位于数据包的首字节,我们将有效数据范围的起点设为"0",长度设为"1"。我们假设它依照网络字节顺序,所以将最后一个参数设为"FALSE"("TRUE"表示"little endian","FALSE"表示"big endian")。尽管对于单字节数据无所谓字节顺序,但我们最好还是保持指定字节顺序的良好习惯。
如果详细查看静态数组中"hf_rdp_pdu_type"的声明,我们能够获悉定义的明细。
-          hf_rdp_version:节点索引。
-          TPKT Header:Version:项标示。
-          rdp.version:过滤字符串。我们可以在过滤框中输入诸如"rdp.version=1"的结构。
-          FT_UNIT8:指定该项数据是一个8比特位的无符号整型。这和我们之前调用函数时设置的一字节有效数据是相一致的。
-          BASE_DEC:针对整型数据,指定将其作为十进制数显示。当然视具体情况也可以设置为"BASE_HEX"(十六进制)和"BASE_OCT"(八进制),以使数据更易辨识。
至于结构中余下的部分我们暂且忽略。
如果您现在安装并试用这个插件,就会发现一些有用的东西了。
接下来让我们完成这个简单协议的tpkt头部的解析工作吧。我们需要再添加一些hf数组成员和程序调用。

例 9  

//添加到文件开始的某个地方做全局变量
static int hf_rdp_reserved    = -1;
static int hf_rdp_length      = -1;
//添加到"proto_register_rdp"函数中的"hf"数组中,作为数组的成员

  {
   &hf_rdp_reserved,
   {
    "TPKT Header:Reserved",
    "rdp.reserved",                                          //添加到"dissect_rdp"函数中,实现数据包的解析
    FT_UINT8,
    BASE_DEC,
    NULL,
    0x0,
    "Reserved, should be 0", HFILL
   }
  },

{
   &hf_rdp_length,
   {
    "TPKT Header:Length",
    "rdp.length",
    FT_UINT16,
    BASE_DEC,
    NULL,
    0x0,
    "Length of data unit, including this header", HFILL
   }
  },
//添加到"dissect_rdp"函数中,实现数据包的解析
/* Reserved*/
   proto_tree_add_item(rdp_tree, hf_rdp_reserved, tvb, offset, 1, FALSE);
   offset += 1;
   /* length */
   data_len = tvb_get_ntohs(tvb, offset);
   proto_tree_add_uint(rdp_tree, hf_rdp_length, tvb, offset, 2, data_len);
   offset += 2;

我们引入了一个新的变量"offset"以记录数据包解析的位置。将这些额外的代码块放入合适的位置,整个协议就可以得到全面的解析。这样TPKT头部的信息就添加到解析代码中,若要再添加其他解析字段,需要根据具体情况,将字段与判断条件一同添加。   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP