Win10 下基于 Npcap 的抓包程序详解
1. 背景
wireshark 是最常用的是网络抓包程序 ,不过,wireshark 也有无法满足我的时候。试想下,我们发送的 UDP 数据包的负载(payload)是自定义内容,此时的 wireshark 只能看到 payload 的原始数据。虽然可以使用 wireshark dissastor 将协议可视化(参考:Wireshark C 插件开发之插件框架),但是工作量大且繁琐。那有没有一种相对方便的手段实现监控数据包并解析 payload 的功能呢?有!我们可以自己实现抓包程序。
2. wireshark 抓包原理
Document:https://wiki.wireshark.org/libpcap
wireshark 调用 libpcap 实现监控网络数据包的功能。Win10 环境下,libpcap 的功能由 Npcap 提供。
3. Npcap 简介
Document:https://npcap.com/guide/index.html
Npcap 是专为 Windows 开发的一款网络抓包 SDK,该 SDK 提供了被应用程序调用的库文件和系统驱动程序。通过 Npcap,我们可以得到原始(raw)网络数据,即未经过 TCP/IP 协议栈的数据,也就是网卡收到的数据。同时呢,我们也可以通过 Npcap 设置接收过滤器,这样收到的数据就是我们感兴趣的数据,比如某个端口的数据。而且,Npcap 还提供发送原始(raw)网络数据的功能。
4. Npcap 原理
Document:https://npcap.com/guide/npcap-internals.html#npcap-internals-driver
Npcap 实现了 Win10 驱动程序,叫做 NPF(Netgroup Packet Filter),该驱动从 Win10 miniport 驱动获取网卡数据实现监控网络数据包的功能(Win10 使用 miniport 驱动控制网卡)。
5. Npcap 使用
Npcap SDK 使用起来很简单,一共分为三步。
5.1 安装 visual studio
我使用的是 visual studio 2019。
5.2 安装 npcap 到 win10
安装 Npcap 1.71 installer 到 win10 系统中,主要是安装了 NPF 驱动和 dll 文件(Packet.dll 和 Wpcap.dll)。
下载地址:https://npcap.com/#download
5.3 下载 Npcap SDK
Npcap SDK 中提供了 lib 和头文件,我们编写抓包程序时需要用到这些。
5.4 例程
这里,我以 Npcap SDK 中的 npcap-sdk-1.13\Examples-pcap\UDPdump 为例进行说明,UDPdump 用于监控收到的 UDP 数据包。
5.4.1 udpdump.c
在原有文件的基础上我添加了 #pragma comment(lib,"ws2_32.lib")
语句,否则 ntohs() 会导致编译失败。
/*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino, CACE Technologies
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <pcap.h>
#include <time.h>
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib")
#ifdef _WIN32
#include <tchar.h>
BOOL LoadNpcapDlls()
{
_TCHAR npcap_dir[512];
UINT len;
len = GetSystemDirectory(npcap_dir, 480);
if (!len) {
fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
return FALSE;
}
_tcscat_s(npcap_dir, 512, _T("\\Npcap"));
if (SetDllDirectory(npcap_dir) == 0) {
fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
return FALSE;
}
return TRUE;
}
#endif
/* 4 bytes IP address */
typedef struct ip_address
{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
/* IPv4 header */
typedef struct ip_header
{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
ip_address saddr; // Source address
ip_address daddr; // Destination address
u_int op_pad; // Option + Padding
}ip_header;
/* UDP header*/
typedef struct udp_header
{
u_short sport; // Source port
u_short dport; // Destination port
u_short len; // Datagram length
u_short crc; // Checksum