zoukankan      html  css  js  c++  java
  • NetAnalyzer笔记 之 三. 用C++做一个抓包程序

    [创建时间:2015-08-27 22:15:17]

    NetAnalyzer下载地址

    经过前两篇的瞎扯,你是不是已经厌倦了呢,那么这篇让我们来点有意思的吧,什么,用C#。不,这篇我们先来C++的

    Winpcap开发环境配置

    完成了对Winpcap的介绍,什么,你没看到Winpcap的介绍,左转,百度(其实,真的是不想复制)。我们就需要做一点有用的事情,比如写一个简单的数据采集工具。当然在此之前,我们需要配置Winpcap的开发环境。

    (1) 运行环境设置

    Win32 平台下Winpcap应用程序需要以下四个动态链接库才能正常运行:wpcap.dll Packet.dll WanPacket.dll pthreadVC.dll,这四个动态链接库在WinPcap驱动程序里。如果没有这个驱动程序,需要到WinPcap官方网站上下载,下载地址为:www.WinPcap.org。下载完后点击安装即可完成Winpcap核心驱动的配置,即计算机有了最初的运行基础。

    (2) 开发环境的配置

    本次开发使用的组件是由Winpcap官方提供的SDK,从http://www.WinPcap.org  下载Winpcap 的SDK ——WpdPack,

    也可以直接在这里下载:http://pan.baidu.com/s/1hqKtsOk

    当然在此之前你的爱机一定要装Winpcap

    WinPcap SDk里面包含库文件,头文件,文档文件和一些例子。解压到一个指定的目录。

                                 图1 WpdPack

    其中的docs为E文,如果E实在不行 点这里http://pan.baidu.com/s/1hqHB6Pu

    示例我已经在Visual Studio 2010 下成功过通过

    接下来我们看看如何配置

    解压缩后把Include目录与Lib目录添加到开发环境中。VC6.0环境如图2所示,

    VC6.0: 菜单栏Tools->Option->Directory,在下拉列表Show directories for:中选择Include files对话框中配置Include目录,我将该文件放在D:WPDPACKINCLUDE文件夹下。同样改变Show directories for:选中Library files配置Lib目录。

     

                          图2 VC6.0环境下Include目录与Lib目录配置

    VS2010环境如图3所示,

    Visual Studio 2010: 菜单栏 工具->选项->项目和解决方案/项目->VC++目录。有时候可能出现“目录编辑功能被否决”的情况,可以通过 菜单栏 项目->XXX属性->配置属性->VC++目录 中配置,本次使用的就是这种方式。

                        图3 Visual  Studio 2010环境下Include目录与Lib目录配置

                 

    通过上面的方式完成了文件引入部分的配置,接下来是导入库文件的方法,在VC6.0中也叫做链接库的配置。

    VC6.0:菜单栏Project->Settings->Link->Object/library modules,在其中添加wpcap.lib,Packet.lib,点击OK即可。如图4

                                  图4 VC6.0环境下链接库文件配置

    Visual Studio 2010:右击 解决方案资源管理器->添加->现有项…导入Packet.lib和wpacp.lib库文件即可。如图5

               图5 .Net中导入的库文件

    完成了库文件的配置,现在开始本次配置的最后一步:

    新的版本里WinPcap支持远程数据包获取,所以还应当添加一个头文件remote-ext.h ,即#include "remote-ext.h"(记住这条语句要放在#include”pcap.h”之后,否则会出错!)

    否则会发生下面的错误:

    error C2065: “PCAP_SRC_IF_STRING”: 未声明的标识符

    error C3861: “pcap_findalldevs_ex”: 找不到标识符

    error C2065: “PCAP_OPENFLAG_PROMISCUOUS”: 未声明的标识符

    error C3861: “pcap_open”: 找不到标识符

    虽然上面提供了一些解决方法,但似乎没什么作用,于是需要在开发环境中进行配置,因为VC6.0在Windows7下兼容问题,尝试多次未成功运行,所以此处只给出Visual Studio 2010中的配置结果

    或者不用添加#include "remote-ext.h".在VC.NET提供的IDE环境中,可以通过执行“项目”菜单中的的“属性”进入该项目的属性配置页,通过选择“配置属性”树中的“C/C++预处理库”选项就增加”WPCAP”和”HAVE_REMOTE”两个标号,。如图6所示

                   图6 Visual Studio 2010环境下WPCAP与HAVE_REMOTE标号的配置

     Winpcap编程实现

    通过上面的配置完成了对Winpcap开发环境搭建,接下来我们就可以做一个小程序了。在做抓包程序之前,我们首先要确定从何处采集数据,大家首先想到的就是网卡,所以,第一步就是要获取网卡:

    步骤:

     (a)  打开Visual Studio 2010 新建项目,语言选择C++,类型选择Win32控制台应用程序,点击确定按钮。

                                            图7 新建项目

     (b)  进入想到页面,直接点击下一步,进入第二个页面,因为我们要使用C语言来制作该程序,但是在Visual Studio 2010并没用提供专用的C开发环境,所以上一步中我们选择的是C++模板,因此在接下来的页面,我们要在附加选项中选择“空项目”,这样开发环境就不会导入一些关于C++的东西了,点击完成。

     

                                           图8 选择空项目

    (c) 于是开发环境为我们配置了一个空项目,在解决方案资源管理器中选择源文件,右击在菜单中添加选择新建项,此时打开新建项对话框,找到C++文件,输入文件名称,注意,同时键入扩展名“.c,这样就可以建立一个C源文件,

                   图9 配置方案结果  

    (d) 然后按照上面的环境配置方案,对项目中Include目录lib目录进行配置;导入库文件;配置标识号;最后写入如下代码:

     1 #include "pcap.h"
     2 main()
     3 {
     4     pcap_if_t *alldevs;
     5     pcap_if_t *d;
     6     int i=0;
     7     char errbuf[PCAP_ERRBUF_SIZE];
     8     
     9     /* 获取本地机器设备列表 */
    10     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
    11     {
    12         fprintf(stderr,"Error in pcap_findalldevs_ex: %s
    ", errbuf);
    13         exit(1);
    14     }
    15     /* 打印列表 */
    16     for(d= alldevs; d != NULL; d= d->next)
    17     {
    18         printf("%d. %s", ++i, d->name);
    19         if (d->description)
    20             printf(" (%s)
    ", d->description);
    21         else
    22             printf(" (No description available)
    ");
    23     }
    24     
    25     if (i == 0)
    26     {
    27         printf("
    No interfaces found! Make sure WinPcap is installed.
    ");
    28         return;
    29     }
    30     /* 不再需要设备列表了,释放它 */
    31     pcap_freealldevs(alldevs);
    32 }

    该段代码来自Winpcap开发文档中的第一节,主要的任务是获取主机网卡设备。

     (e) 最后按Ctrl+F5启动,开始编译执行该段。

          结果:如图10

          这里的编程实现仅仅是为了演示,Winpcap的开发配置过程,更多更为详尽的实现过程请参阅Winpcap开发文档,从Winpcap官网即可获得,所以之后的一些实现原理并不是本书的重点,故不再赘述。

                                   图10 获取网卡执行结果

    如果只是,获取到网卡,那也没什么好讲的了,下面是一段示例中的代码,在这段代码中我们不但可以取到网卡,还可以进行数据分析

      1 #ifdef _MSC_VER
      2 /*
      3  * we do not want the warnings about the old deprecated and unsecure CRT functions
      4  * since these examples can be compiled under *nix as well
      5  */
      6 #define _CRT_SECURE_NO_WARNINGS
      7 #endif
      8 
      9 #include "pcap.h"
     10 
     11 /* 4 bytes IP address */
     12 typedef struct ip_address
     13 {
     14     u_char byte1;
     15     u_char byte2;
     16     u_char byte3;
     17     u_char byte4;
     18 }ip_address;
     19 
     20 /* IPv4 header */
     21 typedef struct ip_header
     22 {
     23     u_char    ver_ihl;        // Version (4 bits) + Internet header length (4 bits)
     24     u_char    tos;            // Type of service 
     25     u_short tlen;            // Total length 
     26     u_short identification; // Identification
     27     u_short flags_fo;        // Flags (3 bits) + Fragment offset (13 bits)
     28     u_char    ttl;            // Time to live
     29     u_char    proto;            // Protocol
     30     u_short crc;            // Header checksum
     31     ip_address    saddr;        // Source address
     32     ip_address    daddr;        // Destination address
     33     u_int    op_pad;            // Option + Padding
     34 }ip_header;
     35 
     36 /* UDP header*/
     37 typedef struct udp_header
     38 {
     39     u_short sport;            // Source port
     40     u_short dport;            // Destination port
     41     u_short len;            // Datagram length
     42     u_short crc;            // Checksum
     43 }udp_header;
     44 
     45 /* prototype of the packet handler */
     46 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
     47 
     48 
     49 int main()
     50 {
     51     pcap_if_t *alldevs;
     52     pcap_if_t *d;
     53     int inum;
     54     int i=0;
     55     pcap_t *adhandle;
     56     char errbuf[PCAP_ERRBUF_SIZE];
     57     u_int netmask;
     58     char packet_filter[] = "ip and udp"; 
     59     struct bpf_program fcode;
     60     
     61     /* Retrieve the device list */
     62     if(pcap_findalldevs(&alldevs, errbuf) == -1)
     63     {
     64         fprintf(stderr,"Error in pcap_findalldevs: %s
    ", errbuf);
     65         exit(1);
     66     }
     67     
     68     /* Print the list */
     69     for(d=alldevs; d; d=d->next)
     70     {
     71         printf("%d. %s", ++i, d->name);
     72         if (d->description)
     73             printf(" (%s)
    ", d->description);
     74         else
     75             printf(" (No description available)
    ");
     76     }
     77 
     78     if(i==0)
     79     {
     80         printf("
    No interfaces found! Make sure WinPcap is installed.
    ");
     81         return -1;
     82     }
     83     
     84     printf("Enter the interface number (1-%d):",i);
     85     scanf("%d", &inum);
     86     
     87     /* Check if the user specified a valid adapter */
     88     if(inum < 1 || inum > i)
     89     {
     90         printf("
    Adapter number out of range.
    ");
     91         
     92         /* Free the device list */
     93         pcap_freealldevs(alldevs);
     94         return -1;
     95     }
     96 
     97     /* Jump to the selected adapter */
     98     for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
     99     
    100     /* Open the adapter */
    101     if ((adhandle= pcap_open_live(d->name,    // name of the device
    102                              65536,            // portion of the packet to capture. 
    103                                             // 65536 grants that the whole packet will be captured on all the MACs.
    104                              1,                // promiscuous mode (nonzero means promiscuous)
    105                              1000,            // read timeout
    106                              errbuf            // error buffer
    107                              )) == NULL)
    108     {
    109         fprintf(stderr,"
    Unable to open the adapter. %s is not supported by WinPcap
    ");
    110         /* Free the device list */
    111         pcap_freealldevs(alldevs);
    112         return -1;
    113     }
    114     
    115     /* Check the link layer. We support only Ethernet for simplicity. */
    116     if(pcap_datalink(adhandle) != DLT_EN10MB)
    117     {
    118         fprintf(stderr,"
    This program works only on Ethernet networks.
    ");
    119         /* Free the device list */
    120         pcap_freealldevs(alldevs);
    121         return -1;
    122     }
    123     
    124     if(d->addresses != NULL)
    125         /* Retrieve the mask of the first address of the interface */
    126         netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    127     else
    128         /* If the interface is without addresses we suppose to be in a C class network */
    129         netmask=0xffffff; 
    130 
    131 
    132     //compile the filter
    133     if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
    134     {
    135         fprintf(stderr,"
    Unable to compile the packet filter. Check the syntax.
    ");
    136         /* Free the device list */
    137         pcap_freealldevs(alldevs);
    138         return -1;
    139     }
    140     
    141     //set the filter
    142     if (pcap_setfilter(adhandle, &fcode)<0)
    143     {
    144         fprintf(stderr,"
    Error setting the filter.
    ");
    145         /* Free the device list */
    146         pcap_freealldevs(alldevs);
    147         return -1;
    148     }
    149     
    150     printf("
    listening on %s...
    ", d->description);
    151     
    152     /* At this point, we don't need any more the device list. Free it */
    153     pcap_freealldevs(alldevs);
    154     
    155     /* start the capture */
    156     pcap_loop(adhandle, 0, packet_handler, NULL);
    157     
    158     return 0;
    159 }
    160 
    161 /* Callback function invoked by libpcap for every incoming packet */
    162 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
    163 {
    164     struct tm *ltime;
    165     char timestr[16];
    166     ip_header *ih;
    167     udp_header *uh;
    168     u_int ip_len;
    169     u_short sport,dport;
    170     time_t local_tv_sec;
    171 
    172     /*
    173      * unused parameter
    174      */
    175     (VOID)(param);
    176 
    177     /* convert the timestamp to readable format */
    178     local_tv_sec = header->ts.tv_sec;
    179     ltime=localtime(&local_tv_sec);
    180     strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
    181 
    182     /* print timestamp and length of the packet */
    183     printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
    184 
    185     /* retireve the position of the ip header */
    186     ih = (ip_header *) (pkt_data +
    187         14); //length of ethernet header
    188 
    189     /* retireve the position of the udp header */
    190     ip_len = (ih->ver_ihl & 0xf) * 4;
    191     uh = (udp_header *) ((u_char*)ih + ip_len);
    192 
    193     /* convert from network byte order to host byte order */
    194     sport = ntohs( uh->sport );
    195     dport = ntohs( uh->dport );
    196 
    197     /* print ip addresses and udp ports */
    198     printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d
    ",
    199         ih->saddr.byte1,
    200         ih->saddr.byte2,
    201         ih->saddr.byte3,
    202         ih->saddr.byte4,
    203         sport,
    204         ih->daddr.byte1,
    205         ih->daddr.byte2,
    206         ih->daddr.byte3,
    207         ih->daddr.byte4,
    208         dport);
    209 }

     在代码中只获取了UDP数据包,具体代码如下

      char packet_filter[] = "ip and udp"; 

    执行结果:

    图11 UDP数据包分析结果
    为了操作方便我把其他网卡禁用了

     在Winpcap 的开发包中还有其他示例额,自己慢慢去看吧

     本篇有卖弄嫌疑,但是也是让大家深入理解Winpcap的具体开发方法,在下一篇我们就一起使用winpcap抓包吧 ^_^

    NetAnalyzer下载地址

    NetAnalzyer交流群:39753670 (PS 只提供交流平台,群主基本不说话^_^)

    [转载请保留作者信息  作者:冯天文  网址:http://www.cnblogs.com/twzy/p/4765155.html]

  • 相关阅读:
    ASP.NET学习篇(4)——服务器端的控件【转自www.bitsCN.com】
    sql2005 管道的另一端上无任何进程解决方法
    SQL服务器名称的更改
    如何辨别移动硬盘的好坏
    ADO绑定SQL数据库过程
    SQL变量的使用
    SQL子查询
    什么SQL解发器?
    什么是存储过程呢?
    显式事务和隐式事务之间有什么区别?
  • 原文地址:https://www.cnblogs.com/twzy/p/4765155.html
Copyright © 2011-2022 走看看