Windows下使用winpcap-2.1ARP探测局域网活动主机(发送ARP请求)

来源:互联网 发布:mysql中full join报错 编辑:程序博客网 时间:2024/05/24 06:30

通过上一次的配置环境,现在就可以使用了,那么这里我们就先来发一个arp请求吧,这里建议大家安装一个wireshark(抓包工具,操作简单),以便于我们随时查看数据包,方便调试。

首先,我们需要知道的是,ARP是地址解析协议,工作在数据链路层,用来在一个局域网内获取一个IP的mac地址,当我们想要知道一个IP的MAC地址的时候,我们就向局域网广播一个arp请求,如果此IP为活动主机,则其就会回复一个arp应答,我们就是通过有没有收到arp应答来判断此ip主机是否为活动的。

按照上次文章所说的建立好工程,我建立的是简单的控制台程序,配好环境,写上需要的头文件,这里我们还需要#include"packet32.h",#include "ntddndis.h"这两个头文件,我们会用到里面的一些东西。

先定义三个结构体,用来表示我们的包,以太网首部和arp包

//以太网首部 struct ethernet_head{unsigned char dest_mac[6];//目的MAC地址unsigned char source_mac[6];//源MAC地址unsigned short eh_type;//帧类型};
//arp数据包struct arp_head{unsigned short hardware_type;//硬件类型unsigned short protocol_type;//协议类型unsigned char add_len;//硬件地址长度unsigned char pro_len;//协议地址长度unsigned short option;//操作类型,arp请求与应答,rarp请求与应答unsigned char sour_addr[6];//源MACunsigned long sour_ip;//源IPunsigned char dest_addr[6];//目的MACunsigned long dest_ip;//源IPunsigned char padding[18];//填充数据};//发送的数据包struct arp_packet{ethernet_head eth;//以太网首部arp_head arp;//arp包};
这里有个问题需要主要,在vs中,由于编译的优化问题,结构体的大小不等于结构体中每个变量的大小和,这样在后面的使用会存在问题(将我们构造的数据包强转为char*数据和将收到数据强转回来时),主要原因可以看一下这位的这篇点击打开链接

这里可以这样设置,取消这种对齐项目->属性->C/C++->代码生成,结构成员对齐中设为1字节即可。

需要的变量:(不是所有都用了,有些是我用来做测试的,自己看着用吧)

pcap_if_t *alldevs;            //全部网卡列表 pcap_if_t *d;                  //一个网卡 int inum;                      //用户选择的网卡序号 int i = 0;                       //循环变量 pcap_t *adhandle;              //一个pcap实例 char errbuf[PCAP_ERRBUF_SIZE]; //错误缓冲区 unsigned char *mac;            //本机MAC地址 unsigned char *packet;         //ARP包 unsigned long sourceIP;          //要伪装成的IP地址 unsigned long destIP;pcap_addr_t *pAddr;            //网卡地址 unsigned long ip;              //IP地址 unsigned long netmask;         //子网掩码 struct in_addr net_ip_address;//网卡IP信息,在pcap.h里面有定义  struct in_addr net_mask_address;char *net_ip_string;char *net_mask_string;


1.获取本机网卡列表

if (pcap_findalldevs(&alldevs, errbuf) == -1){cout << "Error in pcap_findalldevs:" << errbuf << endl;}

2.这里我们可以输出一下我们获取到的所有网卡信息,当然这在发送arp请求中不是必须的,但考虑到一个电脑可能有多个网卡,这时我们需要让用户选择自己想要用来发送arp请求的网卡

for (d = alldevs; d; d = d->next){cout << ++i;if (d->description){cout << "." << d->description << ";"<< d->addresses << endl;}elsecout << ".No description available" << endl;}//如果没有网卡if (i == 0){cout << "\nNo interfaces found! Make sure WinPcapis installed.\n" << endl;return -1;}
3.打开我们需要的那个网卡,这里我需要的就是第一个网卡,所以直接打开,如果你需要的是其它网卡,先用一个循环跳转到你需要的网卡(d->next表示下一个网卡信息:d=d->next)

d = alldevs; if ((adhandle = pcap_open_live(d->name, 65536, 0, 1000, errbuf)) == NULL){cout << "Unable to open the adapter." << d->name << " is not supported bu WinPcap" << endl;return -1;}
4.获取本机ip地址(这里为什么是pAddr->next->addr,很多地方直接是pAddr->addr,实际我在使用的时候,后者不行,获取的ip这些信息是空的,必须要先next,你们可以自己试试,原因布吉岛。。。。。。。。)

pAddr = d->addressesip = ((struct sockaddr_in *)pAddr->next->addr)->sin_addr.s_addr;
5.获取本机mac(这个函数自己实现的)

mac = GetSelfMac(alldevs->name);
unsigned char* GetSelfMac(char* pDevName){static u_char mac[6];LPADAPTER lpAdapter = PacketOpenAdapter(pDevName);if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))return NULL;PPACKET_OID_DATA OidData = (PPACKET_OID_DATA)malloc(6 + sizeof(PACKET_OID_DATA));if(OidData == NULL){PacketCloseAdapter(lpAdapter);return NULL;}OidData->Oid = OID_802_3_CURRENT_ADDRESS;OidData->Length = 6;memset(OidData->Data, 0, 6);BOOLEAN Status = PacketRequest(lpAdapter, FALSE, OidData);if (Status)memcpy(mac, (u_char*)(OidData->Data), 6);free(OidData);PacketCloseAdapter(lpAdapter);return mac;}

6.构造包(函数自己实现),不修改vs的结构体对齐,这里就会出错

destIP = inet_addr("192.168.218.128");//我要探测的IPpacket = BuildArpPacket(mac, sourceIP, destIP);
unsigned char *BuildArpPacket(unsigned char* source_mac, unsigned long srcIP, unsigned long destIP){static struct arp_packet packet;//目的MAC地址为广播地址,FF-FF-FF-FF-FF-FF memset(packet.eth.dest_mac, 0xFF, 6);//源MAC地址 memcpy(packet.eth.source_mac, source_mac, 6);//上层协议为ARP协议,0x0806 packet.eth.eh_type = htons(0x0806);//硬件类型,Ethernet是0x0001 packet.arp.hardware_type = htons(0x0001);//上层协议类型,IP为0x0800 packet.arp.protocol_type = htons(0x0800);//硬件地址长度:MAC地址长度为0x06 packet.arp.add_len = 0x06;//协议地址长度:IP地址长度为0x04 packet.arp.pro_len = 0x04;//操作:ARP请求为1 packet.arp.option = htons(0x0001);//源MAC地址 memcpy(packet.arp.sour_addr, source_mac, 6);//源IP地址 packet.arp.sour_ip = srcIP;//目的MAC地址,填充0 memset(packet.arp.dest_addr, 0, 6);//目的IP地址 packet.arp.dest_ip = destIP;//填充数据,18个字节memset(packet.arp.padding, 0, 18);return (unsigned char*)&packet;}

7.发送数据包,这里之后,wireshark(以后我就叫他鲨鱼了)就能抓到数据包了
if (pcap_sendpacket(adhandle, packet, 60) == -1){cout << "pcap_sendpacket error" << endl;}

至此,arp请求的发送完成,下次我们来看接收,通过对一个我们想要扫描的ip发送arp请求,如果收到了来自该ip的arp应答,则此ip的主机为活动主机


0 0
原创粉丝点击