网络安全 频道

手把手教你捕获数据包

 

一.捕获数据包的实现原理:
在通常情况下,网络通信的套接字程序只能响应与自己硬件地址相匹配的或是以广播形式发出的数据帧,对于其他形式的数据帧比如已到达网络接口但却不是发给此地址的数据帧,网络接口在验证投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取与自己无关的的数据包。
所以我们要想实现截获流经网络设备的所有数据包,就要采取一点特别的手段了:
将网卡设置为混杂模式。
这样一来,该主机的网卡就可以捕获到所有流经其网卡的数据包和帧。
但是要注意一点,这种截获仅仅是数据包的一份拷贝,而不能对其进行截断,要想截断网络流量就要采用一些更底层的办法了,不在本文的讨论范围之内。
 
二. 捕获数据包的编程实现:
1.raw socket的实现方法
不同于我们常用的数据流套接字和数据报套接字,在创建了原始套接字后,需要用WSAIoctl()函数来设置一下,它的定义是这样的

int WSAIoctl(
  SOCKET s,
  DWORD dwIoControlCode,
  LPVOID lpvInBuffer,
  DWORD cbInBuffer,
  LPVOID lpvOutBuffer,
  DWORD cbOutBuffer,
  LPDWORD lpcbBytesReturned,
  LPWSAOVERLAPPED lpOverlapped,
  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

虽然咋一看参数比较多,但是其实我们最关心的只是其中的第二项而已,我们需要做的就是把第二项设置为SIO_RCVALL,讲了这么多其实要做的就是这么一行代码,很简单吧?^_^
 当然我们还可以指定是否亲自处理IP头,但是这并不是必须的。
完整的代码类似与如下这样,加粗的代码是与平常不同的需要注意的地方:
( 为了让代码一目了然,我把错误处理去掉了,下同)

#include “WinSock2.h”
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
 
SOCKET SnifferSocket
  WSADATA wsaData;
  iFlag=WSAStartup(MAKEWORD(2,2),&wsaData);           //开启winsock.dll
                                 
SnifferSocket=WSASocket(AF_INET,             //创建raw  socket
SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
 
  char FAR name[128];                                //获取本机IP地址
gethostname(name, sizeof(name));
  struct hostent FAR * pHostent;
  pHostent = gethostbyname(name);
 
  SOCKADDR_IN sa;                           //填充SOCKADDR_IN结构的内容
  sa.sin_family = AF_INET;
  sa.sin_port = htons(6000);           // 端口号可以随便改,当然与当然系统不能冲突
  memcpy(&(sa.sin_addr),pHostent->h_addr,pHostent->h_length);
 
bind(SnifferSocket,(LPSOCKADDR)&sa,sizeof(sa));            //绑定
  // 置ioctl来接收所有网络数据,关键步骤
  DWORD dwBufferLen[10] ;
  DWORD dwBufferInLen = 1 ;
  DWORD dwBytesReturned = 0 ;
  WSAIoctl(SnifferSocket, IO_RCVALL,&dwBufferInLen, izeof(dwBufferInLen),
  &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );

至此,实际就可以开始对网络数据包进行嗅探了,而对于数据包的接收还是和普通的socket一样,通过recv()函数来完成,因为这里涉及到不同的socket模型,接收方法差别很大,所以在此就不提供接收的代码了。
 
0
相关文章