
简介华中科技大学2018年计算机网络安全实验的完整源码基于Winpcap实现的数据分析器嗅探器适用于高校网络安全课程学习者、安全爱好者及希望动手复现抓包和中间人攻击的开发者。工程实现了数据包实时抓取与常见协议深度解析并支持通过ARP欺骗主动发起中间人攻击代码按功能拆分为抓包、ARP欺骗、报文发送和界面交互等模块每个模块职责清晰便于逐段阅读和调试。资源共27个文件以C头文件和源文件为主辅以Qt界面设计文件、图片资源及工程配置压缩包整体仅293KB轻量不臃肿适合快速定位关键逻辑。目前已有2812人学习下载。通过分析这份源码可以深入理解Winpcap的抓包与过滤原理、ARP报文构造和欺骗流程以及Qt多线程操作网络设备的技巧在配置好Qt和Winpcap环境后可直接编译运行直观观察数据包列表、协议解析结果和中间人攻击效果是网络安全实验与二次开发的实用参考。 上周刚把华科《计算机网络安全》里这个核心实验——基于 Winpcap 的数据分析器嗅探的实现——完整跑通。这个实验说白了就是自己动手写一个抓包工具装上 Winpcap 驱动后用它的 API 把经过本机网卡的数据包捕获下来再按以太网帧、IP、TCP/UDP 的层次做协议解析最后把源地址、目的地址、协议类型、端口和包长度统计出来。别小看这个项目它既有驱动层的兼容性问题又有字节序、包结构、过滤规则这些细节工作量不算大坑是真的多。这篇文章把实验从原理拆到代码、从安装到排错完整复盘一遍。正在做同款实验的同学可以直接照着抄想搞懂抓包原理的人也能从里面找到关键思路。先提醒一句整个实验请在实验课指定的虚拟机或者自己有管理权限的测试环境里完成抓包范围仅限于本机或已授权网络这类工具看着很酷但一定要放在合法场景里用。1. 实验拆解一个嗅探器要解决哪几件事1.1 抓包、解包、统计三步读懂数据流一个完整的基于 Winpcap 的数据分析器拆开来看就三个环节捕获、解析、展示。捕获环节负责把网卡上流过的数据帧拿到应用层。普通情况下网卡只把发给自己的数据包交给系统协议栈而 Winpcap 可以把网卡设置成混杂模式让经过它的每个数据包都被复制一份出来这正是“嗅探”的核心能力。你可以理解为网卡是收发室普通模式只收自己家的信件混杂模式相当于把所有路过的信件都抄了一份Winpcap 就是在收发室里装的监控装置。解析环节是按照 TCP/IP 协议栈的层次把裸的二进制数据拆成有意义的字段。先看以太网帧头再根据帧头里的类型字段决定下一步解析 IP 还是 ARP如果是 IPv4继续解析 IP 头拿到源 IP、目的 IP、协议类型如果是 TCP 或 UDP再解析端口号。整个链路就像剥洋葱一层一层往里剥。展示环节则是把解析结果变成人话。最简单的做法是在控制台输出一行行数据包信息再攒一个协议统计表告诉用户当前抓了多少个 TCP 包、多少个 UDP 包、总流量是多少。这也是“数据分析器”和“抓包工具”最大的区别前者要能汇总、统计、提炼信息而不是把原始十六进制直接扔给用户看。这门实验特别适合网络方向或者安全方向的在校生因为它能让你直观理解 IP 分片、TCP 握手、端口号、MAC 地址这些原本只停留在书本上的概念。你亲眼看到一次完整的三次握手包后很多协议细节一下就通了。1.2 为什么课程实验偏爱 Winpcap可能有人会问Windows 下抓包不是直接用 WinSock 的原始套接字就行了吗为什么实验要专门用 Winpcap第一个原因是层次问题。WinSock 的原始套接字拿到的数据从 IP 层开始位置偏上层而且 Windows 对原始套接字限制很多收发规则也比较别扭。Winpcap 则是通过内核驱动直接在数据链路层抓取原始帧连以太网帧头都能看到这对理解完整协议栈非常有帮助。第二个原因是效率。Winpcap 内部实现了 BPF 过滤器像tcp port 80、icmp这样的过滤表达式可以直接在驱动层执行把不关心的数据包提前丢掉用户态拿到的都是有效数据。如果自己写循环判断每个包性能和代码量都不理想。第三个原因是生态和教学惯性。Winpcap 的 API 设计得很清晰官方文档和示例代码齐全全球大量网络课程和安全实验都基于它。虽然官方早就停止更新现在新系统上更推荐 Npcap但很多高校实验环境还是沿用 Winpcap 4.1.3 加 WpdPack 开发包。原理完全一样把 Winpcap 跑明白Npcap 也就是换个名字的事。2. 环境准备把 Winpcap 跑起来的正确姿势2.1 Winpcap 驱动架构与 API 分工开始写代码前先搞清楚 Winpcap 的结构。它分三层最底层是 NPF 内核驱动服务名通常是 npf负责从网卡抓取数据帧、执行 BPF 过滤、维护内核缓冲区中间层是 packet.dll提供底层驱动访问接口最上层是 wpcap.dll提供我们熟悉的pcap_*系列 API。对应用开发者来说主要打交道的是 wpcap.dll。一个典型抓包流程是这样用pcap_findalldevs枚举所有网卡让用户选择其中一个设备名用pcap_open_live打开设备设置快照长度、混杂模式和超时时间用pcap_compile编译过滤表达式再用pcap_setfilter应用过滤规则循环调用pcap_next_ex或pcap_dispatch获取数据包结束前用pcap_close释放资源。理解这个流程后代码骨架就基本出来了。很多同学一上来就找完整源码其实不如先把这几个 API 的调用链理清代码写起来非常快。2.2 安装与工程配置避坑指南安装 Winpcap 看起来很简单双击安装包一路下一步就行但这里有几个细节不注意后面会连续踩坑。先到官网下载 Winpcap 4.1.3注意安装时右键“以管理员身份运行”路径保持默认C:\Program Files\WinPcap就好不要去改成带中文的目录。网上有人问“winpcap 怎么选择安装路径”其实开发环境是否正常和安装路径关系不大关键是 WpdPack 开发包要单独放到一个纯英文目录。安装完成后打开服务管理器确认存在 NetGroup Packet Filter Driver 这个服务。如果服务没启动抓包 API 会直接报错。后面表格里我会专门写 NPF 服务启动失败的解决办法这里先记着这个服务名。然后是开发者工具包 WpdPack建议下载 4.1.2 版本解压到比如C:\WpdPack。在 Visual Studio 里新建一个 Win32 控制台项目配置如下C/C - 常规 - 附加包含目录添加C:\WpdPack\Include链接器 - 常规 - 附加库目录添加C:\WpdPack\Lib如果编译 64 位程序用C:\WpdPack\Lib\x64链接器 - 输入 - 附加依赖项添加wpcap.lib和ws2_32.libC/C - 预处理器 - 预处理器定义添加WPCAP;HAVE_REMOTE注意WPCAP宏很关键它告诉编译器使用的是 wpcap.dll 的导入库方式。如果缺少这个宏链接阶段会出现一堆pcap_xxx函数无法解析的错误。配置完成后先写个最简单的枚举网卡程序测试环境能列出网卡就说明环境没问题了。很多同学一上来就抄整个项目结果编译报错分不清是环境问题还是代码问题浪费时间。3. 代码落地从抓包到协议解析3.1 主流程枚举网卡到循环抓包下面这段代码是抓包主流程的骨架我做了简化但脉络是完整的#include pcap.h #include stdio.h #include winsock2.h #pragma comment(lib, wpcap.lib) #pragma comment(lib, ws2_32.lib) void packet_handler(u_char *user, const struct pcap_pkthdr *hdr, const u_char *pkt); int main() { pcap_if_t *alldevs NULL; char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *fp NULL; pcap_if_t *d; int i 0, inum; // 1. 枚举本机网卡 if (pcap_findalldevs(alldevs, errbuf) -1) { printf(枚举网卡失败%s\n, errbuf); return 1; } for (d alldevs; d; d d-next) { printf(%d. %s, i, d-name); if (d-description) printf( - %s, d-description); printf(\n); } printf(请选择网卡编号); scanf(%d, inum); if (inum 1 || inum i) { printf(编号无效\n); return 1; } // 2. 打开网卡设置混杂模式 d alldevs; for (i 0; i inum - 1; i) d d-next; fp pcap_open_live(d-name, 65536, 1, 1000, errbuf); if (fp NULL) { printf(打开网卡失败%s\n, errbuf); return 1; } // 3. 编译并设置过滤规则 struct bpf_program fcode; char filter[] ip or arp; if (pcap_compile(fp, fcode, filter, 1, PCAP_NETMASK_UNKNOWN) -1) { printf(过滤规则编译失败\n); return 1; } pcap_setfilter(fp, fcode); // 4. 循环抓包 printf(开始抓包按 CtrlC 退出...\n); pcap_loop(fp, 0, packet_handler, NULL); pcap_close(fp); pcap_freealldevs(alldevs); return 0; }pcap_open_live的四个参数里65536是快照长度表示每个数据包最多保留多少字节设置成 65536 可以保证拿到完整包第三个参数填1表示开启混杂模式1000是读取超时时间单位毫秒超过 1000 毫秒没有数据就返回超时。pcap_loop的第二个参数是抓包数量0 表示无限循环配合 CtrlC 结束。回调函数packet_handler会在每个数据包到达时被调用一次整个数据包内容就在pkt指针指向的缓冲区里。走到这一步你的程序已经具备基本嗅探能力了。3.2 手动拆解以太网帧和 IP/TCP 头拿到原始数据包后解析是最核心的部分。以太网帧头是固定的 14 字节6 字节目的 MAC、6 字节源 MAC、2 字节上层协议类型。0x0800 表示 IPv40x0806 表示 ARP。可以定义如下结构体#pragma pack(push, 1) typedef struct eth_header { unsigned char dest[6]; unsigned char src[6]; unsigned short type; } eth_header_t; typedef struct ip_header { unsigned char ver_ihl; // 版本号 首部长度 unsigned char tos; unsigned short total_len; unsigned short id; unsigned short frag_off; unsigned char ttl; unsigned char protocol; unsigned short checksum; struct in_addr src_addr; struct in_addr dst_addr; } ip_header_t; #pragma pack(pop)注意#pragma pack(push, 1)很关键它告诉编译器按 1 字节对齐否则结构体会因为默认对齐产生空洞解析出来的字段全错位。从pkt指向的缓冲区开始先取 14 字节作为以太网头然后判断type字段。注意这里必须调用ntohs()把网络字节序转为主机字节序因为协议栈传输使用大端序而 x86 机器是小端序直接读会把端口号、长度字段都读反。IP 头从pkt 14开始首部长度取ver_ihl的低 4 位再乘以 4单位是字节。IP 头里protocol字段标识上层协议6 是 TCP17 是 UDP1 是 ICMP。源地址和目的地址是 4 字节网络序用inet_ntoa转成点分十进制字符串显示。TCP 头紧跟在 IP 头后面源端口和目的端口在 TCP 头的最前面两个 16 位字段同样要用ntohs转一遍。到这里一个数据包最核心的“五元组”信息就出来了源 IP、目的 IP、协议、源端口、目的端口。这就是分析的基本素材。3.3 让数据“会说话”简单统计输出如果只是逐行打印每个包那还算不上“数据分析器”。我在实验里加了两层统计效果一下子就不一样了。第一层是协议统计。用全局数组proto_count[256]记录每种协议的出现次数数组下标就是 IP 头里的 protocol 字段值。每解析一个包就把对应计数加一同时累加hdr-len得到总字节数。这样程序运行一段时间后按 CtrlC 退出前打印一份统计表TCP 多少个、UDP 多少个、ICMP 多少个、ARP 多少个、总流量多少 MB数据概览一目了然。第二层是速率统计。设定一个 1 秒窗口每秒打印一次当前速率格式类似[1000ms] TCP52 UDP18 ICMP6 速率124.5 KB/s这个功能实现起来不复杂记录每秒开始时的累计字节数到秒末用差值除以时间即可。有了这个面板程序才真正有“分析工具”的样子也能直观看到下载文件、访问网页时流量突增的现象。如果还想外扩可以按目标端口统计 Top 10比如 80 端口通常是 HTTP、443 是 HTTPS、53 是 DNS。这些统计在控制台里用简单表格输出不需要额外依赖图形库。4. 高频问题排查与调试经验4.1 安装阶段NPF 服务、接口不可用等典型报错这个实验最常见的挫败感往往不是来自代码而是来自环境。我把安装和启动阶段的高频问题整理成一张表供大家快速定位。现象可能原因解决办法Winpcap 安装失败提示 NPF 服务启动失败权限不足、杀毒软件拦截、旧版本残留以管理员身份运行安装包临时关闭杀软先卸载旧版并重启再装打开抓包工具提示 local interfaces are unavailable because winpcap is installed but is no longer...NPF 服务没有运行或被 Npcap 覆盖打开服务管理器启动 NPF或卸载后重装 Winpcap 4.1.3pcap_findalldevs 返回 -1驱动服务未启动或程序没有管理员权限管理员身份运行程序确认服务列表里有 npf 服务64 位系统编译链接报错库路径选错x86/x64 不匹配32 位程序用Lib目录64 位程序用Lib\x64目录保持一致另外提醒一个场景有的大型开发软件在部署时会捆绑旧版 Winpcap 或 Npcap装完之后抓包工具的驱动服务互相覆盖导致 npf 服务起不来。遇到这种情况先把捆绑安装的驱动卸载干净重启后再装独立版 Winpcap或者改用 Npcap 的 Winpcap 兼容模式。环境问题通常不是代码问题别急着改代码。4.2 编码与运行阶段链接错误、抓不到包怎么办代码写完后我遇到过这些情况整理出来供参考链接错误最常见的LNK2019 unresolved external symbol pcap_findalldevs十有八九是附加依赖项里没加wpcap.lib或者预处理宏缺少WPCAP。解决方法是回到工程配置检查一遍尤其是 64 位工程的库目录。抓不到任何包先看设备选择对不对。很多电脑有多个网卡虚拟机的虚拟网卡、蓝牙网卡、物理网卡都列在枚举结果里选错了自然抓不到流量。可以先选择物理网卡然后另开一个命令窗口执行ping 192.168.x.1网关地址制造流量验证抓包链路通不通。过滤规则不生效注意pcap_compile的过滤字符串格式。比如要抓 HTTP 流量用tcp port 80而不是直接写http要抓 ping 包用icmp。过滤表达式本身有语法写错了编译阶段就会返回失败。程序退出时崩溃多数和缓冲区管理有关。pcap_next_ex返回的pkt_data是内部缓冲区指针读取完后不能保存这个指针跨到下一次循环继续使用需要自己memcpy一份。调试阶段我强烈建议先用最简单的过滤表达式验证链路比如只抓icmp然后 ping 一下网关再抓tcp port 80浏览器访问一个普通网站。一层层把问题缩小不要一上来就越过环境问题去怀疑协议解析写错了。5. 从实验到实战优化方向与心得5.1 三个容易上手的扩展方向实验做完交差之后如果你还想继续发挥下面三个方向都是最容易出成果的第一个方向是保存 pcap 文件。Winpcap 提供了pcap_dump_open、pcap_dump、pcap_dump_close这组 API把pcap_pkthdr和数据包内容写进文件保存的文件可以被 Wireshark 直接打开。这意味着你的嗅探器抓完包后还能用专业工具二次分析补齐自己解析能力不足的部分。第二个方向是 HTTP 请求级解析。在 TCP 端口 80 的载荷里找GET、POST、Host:这些关键字把访问的 URL、Host、User-Agent 打印出来这就是一个迷你 HTTP 日志分析器。做的时候要处理 TCP 分片和乱序逻辑会复杂一些但做完对 TCP 流式语义的理解会深很多。第三个方向是 GUI 化。控制台虽好但展示能力有限。可以考虑用 C 配合 Qt 或者 Win32 列表控件做一个简单的界面左侧实时滚动数据包列表右侧显示统计图。实现时要注意把抓包循环放到独立线程里界面线程通过消息或回调刷新否则抓包一阻塞界面就卡死。5.2 我的几条排错心得最后分享几条我个人的实操体会全是踩过坑换来的经验。第一先把环境搞干净。管理员权限、npf 服务、WpdPack 路径这三件事没捋顺后面所有代码问题都会被环境问题盖住排查起来特别费劲。我见过有人花一下午调代码最后发现是压根没以管理员身份运行。第二解析协议时先看十六进制再写结构体。不要把代码一写完就当成功最好用 Wireshark 抓同一个包做对照逐字段比对。我第一次写 IP 头解析时就是把ver_ihl的低 4 位当成了首部长度本身没乘 4结果 TCP 头的起始位置算错了后面全乱。第三读懂 API 返回值。pcap_next_ex返回 1 是成功0 是超时-1 是错误。很多人只判断结果 ! 1就当失败处理结果把正常超时也当异常输出一堆误导信息。严格按返回值分类处理程序稳定性会好很多。说实话这个实验的技术难度不算高但它把一个完整的“抓包—解析—统计—呈现”链路从头到尾走了一遍。我记得第一次在控制台上看到自己抓到的 ICMP 报文正确打印出源 IP 和目的 IP 时那种从 0 到 1 的成就感确实比直接打开 Wireshark 看现成数据来得强烈得多。沿着这个项目继续往下做你的网络协议功底会在不知不觉中扎实起来。本文还有配套的精品资源点击获取