使用原始套接字Raw Socket实现数据包嗅探

Schoolleave

发布日期: 2018-12-20 12:25:50 浏览量: 1642
评分:
star star star star star star star star star_border star_border
*转载请注明来自write-bug.com

背景

网络上随时都流通了大量的数据包,我们要想实现抓包并分析,实现思路思路大概是:在合适的时候捕获数据包,保存到缓冲区,作为备用;然后,按照一定的结构和格式去读取缓冲区的内容。由于各种公开的网络协议是已知的,所以对于数据包的分析就比较简单。

通常我们都是使用类似WireShark的抓包软件嗅探数据包,这些抓包工具大部分都是基于WinPcap库实现的数据包嗅探功能。而现在,本文讲解下使用原始套接字的RawSocket方式实现数据包的嗅探。当然,和WinPcap相比,Raw Socket有很大的局限性。,它只能抓到IP层及以上的数据包,抓不到MAC层的数据包。

但是,Raw Socket开发的程序使用起来比较方便,不需要额外安装什么。本文就把实现的过程原理写成文档,分享给大家。

程序分析

要实现基于Raw Socket嗅探数据包,关键是创建Raw Socket。那么创建步骤就如下所示:

1. 初始化 Winsock 服务环境

在使用 Socket 函数之前,必须要经过初始化 Winsock 库才能成功调用。我们使用 WSAStartup 函数来帮助我们实现初始化工作,指定使用 Socket 的版本。

  1. // 初始化Winsock服务环境, 设置版本
  2. WSADATA wsaData = {0};
  3. if(0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
  4. {
  5. ShowError("WSAStartup");
  6. return FALSE;
  7. }

2. 创建原始套接字

我们调用 socket 函数来创建套接字,其中,函数中的第 1 个参数为 AF_INET ,表示IPv4地址族格式;第 2 个参数为 SOCK_RAW ,表示要创建原始套接字,注意:只有管理员权限用户才能创建原始套接字;第 3 个参数为 IPPROTO_IP,表示的是IP协议。

  1. // 创建原始套接字
  2. // !!!Windows上没办法用Raw Socket抓MAC层的数据包,只能抓到IP层及以上的数据包!!!
  3. g_RawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  4. if (INVALID_SOCKET == g_RawSocket)
  5. {
  6. WSACleanup();
  7. ShowError("socket");
  8. return FALSE;
  9. }

3. 绑定嗅探的IP地址

帮使用 bind 函数来绑定IP地址,这样原始套接字就会使用绑定IP地址对应的网卡进行数据包的嗅探。其中,端口要设为 0 。

  1. // 构造地址结构
  2. sockaddr_in SockAddr = {0};
  3. RtlZeroMemory(&SockAddr, sizeof(sockaddr_in));
  4. SockAddr.sin_addr.S_un.S_addr = inet_addr(lpszHostIP);
  5. SockAddr.sin_family = AF_INET;
  6. SockAddr.sin_port = htons(0);
  7. // 绑定
  8. if (SOCKET_ERROR == ::bind(g_RawSocket, (sockaddr *)(&SockAddr), sizeof(sockaddr_in)))
  9. {
  10. closesocket(g_RawSocket);
  11. WSACleanup();
  12. ShowError("bind");
  13. return FALSE;
  14. }

4. 设置混杂模式

要想捕获到其它目的地非本机的数据包,就需要将网卡设置为混杂模式。ioctlsocket 函数中的 SIO_RCVALL 控制代码使套接字能够接收通过网络接口的所有IPv4或IPv6数据包。

  1. // 设置混杂模式,这样才能捕获所有的数据包
  2. DWORD dwSetVal = 1;
  3. if (SOCKET_ERROR == ioctlsocket(g_RawSocket, SIO_RCVALL, &dwSetVal))
  4. {
  5. closesocket(g_RawSocket);
  6. WSACleanup();
  7. ShowError("ioctlsocket");
  8. return FALSE;
  9. }

5. 捕获数据包

直接创建多线程,在多线程中不断循环调用 recvfrom 函数接收数据包。

  1. iRecvBytes = recvfrom(g_RawSocket, (char *)lpRecvBuf, dwBufSize, 0, (sockaddr *)(&RecvAddr), &iRecvAddrLen);

经过上面 5 个步骤的操作,就可以使用Raw Socket成功捕获数据包了。我们可以将捕获到的数据包保存到缓冲区,并按照一定的结构和格式去读取缓冲区的内容,对数据包进行分析。

至于数据包的分析部分,本文在此就不详细讲解了。由于各种公开的网络协议是已知的,所以对于数据包的分析就只需要对照着协议格式仔细进行分析即可。

程序测试

我们以管理员身份运行程序,选择其中一个IP地址对应的网卡进行数据包嗅探,成功嗅探到数据包。

总结

对于上面的程序,我们之分析关键部分的代码,对于IP的显示和选择,以及数据包的分析我们在本文上并没有给出分析过程,大家可以对照代码进行理解即可。

其中,需要注意的是,需要管理员权限才能成功创建原始套接字。所以,测试程序的时候,要记得以管理员权限运行程序。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download RawSocket_Test.7z ( 168.37kb, 58次下载 )

发送私信

人生就像马拉松,获胜的关键不在于瞬间的爆发

8
文章数
20
评论数
最近文章
eject