基于ARP协议获取局域网内主机MAC地址

基于ARP协议获取局域网内主机MAC地址

ARP帧数据结构

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#defineBROADMAC{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}//广播MAC
#defineEH_TYPE0x0806//ARP类型
#defineARP_HRD0X0001//硬件类型:以太网接口类型为
#defineARP_PRO0x0800//协议类型:IP协议类型为X0800
#defineARP_HLN0x06//硬件地址长度:MAC地址长度为B
#defineARP_PLN0x04//协议地址长度:IP地址长度为B
#defineARP_REQUEST0x0001//操作:ARP请求为
#defineARP_REPLY0x0002//操作:ARP应答为
#defineARP_THA{0,0,0,0,0,0}//目的MAC地址:ARP请求中该字段没有意义,设为;ARP响应中为接收方的MAC地址
#defineARP_PAD{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}//18字节的填充数据
#defineSPECIAL0x70707070//定义获得自己MAC地址的特殊源IP,.112.112.112
#defineETH_HRD_DEFAULT{BROADMAC,{0,0,0,0,0,0},htons(EH_TYPE)}//广播ARP包帧头
#defineARP_HRD_DEFAULT{htons(ARP_HRD),htons(ARP_PRO),ARP_HLN,ARP_PLN,htons(ARP_REQUEST),{0,0,0,0,0,0},0,ARP_THA,0,ARP_PAD}
#defineIPTOSBUFFERS12
#defineWM_PACKETWM_USER+105//用户自定义消息

structethernet_head
{
//物理帧帧头结构
unsignedchardest_mac[6];//目标主机MAC地址(6字节)
unsignedcharsource_mac[6];//源端MAC地址(6字节)
unsignedshorteh_type;//以太网类型(2字节)
};
structarp_head
{
//ARP数据帧
unsignedshorthardware_type;//硬件类型:以太网接口类型为
unsignedshortprotocol_type;//协议类型:IP协议类型为X0800
unsignedcharadd_len;//硬件地址长度:MAC地址长度为B
unsignedcharpro_len;//协议地址长度:IP地址长度为B
unsignedshortoption;//操作:ARP请求为,ARP应答为

unsigned
charsour_addr[6];//源MAC地址:发送方的MAC地址
unsignedlongsour_ip;//源IP地址:发送方的IP地址
unsignedchardest_addr[6];//目的MAC地址:ARP请求中该字段没有意义;ARP响应中为接收方的MAC地址
unsignedlongdest_ip;//目的IP地址:ARP请求中为请求解析的IP地址;ARP响应中为接收方的IP地址
unsignedcharpadding[18];
};

structarp_packet//最终arp包结构
{//物理帧结构
ethernet_headeth;//以太网头部
arp_headarp;//arp数据包头部
};

获取本机的网络适配器

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->inti=1;
stringstrDev="";
m_Dev.AddString(
"经分析,本系统网络适配器列表如下:");
pcap_if_t
*alldevs=0;
pcap_if_t
*pDev=0;
pcap_addr_t
*pAdr=0;
charerrbuf[PCAP_ERRBUF_SIZE+1];
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
//获得设备列表
MessageBox(errbuf,NULL,MB_OK|MB_ICONINFORMATION);//若没有设备则弹出警告
exit(1);
}
for(pDev=alldevs;pDev;pDev=pDev->next)
{
//遍历所有成员
if(pDev->description)
{
strDev
=char(i+48);
strDev
+=".";
strDev
+=DelSpace(pDev->description);//去掉网卡描述过多的空格
pAdr=pDev->addresses;//IP地址
if(pAdr!=NULL)
{
if(pAdr->addr->sa_family==AF_INET)
{
//pAdr->addr是否IP地址类型
strDev+="->";
strDev
+=IpToStr(((structsockaddr_in*)pAdr->addr)->sin_addr.s_addr);
if(IpToStr(((structsockaddr_in*)pAdr->addr)->sin_addr.s_addr)[0]!='0')
{
m_Dev_No
=i;
UpdateData(FALSE);
//传递变量值去界面
}
strDev
+="&[";
strDev
+=IpToStr(((structsockaddr_in*)pAdr->netmask)->sin_addr.s_addr);//子网掩码
strDev+="]";
GetDlgItem(IDC_GET_MAC)
->EnableWindow(TRUE);//若网卡有IP地址,则使抓包按钮可用
}
}
m_Dev.InsertString(i
++,strDev.c_str());
}
}
pcap_freealldevs(alldevs);
//不再需要网络适配器列表,释放

获取本机MAC地址

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->unsignedchar*BuildArpRequestPacket(unsignedchar*source_mac,unsignedchar*arp_sha,unsignedlongchLocalIP,unsignedlongarp_tpa,intPackSize)
{
//封装ARP请求包
staticarp_packetarpPackStru;
staticconstarp_packetarpDefaultPack={ETH_HRD_DEFAULT,ARP_HRD_DEFAULT};
memcpy(
&arpPackStru,&arpDefaultPack,sizeof(arpDefaultPack));
//填充源MAC地址
memcpy(arpPackStru.eth.source_mac,source_mac,6);//源MAC
memcpy(arpPackStru.arp.sour_addr,arp_sha,6);//源MAC
arpPackStru.arp.sour_ip=chLocalIP;//源IP地址
arpPackStru.arp.dest_ip=arp_tpa;//目的IP地址
return(unsignedchar*)&arpPackStru;
}
unsigned
char*GetSelfMac(char*pDevName,unsignedlongchLocalIP)
{
//获得本机MAC地址,pDevName为网卡名称,chLocalIP为本机IP地址
pcap_t*pAdaptHandle;
charerrbuf[PCAP_ERRBUF_SIZE+1];
//打开网卡适配器
if((pAdaptHandle=pcap_open_live(pDevName,60,1,100,errbuf))==NULL)
{
MessageBox(NULL,
"无法打开适配器,可能与之不兼容!","Note",MB_OK);
returnNULL;
}
structpcap_pkthdr*header;//包头部
constu_char*pkt_data;//包数据部
intres;
unsigned
shortarp_op;
staticunsignedchararp_sha[6];
unsigned
longarp_spa=0;
unsigned
longarp_tpa=0;
unsigned
charsource_mac[6]={0,0,0,0,0,0};
unsigned
char*arp_packet_for_self;
arp_packet_for_self
=BuildArpRequestPacket(source_mac,source_mac,SPECIAL,chLocalIP,60);//把自己作为目的,构建一个广播ARP请求包,伪造请求来自.112.112.112
while(!GetMacSignal)
{
pcap_sendpacket(pAdaptHandle,arp_packet_for_self,
60);//发送ARP请求包
Sleep(10);
res
=pcap_next_ex(pAdaptHandle,&header,&pkt_data);
if(res==0)
{
continue;
}
//物理帧头部占字节,然后是硬件类型,上层协议类型,硬件地址长度,IP地址长度,这四个占去字节,具体参看ARP帧的数据结构
memcpy(&arp_op,pkt_data+20,2);//操作类型(请求或应答)
memcpy(arp_sha,pkt_data+22,6);//源MAC
memcpy(&arp_spa,pkt_data+28,4);//源IP
memcpy(&arp_tpa,pkt_data+38,4);//目标IP

if(arp_op==htons(ARP_REPLY)&&arp_spa==chLocalIP&&arp_tpa==SPECIAL)
{
//是本机
GetMacSignal=1;
pcap_close(pAdaptHandle);
returnarp_sha;
}
Sleep(
100);//若不成功再等ms再发,让网卡歇歇
}
pcap_close(pAdaptHandle);
returnarp_sha;
}

发送ARP请求线程

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->voidSendArpRequest(pcap_if_t*pDev,unsignedchar*bLocalMac)
{
//发送ARP请求
pcap_addr_t*pAdr=0;
unsigned
longchLocalIp=0;//存放本地ip地址
unsignedlongarp_tpa=0;
unsigned
longsnd_tpa=0;
unsigned
longnlNetMask=0;
intnetsize=0;
constchar*pDevName=strSelDeviceName.c_str();
pcap_t
*pAdaptHandle;
charerrbuf[PCAP_ERRBUF_SIZE+1];
//打开网卡适配器
if((pAdaptHandle=pcap_open_live(pDev->name,60,0,100,errbuf))==NULL)
{
MessageBox(NULL,
"无法打开适配器,可能与之不兼容!","Send",MB_OK);
return;
}
unsigned
char*arp_packet_for_req;
arp_packet_for_req
=BuildArpRequestPacket(bLocalMac,bLocalMac,chLocalIp,chLocalIp,60);//构造包
unsignedlongulOldMask=0;
for(pAdr=pDev->addresses;pAdr;pAdr=pAdr->next)
{
if(!nThreadSignal)
{
//判断线程是否应该中止
break;
}
chLocalIp
=((structsockaddr_in*)pAdr->addr)->sin_addr.s_addr;//得到本地ip
if(!chLocalIp)
{
continue;
}
nlNetMask
=((structsockaddr_in*)(pAdr->netmask))->sin_addr.S_un.S_addr;//得到子网掩码
if(ulOldMask==nlNetMask)
{
continue;
}
ulOldMask
=nlNetMask;
netsize
=~ntohl(nlNetMask);//子网大小
arp_tpa=ntohl(chLocalIp&nlNetMask);//IP地址
for(inti=0;i<netsize;i++)
{
if(!nThreadSignal)
{
break;
}
arp_tpa
++;
snd_tpa
=htonl(arp_tpa);
memcpy(arp_packet_for_req
+38,&snd_tpa,4);//目的IP在子网范围内按序增长
pcap_sendpacket(pAdaptHandle,arp_packet_for_req,60);//发送ARP请求包
Sleep(5);//休息一下再发ARP请求包
}
}
}
UINTStartArpScan(LPVOIDmainClass)
{
//发送ARP请求线程
AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET,0,1);//开始发送ARP请求包
SendArpRequest(pDevGlobalHandle,bLocalMac);//对选中设备的所有绑定的IP网段进行ARP请求
AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET,0,2);//全部ARP请求包发送完毕
return0;
}

接收ARP响应线程

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->UINTWaitForArpRepeatPacket(LPVOIDmainClass)
{
pcap_t
*pAdaptHandle;
constchar*pDevName=strSelDeviceName.c_str();
charerrbuf[PCAP_ERRBUF_SIZE+1];
//打开网卡适配器
if((pAdaptHandle=pcap_open_live(pDevName,60,0,100,errbuf))==NULL)
{
MessageBox(NULL,
"无法打开适配器,可能与之不兼容!","wait",MB_OK);
return-1;
}
stringipWithMac;
char*filter="etherproto//arp";
bpf_programfcode;
intres;
unsigned
shortarp_op=0;
unsigned
chararp_sha[6];
unsigned
longarp_spa=0;
structpcap_pkthdr*header;
constu_char*pkt_data;
if(pcap_compile(pAdaptHandle,&fcode,filter,1,(unsignedlong)(0xFFFF0000))<0)
{
MessageBox(NULL,
"过滤条件语法错误!","wait",MB_OK);
return-1;
}
//setthefilter
if(pcap_setfilter(pAdaptHandle,&fcode)<0)
{
MessageBox(NULL,
"适配器与过滤条件不兼容!","wait",MB_OK);
return-1;
}
while(1)
{
if(!nThreadSignal)
{
break;
}
inti=0;
ipWithMac
="";
res
=pcap_next_ex(pAdaptHandle,&header,&pkt_data);
if(!res)
{
continue;
}
memcpy(
&arp_op,pkt_data+20,2);//包的操作类型
memcpy(arp_sha,pkt_data+22,6);//源MAC地址
memcpy(&arp_spa,pkt_data+28,4);//源IP地址
ipWithMac+=IpToStr(arp_spa);
for(intj=strlen(IpToStr(arp_spa));j<16;j++)
{
ipWithMac
+="";
}
ipWithMac
+="--*->";
ipWithMac
+=MacToStr(arp_sha);
for(i=6;i>0;i--)
{
if(arp_sha[i-1]!=bLocalMac[i-1])
{
break;
}
}
if(arp_op==htons(ARP_REPLY)&&i)
{
AfxGetApp()
->m_pMainWnd->SendMessage(WM_PACKET,WPARAM(&ipWithMac),0);//通知主线程更新界面
}
}
return0;
}

主线程消息处理

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->LRESULTCArpByWinpcapDlg::OnPacket(WPARAMwParam,LPARAMlParam)
{
string*transPack=(string*)wParam;
//处理捕获到的数据包
if(lParam==0)
{
m_Mac_list.AddString(transPack
->c_str());
m_count
="发现";
charbuffer[5];
itoa(m_Mac_list.GetCount(),buffer,
10);//将数量转化为进制字符串;
m_count+=buffer;
m_count
+="台活动主机";
}
elseif(lParam==1)
{
m_sending
="正在发送ARP请求包!";
}
elseif(lParam==2)
{
if(nThreadSignal)
{
m_sending
="全部ARP请求包发送完毕!";//判断是自行发送完毕还是用户终止的?
};
}
UpdateData(FALSE);
return0;
}

参考资料:《Winpcap网络开发库入门