WinPcap是windows下的一个开源库,简单来说就是用户自己可以发送数据包,比如windows XP之后就不能用socket发送SYN数据包了,因为操作系统进行了封装。所以想要发送自己的数据包,就要绕开操作系统,WinPcap就提供了这样的功能。
再说ARP——地址解析协议,ARP是数据链路层的协议。一般来说,一个局域网会用一个或多个路由器与Internet连接,那么当外部数据要发送到目的主机是怎么样的呢?同样,局域网内部主机间通信是怎么样的。我们都知道,网络通信的本质是寻找MAC地址,但是在socket编程中我们只是给了目标机的IP地址,并没有MAC地址。
MAC的工作原理:外来的数据包到达路由器时,路由器取出数据包中的目的IP地址,如果路由器知道这个IP地址是哪台主机,那么路由器会直接将数据包发过去。假如路由器不知道这个IP是哪台主机,则路由器会广播一个ARP请求包,意思是“192.168.0.10是谁的IP?”。当局域网的主机收到数据包后会检查自己的IP,看是不是192.168.1.10,如果不是,则丢弃,假如是,则该主机会把发送方的IP和MAC地址记录下来,同时把自己的MAC发过去。
既然ARP的请求是广播形式,那我们可以用ARP来嗅探局域网中的主机,简单来说就是发送一个ARP数据请求包,看有没有回应,如果有,则说明局域网中有对应的IP主机。
0 8 16 32
+-------------------------+-------------------------+
| 硬件类型 | 协议类型 |
+-------------------------+-------------------------+
| 硬件长度 | 协议长度 | 操作 |
+------------+------------+-------------------------+
| 发送端硬件地址 6字节 |
+---------------------------------------------------+
| 发送端协议地址 |
+---------------------------------------------------+
| 目的端硬件地址 6字节 |
+---------------------------------------------------+
| 目的端协议地址 |
+---------------------------------------------------+
硬件类型:以太网上填 1
协议类型:如果是IPV4,则写0x0800
硬件长度:物理地址的长度以字节为单位,mac地址的长度为6
协议长度:逻辑地址长度,即IP地址,以字节为单位,IPV4的长度为4字节
操作:1表示ARP请求,2表示ARP应答
发送端硬件地址 / 发送端协议地址:发送端的mac地址和IP地址
目的端硬件地址 / 目的端协议地址:目的端mac地址和IP地址,ARP请求数据包是以广播的形式发送的,所以他不知道目的硬件地址。《TCP-IP协议簇》上说对于ARP请求报文,目的端硬件地址全为0,但我测试时全为1也可以。
只是一个ARP数据包还是不能发送的,得加上以太网头,最后组成如下格式:
0 6 12 14
+-------------------+------------------+--------+-----------+
| 以太网目的地址 | 以太网源地址 | 帧类型 | ARP报文 |
+-------------------+------------------+--------+-----------+
注意:对于ARP请求报文来说,它是广播发送的,所以以太网目的地址全写1,不然发不出去。
struct ARP_HEADER
{
unsigned char ucHardwareType[2];
unsigned char ucProtocolType[2];
unsigned char ucHardwareLen;
unsigned char ucProtocolLen;
unsigned char ucOperatorType[2];
unsigned char ucSenderMacAddr[6];
unsigned char ucSenderIpAddr[4];
unsigned char ucRecverMacAddr[6];
unsigned char ucRecverIpAddr[4];
unsigned char ucPadding[18];
};
struct ETHERNET_HEADER
{
unsigned char ucDstMacAddr[6];
unsigned char ucSrcMacAddr[6];
unsigned char ucEthernetType[2];
};
struct DEVS_INFO
{
char szDevName[512];
char szDevsDescription[512];
};
int GetAllDevs( DEVS_INFO devsList[] )
{
int nDevsNum = 0;
pcap_if_t *alldevs;
char errbuf[PCAP_ERRBUF_SIZE];
if ( pcap_findalldevs(&alldevs,errbuf) == -1 )
{
return -1;
printf("error in pcap_findalldevs_ex: %s\n",errbuf);
}
for ( pcap_if_t *d = alldevs; d != NULL; d = d->next )
{
strcpy( devsList[nDevsNum].szDevName, d->name );
strcpy( devsList[nDevsNum].szDevsDescription, d->description );
nDevsNum++;
}
pcap_freealldevs(alldevs);
return nDevsNum;
}
void HandlePacketCallBack(unsigned char *param,const struct pcap_pkthdr* packet_header, const unsigned char *ucCaptureContent)
{
ETHERNET_HEADER *pEthHeader = ( ETHERNET_HEADER *)ucCaptureContent;
if ( *((unsigned short *)(pEthHeader->ucEthernetType)) != ntohs(0x0806) )
{
return;
}
ARP_HEADER *pArp = ( ARP_HEADER *)(ucCaptureContent + sizeof (ETHERNET_HEADER) );
if ( inet_addr( (char *)param) != *((unsigned int *)(pArp->ucSenderIpAddr ) ) )
{
return ;
}
if ( htons(0x002) != *(unsigned short *)pArp->ucOperatorType )
{
return ;
}
printf("\nIP: ");
for ( int i = 0; i < 4; ++i )
{
printf("%d.", pArp->ucSenderIpAddr[i]);
}
printf("\b MAC: ");
for ( int i = 0; i < 6; ++i)
{
printf("0x%02x-", pArp->ucSenderMacAddr[i]);
}
printf("\b \n");
}
int SendPacket( const unsigned char *ucSendBuffer, int size, const char *pszRecverIpAddr )
{
DEVS_INFO devsList[64];
int nDevsNum = GetAllDevs( devsList ); //列举所有网卡
if ( nDevsNum < 1 )
{
printf("Get adapter infomation failed!");
exit(0);
}
for ( int i = 0; i < nDevsNum; ++i )
{
printf("%d. %s %s\n", i + 1, devsList[i].szDevName, devsList[i].szDevsDescription);
}
int selIndex = 0;
printf("Input the index of adapter: ");
scanf("%d", &selIndex );
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *handle = pcap_open_live(devsList[selIndex-1].szDevName, 65536, 1, 1000, errbuf );
if ( NULL == handle )
{
printf("\nUnable to open the adapter. %s is not supported by WinPcap\n");
return 0;
}
int index = 0;
while ( index ++ < 1 )
{
if ( pcap_sendpacket(handle, ucSendBuffer, size ) != 0)
{
printf("\nError sending the packet: %s\n", pcap_geterr(handle) );
return 0;
}
}
pcap_loop( handle, 64, HandlePacketCallBack, (unsigned char *)pszRecverIpAddr );
pcap_close(handle);
}
int main()
{
const char *pszSenderIpAddr = "10.126.72.37"; //源主机ip
const char *pszRecverIpAddr = "10.126.72.35"; //目的主机ip
const unsigned char ucSenderMacAddr[6] = {0x90, 0x2B, 0x34, 0x9A, 0xC2, 0xBB};//源主机mac
ARP_HEADER arp;
memset(&arp, 0x00, sizeof arp);
*(unsigned short *)&arp.ucHardwareType = htons(0x0001);
*(unsigned short *)arp.ucProtocolType = htons(0x0800);
arp.ucHardwareLen = 0x06;
arp.ucProtocolLen = 0x04;
*(unsigned short *)arp.ucOperatorType = htons(0x0001);
memcpy( arp.ucSenderMacAddr, ucSenderMacAddr, sizeof ucSenderMacAddr );
*( unsigned *)arp.ucSenderIpAddr = inet_addr(pszSenderIpAddr);
memset( &arp.ucRecverMacAddr, 0xff, sizeof arp.ucRecverMacAddr );
*(unsigned *) arp.ucRecverIpAddr = inet_addr(pszRecverIpAddr);
memcpy( arp.ucPadding, "hello world", 18);
ETHERNET_HEADER eth;
memset( ð.ucDstMacAddr, 0xFF, sizeof eth.ucDstMacAddr);
memcpy( eth.ucSrcMacAddr, arp.ucSenderMacAddr, 6 );
*(unsigned short *)eth.ucEthernetType = htons(0x0806);
unsigned char ucSend[1024];
memset( ucSend, 0, sizeof ucSend );
memcpy( ucSend, ð, sizeof eth );
memcpy( ucSend + sizeof eth, &arp, sizeof arp );
SendPacket(ucSend, sizeof arp + sizeof eth, pszRecverIpAddr );
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。