Alex_McAvoy

想要成为渔夫的猎手

Sniffer WinPcap抓包框架

【初始化 WinPcap】

编写 Sniffer_initCap() 功能函数,通过调用 pcap_findalldevs() 函数获得网卡接口信息来初始化 WinPcap

1
2
3
4
5
6
7
8
9
// 1.初始化WinPcap
int CSnifferDlg::Sniffer_initCap(){
devCount = 0;
if (pcap_findalldevs(&alldev, errorBufffer) == -1)//获得网卡接口信息
return -1;
for (dev = alldev; dev; dev = dev->next)//记录设备数
devCount++;
return 0;
}

【捕获数据包】

编写 Sniffer_startCap() 功能函数,用于捕获数据包

该函数框架如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 捕获数据包
int CSnifferDlg::Sniffer_startCap() {
步骤 1:网卡与过滤器设置
步骤 2:获取选中的网卡接口
步骤 3:打开网卡指定接口
步骤 4:检查是否为非以太网
步骤 5:设置子网掩码
步骤 6:编译过滤器
步骤 7:设置过滤器
步骤 8:设置时间
步骤 9:设置数据包存储路径
步骤 10:创建数据包接收线程
return 1;
}

网卡与过滤器设置

通过控件的 GetCurSel() 函数获取下拉框的选项来进行网卡与过滤器设置

1
2
3
4
5
6
7
8
9
10
11
//步骤 1:网卡与过滤器设置
int netCardIndex = this->m_comboBoxNetCard.GetCurSel();//网卡接口索引
int filterIndex = this->m_comboBoxFilterRule.GetCurSel();//过滤器索引
if (netCardIndex == 0 || netCardIndex == CB_ERR) {
MessageBox("请选择网卡接口");
return -1;
}
if (filterIndex == CB_ERR) {
MessageBox("过滤器选择错误");
return -1;
}

获取选中的网卡接口

1
2
3
4
//步骤 2:获取选中的网卡接口
dev = allDevs;
for (int i = 0; i < filterIndex - 1; i++)
dev = dev->next;

打开网卡指定接口

利用 pcap_open_liive() 函数打开指定网卡接口,若无法打开则释放设备列表

1
2
3
4
5
6
7
8
9
10
11
12
//步骤 3:打开网卡指定接口
int dataPackageLen = 65536;//捕获数据包长度
int overtime = 1000;//读超时时间
int flag = 1;//网卡混淆模式设置标志,非0即为混淆模式

//针对指定网络接口创建一捕获句柄,用于后续捕获数据
devHandle = pcap_open_live(dev->name, dataPackageLen, flag, overtime, errorBufffer);
if (devHandle == NULL) {
MessageBox("无法打开接口:" + CString(dev->description));
pcap_freealldevs(allDevs);//释放设备列表
return -1;
}

检查是否为非以太网

利用 pcap_datalink() 方法检查是否为以太网,若为非以太网则释放设备列表

1
2
3
4
5
6
//步骤 4:检查是否为非以太网
if (pcap_datalink(devHandle) != DLT_EN10MB) {
MessageBox("不适合非以太网的网络");
pcap_freealldevs(allDevs);//释放设备列表
return -1;
}

设置子网掩码

1
2
3
4
5
6
//步骤 5:设置子网掩码
u_int netmask;//子网掩码
if (dev->addresses != NULL)
netmask = ((struct sockaddr_in *)(dev->addresses->netmask))->sin_addr.S_un.S_addr;
else
netmask = 0xffffff;

编译过滤器

利用 pcap_compile() 方法设置过滤器,若无法设置则释放设备列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//步骤 6:编译过滤器
struct bpf_program fcode;//BPF过滤代码结构
if (filterIndex == 0) {
char filter[] = "";
if (pcap_compile(devHandle, &fcode, filter, 1, netmask) < 0) {
MessageBox("语法错误,无法编译过滤器");
pcap_freealldevs(allDevs);//释放设备列表
return -1;
}
}
else {
CString str;
this->m_comboBoxFilterRule.GetLBText(filterIndex, str);
int len = str.GetLength() + 1;
char *filter = (char*)malloc(len);
for (int i = 0; i < len; i++) filter[i] = str.GetAt(i);
if (pcap_compile(devHandle, &fcode, filter, 1, netmask) < 0) {
MessageBox("语法错误,无法编译过滤器");
pcap_freealldevs(allDevs);//释放设备列表
return -1;
}
}

设置过滤器

利用 pcap_setfilter() 方法来设置过滤器,若无法设置则释放设备列表

1
2
3
4
5
6
//步骤 7:设置过滤器
if (pcap_setfilter(devHandle, &fcode) < 0) {
MessageBox("设置过滤器错误");
pcap_freealldevs(allDevs);//释放设备列表
return -1;
}

设置时间

利用 struct tm 与 time_t 类型,获取当前时间,同时利用 strftime() 函数来格式化本地时间

1
2
3
4
5
6
7
//步骤 8:设置时间
struct tm *localTime;//年月日结构的时间
time_t secondTime;//自1970至今多少秒的时间
time(&secondTime);
localTime = localtime(&secondTime);
char realTime[30];//当前时间
strftime(realTime, sizeof(realTime), "%Y%m%d %H%M%S", localTime);//格式化本地时间

设置数据包存储路径

利用 pcap_dump_open() 函数创建一个临时文件,捕获的数据会暂时存放在该临时文件中,在捕获结束后,可选择将此文件存储于指定路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//步骤 9:设置数据包存储路径
CFileFind file;
if (!file.FindFile("Data"))
CreateDirectory("Data", NULL);
memset(filePath, 0, sizeof(filePath));
memset(fileName, 0, sizeof(fileName));
strcpy(filePath, "Data\\");
strcat(fileName, realTime);
strcat(fileName, ".lix");
strcat(filePath, fileName);
dumpFile = pcap_dump_open(catchHandle, filePath);
if (dumpFile == NULL){
MessageBox("文件创建错误!");
return -1;
}

创建数据包接收线程

用 CreateThread() 函数创建接收数据包的线程

1
2
3
4
5
6
7
8
9
//步骤 10:创建数据包接收线程
LPDWORD threadCap = NULL;
m_ThreadHandle = CreateThread(NULL, 0, Sniffer_capThread, this, 0, threadCap);
if (m_ThreadHandle == NULL) {
CString str;
str.Format("创建线程错误,代码为:%d.", GetLastError());
MessageBox(str);
return -1;
}
感谢您对我的支持,让我继续努力分享有用的技术与知识点!