QT基于Npcap设计的网络抓包小程序

  • 小程序运行结果
  • Npcap
  • QT
  • Npcap中使用的函数
  • 时序图
  • 程序流程
    • .pro配置文件
    • 网络数据包分析
    • QT 界面中信号与事件触发
    • 网络字节序与主机字节序转换的问题

抓取网络数据包,在windows下可以使用WinPcap 或者 Npcap,而在linux中可以使用libpcap
小程序是使用的语言是C/C++,目前只可以进行同步使用,不可以异步
百度网盘链接:https://pan.baidu.com/s/1r8a5xDjdI8skylJ54pzJBw
提取码:twhg

小程序运行结果

  • 主界面

  • 网卡信息的显示

  • 随机抓取一个网络数据包,并进行解析

    说明该数据包在传输层为UDP协议,对UDP协议进行解析

  • 单独解析一个TCP协议的数据包

没有抓到数据包,或者抓到的数据包无法解析,进行报错处理

对于数据包的解析,分别解析数据链路层的以太网帧头部,网络层的ip协议,传输层的TCP协议和UDP协议。

而对于数据包的抓取,小程序默认只抓10次,有三个功能:只抓取TCP协议的数据包,只抓取UDP协议数数据包,随机抓取一个数据包(TCP,UDP)。只要抓取一个,就会停止抓取,要是抓不到就会有一个弹窗进行报错。

Npcap

NpcapNmap 项目的网络包抓取库在 Windows 下的版本。是致力于采用 Microsoft Light-Weight Filter (NDIS 6 LWF) 技术Windows Filtering Platform (NDIS 6 WFP) 技术对当前最流行的 WinPcap 工具包进行改进的一个项目。(WinPcap目前已经停止了更新)

Npcap 基于 WinPcap 4.1.3 源码基础上开发,支持 32 位和 64 位架构,在 Windows Vista 以上版本的系统中,采用 NDIS 6 技术的 Npcap 能够比原有的 WinPcap 数据包(NDIS 5)获得更好的抓包性能,并且稳定性更好。

Npcap 还独具以下特点:

  1. 支持 NDIS 6 技术;
  2. 支持“只允许管理员 Administrator”访问 Npcap;
  3. 支持与 WinPcap 兼容或并存两种模式;
  4. 支持 Windows 平台的回环(Loopback)数据包采集和发送;

官方网站:https://nmap.org/npcap/


另外,Windows中想要使用Npcap进行抓包,得先安装官方的这个配置文件,里面有程序运行中的一些动态库文件。

QT

中科大开源镜像网站中下载,https://mirrors.ustc.edu.cn/qtproject/archive/qt/5.9/5.9.9/


安装的时候,记得改下软件安装的路径,在配置安装的编译器选项时,不知道怎么配置就全安装吧~~

在项目中,主要使用QT软件对解析后的网络数据包进行一个可视化显示,利用Qt做一个简单的窗体来显示解析后的数据。

Npcap中使用的函数

  • 获取主机网卡信息
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf);
参数 含义
pcap_if_t **alldevsp 存放获取的网卡设备的结构体,使用的数据结构是链表
char *errbuf 存放错误信息
返回值 -1:表示获取失败

函数作用:获取当前主机的网卡设备信息,存放在alldevsp结构体链表中;当返回值为-1时表示调用失败,并在errbuf数组中存放错误的信息

int pcap_findalldevs_ex(char* source,  struct pcap_rmtauth *auth,  pcap_if_t** alldevs,   char* errbuf );

该函数也是获取当前主机的网卡信息,只是这个函数所获取的网卡信息在对网卡的描述方面比pcap_findalldevs详细

参数 含义
char* source 指定是本地适配器或者远程适配器,本地适配器:rpcap://,远程适配器:rpcap://host:port,抓包文件。file://c:/myfolder/
struct pcap_rmtauth *auth 需要抓取其他主机的网卡信息时,该结构体中需要有访问目的主机时的身份验证信息,访问本机时可以传入NULL
返回值 -1:表示获取失败,0 :表示获取成功

pcap_if_t 结构体链表的描述:

struct pcap_if {struct pcap_if *next;char *name;         /* name to hand to "pcap_open_live()" */char *description;    /* textual description of interface, or NULL */struct pcap_addr *addresses;bpf_u_int32 flags;   /* PCAP_IF_ interface flags */
};

struct pcap_rmtauth的描述:

struct pcap_rmtauth
{int type;          // 简要身份验证所需的类型char *username;       // 用户名char *password;       // 密码
};
  • 释放网卡信息
 void pcap_freealldevs(pcap_if_t *alldevs);
参数 含义
pcap_if_t *alldevs 获取的网卡信息的结构体

函数作用:释放网卡信息的结构体链表,防止内存泄漏

  • 建立捕获数据包的嗅探
pcap_t* pcap_open(   const char *    source,int  snaplen,int     flags,int   read_timeout,struct pcap_rmtauth *  auth,char *     errbuf);
参数 含义
const char * source 需要打开源的名称,也就是之前获取的网卡设备的名称
int snaplen 必须保留的包的长度。对于每个数据包,只接收前 snaplen 长度的数据
int flags 捕获数据包的方式,
int read_timeout 以毫秒为单位。read timeout被用来设置在遇到一个数据包的时候读操作不必立即返回,而是等待一段时间,让更多的数据包到来后从OS内核一次读多个数据包
struct pcap_rmtauth * 保存当一个用户登录到某个远程机器上时的必要信息。假如不是远程抓包,该指针被设置为NULL
char * errbuf 一个指向用户申请的缓冲区的指针,存放当该函数出错时的错误信息

函数作用:为捕获/发送数据打开一个普通的源。pcap_open()能够替代所有的pcap_open_xxx()函数,它隐藏了不同的pcap_open_xxx()之间的差异,所以我们不必使用不同的open函数。

返回值是一个pcap_t*指针,它可以作为下一步调用(例如pcap_compile()等)的参数,并且指定了一个已经打开的npcap会话。在遇到问题的情况下,它返回NULL并且errbuf变量保存了错误信息。

/** Specifies whether promiscuous mode is to be used.* 混杂模式获取数据包 UDP*/
#define PCAP_OPENFLAG_PROMISCUOUS       0x00000001 /** 它定义了数据传输(假如是远程抓包)是否用UDP协议来处理*/
#define PCAP_OPENFLAG_DATATX_UDP        0x00000002/*
*它定义了远程探测器是否捕获它自己产生的数据包
*/
#define PCAP_OPENFLAG_NOCAPTURE_RPCAP       0x00000004
  • 捕获数据包
int pcap_next_ex(pcap_t* p,struct pcap_pkthdr** pkt_header,const u_char** pkt_data)
参数 含义
pcap_t* p 已打开的捕捉实例的描述符,之前通过pcap_open函数的返回值
struct pcap_pkthdr** pkt_header 报文头
const u_char** pkt_data 报文内容
返回值 1: 成功;0: 获取报文超时;-1: 发生错误; -2: 获取到离线记录文件的最后一个报文

函数作用:从interface或离线记录文件获取一个报文

时序图

第一次话时序图,可能有些地方还不是很完善,呃呃呃

程序流程

.pro配置文件

我们需要在配置文件中,加入Npcap的头文件和动态库文件。

我是直接把之前下载的这个文件放在了项目文件中,QT在执行时,就可以使用相对路径。./默认是当前项目文件的路径,然后依次将这些头文件和库文件载入一下就可以了,分别在INCLUDEPATHLIBS


之后再编译选项中加入对对应库文件的引入

CONFIG += c++11 -lwpcap -lpacket -lws2_32

网络数据包分析

对于抓到的数据包,Npcap会返回在数据链路层中指定大小的数据帧(一般数据链路层数据帧长度为1518字节)。


IP协议的类型为0x800,所以说在以太网帧头部就需要对网络层使用的协议进行判断

  1. 数据链路层结构体封装:
// 以太网数据帧头格式struct ether_hander {u_char  _ether_dhost[6];    // 目标地址u_char  _ether_shost[6];    // 源地址u_short _ether_type;        // 以太网类型};

我们可以根据对应字段,从整个数据包中截取前14个字节,也就是以太网数据帧的头部大小。

因为到时候我们在界面中所显示的文本,QT中是QString类型,为了到时候转换方便,我们另外再建立一个结构体,里面对应每一个字段设置一个string类型的数据。另外再保留一下原数据,以便和解析的数据进行一次对比。

// 以太网帧头部信息
struct ether_parse {string _decs;       // 目标MAC 地址string _src;        // 源  MAC 地址string _type;       // 上层协议类型string _str;        // 16进制字符串信息
};
extern ether_parse* eth_protocal;  // 以太网协议
  1. 网络层IP协议封装
    struct ip_hander {u_char      _version_handerLen;     // 版本 4  首部长度 4u_char      _diffserv;              // 服务类型u_short     _totalLen;              // 总长度u_short     _identification;        // 标识u_short     _flag_offset;           // 标志 3 + 片偏移 13u_char      _timeLive;              // 生存时间u_char      _protocol;              // 协议u_short     _checkSum;              // 首部校验和long        _src;                   // 源地址long        _desc;                  // 目的地址};

ip_hander* handl = (ip_hander*)(::packData + 14);
::ip_protocal    = new ip_parse();

对于ip数据报首部,可以使用指针类型进行一次跳转,跳过数据报中前面的以太网帧首部

// ip 协议
struct ip_parse {string      _version;           // 版本string      _handerLen;         // 首部长度string      _diffserv;          // 区分服务string      _totalLen;          // 总长度string      _identification;    // 标识string      _flag_offset;       // 标志 3 + 片偏移 13string      _timeLive;          // 生存时间string      _protocol;          // 协议string      _checkSum;          // 首部校验和string      _src;               // 源地址string      _desc;              // 目的地址string      _str[4];            // 16进制字符串信息数组
};
extern ip_parse* ip_protocal;       // ip 协议
  1. 传输层TCP协议
 struct TCP_hander {ushort      _sport;         // 源端口ushort      _dport;         // 目的端口uint        _seqNum;        // 序列号uint        _ackNum;        // 确认号ushort      _off_res_flag;  // 数据偏移 4  保留位 6  标志位 6ushort      _winSize;       // 窗口大小ushort      _checkSum;      // 校验和ushort      _urgentPoint;   // 紧急指针};


而想要得到传输层的数据包长度,就需要进行一次偏移,以太网数据帧首部为14个字节,网络层IP协议首部最少为20个字节,所以可以进行 14 + 20的偏移

// tcp 协议  传输层
struct tcp_parse {string      _sport;             // 源端口string      _dport;             // 目的端口string      _seqNum;            // 序列号string      _ackNum;            // 确认号string      _off_res_flag;      // 数据偏移 4  保留位 6  标志位 6string      _winSize;           // 窗口大小string      _checkSum;          // 校验和string      _urgentPoint;       // 紧急指针string      _str[5];            // 16进制字符串信息数组
};
extern tcp_parse* tcp_protocal;     // tcp 协议
  1. 传输层UDP协议
    struct UDP_handler {ushort      _sport;     // 源端口ushort      _dport;     // 目的端口ushort      _len;       // 数据长度ushort      _checksum;  // 校验和};

// udp 协议  传输层
struct udp_parse {string      _sport;             // 源端口string      _dport;             // 目的端口string      _len;               // 数据长度string      _checksum;          // 校验和string      _str[2];            // 16进制字符串信息数组
};
extern udp_parse* udp_protocal;     // udp 协议

QT 界面中信号与事件触发

有这样的一个需求,就是对于显示主机网卡信息的时候,对于当前行的网卡,绑定一个双击的事件,然后跳转到主界面,在输入选择网卡框中自动填入当前选择的嗅探网卡编号


这可以用到QT中的信号来进行解决:

  1. 在选择网卡信息的界面类中,定义一个信号的函数(QT对于信号函数,只进行声明,不需要定义)
  2. 在主界面中相应的增加一个信号函数,已经接受信号的函数

另外,还需要把网卡信息的界面类,加入到主界面的成员变量中,一定要是指针类型。防止出作用域后进行析构,因为QT中对于窗体的绑定事件都是异步执行的。

  1. 连接两个信号的函数

在主窗体的构造函数中对两个信号函数进行连接,注意一定要对网卡信息的界面类进行构造,并且绑定后不能重新对该界面类构造一个新的窗体。这样会导致绑定失效,因为重新构造后该指针的地址就会发生改变

  1. 设置选择后进行通知

网络字节序与主机字节序转换的问题

问题的发现是在验收的过程中老师所指出的,在TCP协议中的首部长度和保留位不正确,之后经过思考发现是没有转换字节序的问题。

字节序分为两种:大端和小端。

  1. 大端:是数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。低地址指向高数据,常见的设备:手机
  2. 小端:是指数据的地位保存在内存的低地址中,数据的高位则保存在内存的高地址中。低地址指向低数据,常见的设备:电脑

简单验证自己主机字节序的程序:

union uu//联合结构体
{int i;char a;
};//特点:i和a共用一块内存
int CheakSys(){union uu un;un.i = 20;return un.a;
}
int main(){int ret = CheakSys();if (ret == 0x14)printf("小端\n");else
printf("大端\n");return 0;
}

而网络数据包的默认存储模式为大端,也就是说,当我们得到一个数据包,并进行解析的时候,如果原数据所占的大小不是1个字节,那么就需要进行一个转换,也就是网络字节序到主机字节序的转换,即大端到小端的转换。

主要就是由两个数据类型涉及到字节序转换的问题,short和int

// ushort 类型网络字节序转为主机字节序
#define NTOHS(A) ((((A)&0xFF00)>>8) | (((A)&0x00FF)<<8))
// 网络字节序转为主机字节序 short
void NetToHost(ushort& h) {h = NTOHS(h);
}// 网络字节序转为主机字节序 int
void NetToHostInt(uint& h) {h = ((h & 0x000000ff)<<24) | (h&0x0000ff00 << 8) | (h & 0x00ff0000 >> 8) | (h & 0xff000000 >> 24);
}

程序源码地址:https://github.com/duchenlong/Cpp/tree/master/net

QT基于Npcap设计的网络抓包小程序相关推荐

  1. 计算机网络抓包参考文献,计算机网络课程设计二(网络抓包与分析)

    <计算机网络课程设计二(网络抓包与分析)>由会员分享,可在线阅读,更多相关<计算机网络课程设计二(网络抓包与分析)(9页珍藏版)>请在人人文库网上搜索. 1.课程设计课程名称: ...

  2. fiddle无法抓包小程序解答

    抓包小程序的教程很多,但是操作一遍,为什么还是抓不到.这时候就需要来看这里了(ps:来,来我这里,come on baby,包教包会) 步骤: 1.打开任务管理器(快捷键:ctrl + alt + d ...

  3. charles 抓包小程序(电脑window,手机是iPhone ios 10.3)

    栽过几次坑,终于写成经. 反反复复装过多次charles,中间遇到各种问题导致最终没法看到抓包信息,一个坑一个坑的埋,终于成功抓包小程序.梳理了下可以尽量减少栽坑的安装过程,如下: 1.下载charl ...

  4. 用fiddler抓包小程序

    第一步:安装fiddler,保证手机和PC端在同一个wifi下: 第二步:设置属性 按图勾选 第三步:以上两步设置完后,重启下fiddler(解决本地服务器不能访问),然后查看本地IP地址 第四步:手 ...

  5. c++环境下qt+pcpp(winpcap)实现的网络抓包(sniff)程序

    一.软件的简介 1.1 开发技术简介 本软件是利用c++语言基于Qt与PcapPlusPlus(以下简称PcPP)库在vs2019中开发的一个单一的windows应用.Qt是一个良好的跨平台界面设计库 ...

  6. VMOS+小黄鸟解决抓包小程序无网络问题2(附工具)

    前言 接上篇有粉丝反馈说按照上面的配置设置好依然会出现抓包时无网络问题,今天又打开虚拟机调试了一番,发现了一种更加简单高效的方法. 准备工具(工具参考上篇文末): 1. vmos pro破解版 2. ...

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

    应付大作业写的一个程序,先给出程序的运行界面 程序的核心内容是抓包然后分析数据,我做的最多的也是协议分析这块内容.上面首先给出的是当前网络的上传下载速度,这块内容我是参考Windows性能计数器来写的 ...

  8. linux查看程序recvfrom,Linux网络抓包的程序 [使用recvfrom之后无限阻塞]

    操作系统: ubuntu 2.6.24 g++ 网络没有问题 程序原理是 : 1,先创建一个RAW的socket, 2,再把网卡设为混杂模式. 3,使用recvfrom开始抓包. 症状描述: recv ...

  9. Mac OS下Charles抓包小程序的保姆级操作过程

    目录 前言 工具准备 Charles安装及配置 开始抓包 总结 前言 对于压力测试工作而言,小程序接口测试工作和其他接口测试工作相似,都需要为测试工作的开展去准备相应接口的信息,其中包含请求接口,入参 ...

  10. Fiddler结合苹果11抓包小程序 (最新)

    做项目开发,突然发现前端同事可以通过手机抓正式线上小程序的包数据,还可以通过直接替换线上文件进行开发,于是就有了这篇文章. 1.安装fiddler软件:这个去官网下载就好了. 2.fiddler软件的 ...

最新文章

  1. shell指令可以直接在终端输入吗_shell不是LInux系统的壳吗?咋还能脚本编程了?...
  2. IDEA常用快捷键!!
  3. nginx中301和302重定向之间的区别
  4. 任务调度及远端管理(基于Quartz.net)
  5. 亲密关系-【舒适退出】-减少伤害的终局沟通
  6. 计算机被格式化怎么找回资料,电脑文档被格式化,怎么恢复格式化文档
  7. 护考人机对话用计算机吗,2018护士执业资格考试人机对话怎么考 有什么注意事项...
  8. 每日算法系列【LeetCode 992】K个不同整数的子数组
  9. python-snap7的安装记录
  10. python 安装win32com_python调用win32com.client时提示:No module named win32com.client
  11. DSP6678 中断程序
  12. oracle生成awr报告命令,oracle数据库生成awr报告
  13. linux 下svn: E175002: 方法 REPORT 失败于 “/svn/GameSvn/!svn/me”: 不能读块分割符: 安全连接切断 (https://192.168.0.88)
  14. win10如何删除微软拼音输入法
  15. 多普达P800 GPS设置终极教程
  16. 斯坦福大学公开课:量子力学_TimelineMax:了解力学
  17. 19、论文解读:Intensity Scan Context: Coding Intensity and Geometry Relations for Loop Closure Detection
  18. Bzoj3653 谈笑风生
  19. L3-020 至多删三个字符 (30 分)
  20. jquery.validate.min.js使用介绍

热门文章

  1. 80套传统简历模板.zip
  2. mysql意外停止后数据库恢复
  3. android 各国语言对应的缩写
  4. markdown实现点击链接下载文件
  5. 我所了解的GB2312、Unicode、GBK、UTF-8、BIG5等编码
  6. 网店宝贝复制专家操作手册
  7. SSM框架原理以及流程简略
  8. retainall java_java用retainALL 处理两个具有相同元素的list,竟然返回false,这是为什么?...
  9. echarts 多图联动
  10. 简单介绍在线OTA几款平台