基于WinPcap实现的Raw EtherNet 抓包、发包程序

一、背景

  

二、WinPcap中文技术文档

  http://www.ferrisxu.com/WinPcap/html/index.html

二、需要使用到的动态库和外部头文件

  ① 库文件:Packet.dll、Packet.lib、wpcap.dll、wpcap.lib

  

  ② 头文件

  

三、用vs创建工程(我这里使用的是vs2015)

  工程创建完毕需要配置工程属性

  ① 右键工程属性-->VC++目录-->找到包含目录、库目录,把刚才的库文件路径和头文件的路径添加进去,如下图所示

  

  ② 找到链接器--->附加依赖项,添加Packet.lib、wpcap.lib库文件

  

四、示例代码

  ① 头文件

/*****************************************************************************                                            *                                                                          *
*  @file     RawEtherSniffer.h                                               *
*  @brief    通过原始以太网解析FPGA发送的数据                                 *
*  Details.                                                                  *
*                                                                            *
*  @author   jiang shuang                                                    *
*  @email                                                                     *
*  @version  1.0.0.0(版本号)                                                 *
*  @date                                                                     *
*  @license                                                                     *
*                                                                            *
*----------------------------------------------------------------------------*
*  Remark         : Description                                              *
*----------------------------------------------------------------------------*
*  Change History :                                                          *
*  <Date>     | <Version> | <Author>       | <Description>                   *
*----------------------------------------------------------------------------*
*  2019/09/10 | 1.0.0.0   | jiangshuang    | Create file                     *
*----------------------------------------------------------------------------*
*                                                                            *
*****************************************************************************/
#pragma once
#define WIN32
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>

class RawEtherTools
{
public:
    RawEtherTools();
    ~RawEtherTools();

    /**
    * @brief  以太网数据数据帧嗅探器
    * @input  无
    * @output 无
    * @return 无
    */
    void CaptureRawEtherFrame();

    int ethernet_protocol_packet_handle(u_char *argument,
        const struct pcap_pkthdr *packet_header,
        const u_char *packet_content);

};

  ② cpp文件

#define _CRT_SECURE_NO_WARNINGS
#include "Tools.h"

using namespace std;

// 以太网协议格式的定义
typedef struct ether_header {
    u_char ether_dhost[6];        // 目标MAC地址
    u_char ether_shost[6];        // 源MAC地址
    u_short ether_type;            // 以太网类型
}ether_header;

// 用户保存4字节的IP地址
typedef struct ip_address {
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;

// 用于保存IPV4的首部
typedef struct ip_header {
#ifdef WORDS_BIGENDIAN
    u_char ip_version : 4, header_length : 4;
#else
    u_char header_length : 4, ip_version : 4;
#endif

    u_char ver_ihl;            // 版本以及首部长度,各4位
    u_char tos;                // 服务质量
    u_short tlen;            // 总长度
    u_short identification;    // 身份识别
    u_short offset;            // 分组偏移
    u_char ttl;                // 生命周期
    u_char proto;            // 协议类型
    u_short checksum;        // 包头测验码
    ip_address saddr;        // 源IP地址
    ip_address daddr;        // 目的IP地址
    u_int op_pad;            // 可选 填充字段
}ip_header;

RawEtherTools::RawEtherTools()
{

}

RawEtherTools::~RawEtherTools()
{

}

/**
* @brief
* @input  无
* @output 无
* @return 无
*/
void RawEtherTools::CaptureRawEtherFrame()
{
    struct pcap_pkthdr *header;
    pcap_if_t * allDevs;
    pcap_if_t * dev;
    u_int netmask;
    int inum;
    int i = 0;
    int res;
    const u_char *pkt_data;
    time_t local_tv_sec;
    struct tm *ltime;
    char timestr[16];
    ip_header *ih;

    char errbuf[PCAP_ERRBUF_SIZE];
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &allDevs, errbuf) > 0)
    {
        printf("pcap_findallDevs_ex failed\n");
    }

    for (dev = allDevs; dev; dev = dev->next) {
        printf("%d. %s", ++i, dev->name);
        if (dev->description) {
            printf("(%s)\n", dev->description);
        }
        else {
            printf("No description available\n");
        }
    }

    if (0 == i) {
        printf("\nNo interface found!Make sure WinPcap is installed\n");
        return;
    }

    printf("Enter the interface number(1-%d):", i);

    scanf_s("%d", &inum);
    if (inum < 1 || inum > i) {
        printf("\nInterface number out of range.\n");
        pcap_freealldevs(allDevs);
        return;
    }

    for (dev = allDevs, i = 0; i < inum - 1; dev = dev->next, i++);

    pcap_t * handler;

    // 设备名,要捕捉的数据包的部分(65536保证能捕获到不同数据链路层上的每个数据包的全部内容),混杂模式,读取超时时间,错误缓冲池
    if ((handler = pcap_open_live(dev->name, 65536, 1, 1000, errbuf)) == NULL) {
        fprintf(stderr, "\nUnable to open the adapter.%s is not supported by WinPcap\n", errbuf);
        pcap_freealldevs(allDevs);
        return;
    }

    // 检查数据链路层(只考虑了以太网)
    if (pcap_datalink(handler) != DLT_EN10MB) {
        fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
        pcap_freealldevs(allDevs);
        return;
    }

    if (dev->addresses != NULL) {
        // 获得接口的第一个地址的掩码
        netmask = ((struct sockaddr_in*)(dev->addresses->netmask))->sin_addr.S_un.S_addr;
    }
    else {
        netmask = 0xffffff;
    }

    while ((res = pcap_next_ex(handler, &header, &pkt_data)) >= 0)
    {
        // 请求超时
        if (0 == res) {
            continue;
        }

        // 分析数据包
        int ret = ethernet_protocol_packet_handle(NULL, header, pkt_data);
        if (ret == -1)
            continue;

        // 将时间戳转换成可识别的格式
        local_tv_sec = header->ts.tv_sec;
        ltime = localtime(&local_tv_sec);
        strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
        ih = (ip_header *)(pkt_data + 14); //以太网头部长度

                                           // 输出时间和IP信息
                                           //printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
        printf(" len:%d ", header->len);

        printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",
            ih->saddr.byte1,
            ih->saddr.byte2,
            ih->saddr.byte3,
            ih->saddr.byte4,
            ih->daddr.byte1,
            ih->daddr.byte2,
            ih->daddr.byte3,
            ih->daddr.byte4);
        printf("%02x%02x%02x%02x -> %02x%02x%02x%02x\n",
            ih->saddr.byte1,
            ih->saddr.byte2,
            ih->saddr.byte3,
            ih->saddr.byte4,
            ih->daddr.byte1,
            ih->daddr.byte2,
            ih->daddr.byte3,
            ih->daddr.byte4);
        //输出每个包的byte数据ws2_32.lib
        for (int k = 0; k < header->len; k++)
        {
            if (k % 16 == 0 && k != 0)//输出美观
                printf("\n");
            printf("%02x ", *(pkt_data + k));
        }
        printf("\n");
    }

    if (-1 == res) {
        printf("Error reading the packet:%s\n", pcap_geterr(handler));
        return;
    }
    pcap_freealldevs(allDevs);

}

/**
* @brief  抓取以太网协议包
* @input  无
* @output 无
* @return 无
*/
int RawEtherTools::ethernet_protocol_packet_handle(u_char *argument,
    const struct pcap_pkthdr *packet_header,
    const u_char *packet_content)
{
    u_short ethernet_type;                        // 以太网类型
    struct ether_header *ethernet_protocol;        // 以太网协议变量
    u_char *mac_string;                            // 以太网地址

    ethernet_protocol = (struct ether_header*)packet_content;// 获取以太网数据内容
    ethernet_type = ntohs(ethernet_protocol->ether_type);     // 获取以太网类型

    if (ethernet_type != 0x00FF)
    {
        return -1;
    }
    printf("Ethernet type is : %04x\n", ethernet_type);

    // 获取以太网源地址
    mac_string = ethernet_protocol->ether_shost;

    printf(" MAC Source Address is === %02x:%02x:%02x:%02x:%02x:%02x",
        *mac_string,
        *(mac_string + 1),
        *(mac_string + 2),
        *(mac_string + 3),
        *(mac_string + 4),
        *(mac_string + 5)
    );

    // 获取以太网目的地址
    mac_string = ethernet_protocol->ether_dhost;
    printf(" MAC Target Address === %02x:%02x:%02x:%02x:%02x:%02x\n",
        *mac_string,
        *(mac_string + 1),
        *(mac_string + 2),
        *(mac_string + 3),
        *(mac_string + 4),
        *(mac_string + 5)
    );

    printf("%d", sizeof(packet_content));

    return 0;
}

  ③ Main.cpp

#include <iostream>
#include "Tools.h"
using namespace std;

int main()
{
    RawEtherTools *raw = new RawEtherTools();
    raw->CaptureRawEtherFrame();

    system("pause");
    return 0;
}

五、编译程序

  ① 错误1 编译程序报错,如下图所示

  解决办法:

    ws2_32.lib文件,提供了对以下网络相关API的支持,若使用其中的API,则应该将ws2_32.lib加入工程

    在工程属性--->链接器--->附加依赖项,添加ws2_32.lib库文件

    

  ② 错误2 编译程序报错,如下图所示

  

    解决办法:    

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

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

        在WinPcap编程调试解决办法 中,需要项目属性-》配置属性-》C/C++-》预处理器-》预处理器定义中添加HAVE_REMOTE,方可编译成功。

 

  

原文地址:https://www.cnblogs.com/jiangson/p/11890626.html

时间: 2024-11-10 00:52:27

基于WinPcap实现的Raw EtherNet 抓包、发包程序的相关文章

WinPcap网络抓包分析程序--总结

应付大作业写的一个程序,先给出程序的运行界面 程序的核心内容是抓包然后分析数据,我做的最多的也是协议分析这块内容.上面首先给出的是当前网络的上传下载速度,这块内容我是参考Windows性能计数器来写的,就是PDH,直接获取相应的接口, 获取数据,这块内容直接放出代码 1 #include <Pdh.h> 2 #include <list> 3 #pragma comment(lib, "Pdh.lib") 4 5 class NetWorkSpeed 6 { 7

基于HTTP访问特定URL的抓包程序该怎么写

抓包是一个简单易行的事,它可以帮你分析网络的行为.我记得早在2004年的时候,老师就讲过抓包有多么重要.        作为程序员而言,除了抓包几乎没有任何手段探测网络行为,程序员没有机会触摸网络设备,也就没有能力洞悉网络细节,程序员唯一能触摸到的就是自己的终端,在这个终端上唯一能做的就是抓包.我是半个程序员,所以不管站在谁的立场上,我都认为抓包是一个重要的事,虽然在我内心看来,抓包和分析数据包解决不了大多数的问题....        在一台承载大量业务的机器上怎么抓包成了一个问题.因为虚拟主

c语言基于Linux下用libpcap实现抓包程序

c语言基于libpcap实现一个抓包程序过程 基于pcap的嗅探器程序的总体架构,其流程如下:(1)首先要决定用哪一个接口进行嗅探开始.在Linux中,这可能是eth0,而在BSD系统中则可能是xl1等等.我们也可以用一个字符串来定义这个设备,或者采用pcap提供的接口名来工作.(... 基于pcap的嗅探器程序的总体架构,其流程如下: (1)首先要决定用哪一个接口进行嗅探开始.在Linux中,这可能是eth0,而在BSD系统中则可能是xl1等等.我们也可以用一个字符串来定义这个设备,或者采用p

wiresherk抓包之旅

wireshark的原名是Ethereal,新名字是2006年起用的.当时Ethereal的主要开发者Gerald决定离开他原来供职的公司NIS,并继续开发这个软件.但由于Ethereal这个名称的使用权已经被原来那个公司注册,Wireshark这个新名字也就应运而生了. Wireshark是世界上最流行的网络分析工具.这个强大的工具可以捕捉网络中的数据,并为用户提供关于网络和上层协议的各种信息,也是网络工程师.信息安全工程师必备的一个工具之一. Wireshark下载:https://www.

linux主机上编译安装rpcapd实现wireshark远程抓包功能

使用wireshark在远程linux系统抓包 简介 由于在做分布式HLR时,需要一边测试,一边抓取信令消息,而现在分布式HLR的系统都是采用linux,抓包可以使用tcpdump工具,不过感觉不是很方便.正好,之前的测试的同事,已经实现了使用笔记本上的wireshark远程抓包,而我以前对此没有做过了解,不是很懂,抽空在网上查了查资料,大概屡清楚了实现方法.实现远程抓包,主要借助winpacp这个软件中的rpcapd工具,这里就对在linux下的rpcapd工具的安装,使用和windows下的

用Web抓包分析工具Livepool 实现本地替换开发

这是官方的介绍: LivePool 是一个基于 NodeJS,类似 Fiddler 支持抓包和本地替换的 Web 开发调试工具,是 Tencent AlloyTeam 在开发实践过程总结出的一套的便捷的 WorkFlow 以及调试方案. 功能特性还挺多: 基于 NodeJS, 跨平台 支持 http 抓包和本地替换调试,Https/WebSockets 直接代理转发(暂不支持本地替换) 便捷的 UI 管理界面,跟 Fiddler 类似,降低学习成本 可以脱离 UI 后台运行,适应于某些不需要抓包

tcpdump 抓包让wireshark来分析

在linux下面用tcpdump 抓包非常方便, 但是抓的包要提取出来进行分析, 还是得用wireshark来过滤分析比较方便. 下面先介绍一下 TCPDUMP 的使用 例:tcpdump host 172.16.29.40 and port 4600 -X -s 500 tcpdump采用命令行方式,它的命令格式为: tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ] [ -i 网络接口 ] [ -r 文件名] [ -s snaplen ] [ -

Android端抓包方法

By:wangyz 最近这段时间研究抓包发包,汇编可能要推迟一些时间了 做手机测试的同学,肯定都要做一些手机端的抓包测试,看看数据包是否有错误,是否加密之类的,做外挂的也要抓来数据包做做分析. 一般抓包都是在PC机上搭个AP,用Wireshark抓,感觉那种方法有点略麻烦, 抓包环境 三星 GT-I8552 Android 4.1.2 百度云ROM 正式版V6(已ROOT) PC端(Windows XP) 1.正确安装手机驱动,手机端打开USB调试 2.Android手机需要先获得root权限.

微信7.0以上版本fiddler、Charles抓包报HTTPS证书信任问题通报

通报:微信更新到7.0以后抓包公众号会有证书问题,抓包小程序直接不能打开 各位不用到处找了,也不用怀疑人生了,你没有问题.win10也没有问题.fiddler和Charles也没有问题,是因为微信更新了,不再从手机本地获取证书. 安卓系统 7.0 以下版本,不管微信任意版本,都会信任系统提供的证书安卓系统 7.0 以上版本,微信 7.0 以下版本,微信会信任系统提供的证书安卓系统 7.0 以上版本,微信 7.0 以上版本,微信只信任它自己配置的证书列表以上规则是拷贝别人的,但确实亲测如此,搞得我