ARP帧数据结构
 

  1. #define BROADMAC        {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} //广播MAC  
  2. #define EH_TYPE            0x0806                            //ARP类型  
  3. #define ARP_HRD            0X0001                            //硬件类型:以太网接口类型为          
  4. #define ARP_PRO            0x0800                            //协议类型:IP协议类型为X0800  
  5. #define ARP_HLN            0x06                            //硬件地址长度:MAC地址长度为B  
  6. #define ARP_PLN            0x04                            //协议地址长度:IP地址长度为B  
  7. #define ARP_REQUEST        0x0001                            //操作:ARP请求为  
  8. #define ARP_REPLY        0x0002                            //操作:ARP应答为  
  9. #define ARP_THA            {0,0,0,0,0,0}                    //目的MAC地址:ARP请求中该字段没有意义,设为;ARP响应中为接收方的MAC地址  
  10. #define ARP_PAD            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} //18字节的填充数据  
  11. #define SPECIAL            0x70707070                        //定义获得自己MAC地址的特殊源IP,.112.112.112  
  12. #define ETH_HRD_DEFAULT    {BROADMAC, {0,0,0,0,0,0}, htons(EH_TYPE)} //广播ARP包帧头  
  13. #define ARP_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}  
  14. #define IPTOSBUFFERS 12  
  15. #define WM_PACKET    WM_USER + 105    //用户自定义消息  
  16.  
  17. struct ethernet_head  
  18. {// 物理帧帧头结构  
  19.     unsigned char dest_mac[6];                                    //目标主机MAC地址(6字节)  
  20.     unsigned char source_mac[6];                                //源端MAC地址(6字节)  
  21.     unsigned short eh_type;                                        //以太网类型(2字节)  
  22. };  
  23. struct arp_head  
  24. {//ARP数据帧  
  25.     unsigned short hardware_type;                                //硬件类型:以太网接口类型为  
  26.     unsigned short protocol_type;                                //协议类型:IP协议类型为X0800  
  27.     unsigned char add_len;                                        //硬件地址长度:MAC地址长度为B  
  28.     unsigned char pro_len;                                        //协议地址长度:IP地址长度为B  
  29.     unsigned short option;                                        //操作:ARP请求为,ARP应答为  
  30.  
  31.     unsigned char sour_addr[6];                                    //源MAC地址:发送方的MAC地址  
  32.     unsigned long sour_ip;                                        //源IP地址:发送方的IP地址  
  33.     unsigned char dest_addr[6];                                    //目的MAC地址:ARP请求中该字段没有意义;ARP响应中为接收方的MAC地址  
  34.     unsigned long dest_ip;                                        //目的IP地址:ARP请求中为请求解析的IP地址;ARP响应中为接收方的IP地址  
  35.     unsigned char padding[18];  
  36. };  
  37.  
  38. struct arp_packet                                        //最终arp包结构  
  39. {//物理帧结构  
  40.     ethernet_head eth;                                    //以太网头部  
  41.     arp_head arp;                                        //arp数据包头部  
  42. }; 

获取本机的网络适配器

 

  1. int i = 1;  
  2. string strDev = "";  
  3. m_Dev.AddString("经分析,本系统网络适配器列表如下:");  
  4. pcap_if_t* alldevs = 0;   
  5. pcap_if_t* pDev = 0;  
  6. pcap_addr_t* pAdr = 0;  
  7. char errbuf[PCAP_ERRBUF_SIZE+1];   
  8. if (pcap_findalldevs(&alldevs, errbuf) == -1)  
  9. {// 获得设备列表  
  10.     MessageBox(errbuf, NULL, MB_OK | MB_ICONINFORMATION);// 若没有设备则弹出警告  
  11.     exit(1);  
  12. }   
  13. for(pDev = alldevs; pDev; pDev = pDev->next)  
  14. {// 遍历所有成员  
  15.     if (pDev->description)  
  16.     {  
  17.         strDev = char(i + 48);  
  18.         strDev += ". ";  
  19.         strDev += DelSpace(pDev->description);//去掉网卡描述过多的空格  
  20.         pAdr = pDev->addresses;//IP地址  
  21.         if (pAdr!=NULL)  
  22.         {          
  23.             if (pAdr->addr->sa_family == AF_INET)  
  24.             {//pAdr->addr是否IP地址类型  
  25.                 strDev += " -> ";  
  26.                 strDev += IpToStr(((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr);  
  27.                 if(IpToStr(((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr)[0] != '0')  
  28.                 {  
  29.                     m_Dev_No = i;  
  30.                     UpdateData(FALSE);//传递变量值去界面  
  31.                 }  
  32.                 strDev += " & [";  
  33.                 strDev += IpToStr(((struct sockaddr_in *)pAdr->netmask)->sin_addr.s_addr);//子网掩码  
  34.                 strDev += "]";  
  35.                 GetDlgItem(IDC_GET_MAC)->EnableWindow(TRUE);//若网卡有IP地址,则使抓包按钮可用  
  36.             }  
  37.         }  
  38.         m_Dev.InsertString(i++, strDev.c_str());  
  39.     }  
  40. }  
  41. pcap_freealldevs(alldevs);//不再需要网络适配器列表, 释放  

获取本机MAC地址

 

  1. unsigned char* BuildArpRequestPacket(unsigned char* source_mac, unsigned char* arp_sha, unsigned long chLocalIP, unsigned long arp_tpa, int PackSize)  
  2. {//封装ARP请求包  
  3.     static arp_packet arpPackStru;  
  4.     static const arp_packet arpDefaultPack= {ETH_HRD_DEFAULT,ARP_HRD_DEFAULT};  
  5.     memcpy(&arpPackStru,&arpDefaultPack,sizeof(arpDefaultPack));  
  6.     //填充源MAC地址  
  7.     memcpy(arpPackStru.eth.source_mac,source_mac,6);//源MAC  
  8.     memcpy(arpPackStru.arp.sour_addr,arp_sha,6);//源MAC  
  9.     arpPackStru.arp.sour_ip=chLocalIP;//源IP地址      
  10.     arpPackStru.arp.dest_ip=arp_tpa;//目的IP地址  
  11.     return (unsigned char *)&arpPackStru;  
  12. }  
  13. unsigned char* GetSelfMac(char* pDevName, unsigned long chLocalIP)  
  14. {//获得本机MAC地址,pDevName为网卡名称,chLocalIP为本机IP地址  
  15.     pcap_t* pAdaptHandle;                                                  
  16.     char errbuf[PCAP_ERRBUF_SIZE + 1];   
  17.     //打开网卡适配器  
  18.     if((pAdaptHandle = pcap_open_live(pDevName, 60, 1, 100, errbuf)) == NULL)  
  19.     {      
  20.         MessageBox(NULL, "无法打开适配器,可能与之不兼容!""Note", MB_OK);  
  21.         return NULL;  
  22.     }  
  23.     struct pcap_pkthdr *header;//包头部  
  24.     const u_char *pkt_data;//包数据部  
  25.     int res;  
  26.     unsigned short arp_op;  
  27.     static unsigned char arp_sha[6];  
  28.     unsigned long arp_spa = 0;  
  29.     unsigned long arp_tpa = 0;  
  30.     unsigned char source_mac[6] = {0,0,0,0,0,0};  
  31.     unsigned char* arp_packet_for_self;  
  32.     arp_packet_for_self = BuildArpRequestPacket(source_mac, source_mac, SPECIAL, chLocalIP, 60);//把自己作为目的,构建一个广播ARP请求包,伪造请求来自.112.112.112  
  33.     while(!GetMacSignal)  
  34.     {  
  35.         pcap_sendpacket(pAdaptHandle, arp_packet_for_self, 60);//发送ARP请求包  
  36.         Sleep(10);                                          
  37.         res = pcap_next_ex(pAdaptHandle, &header, &pkt_data);  
  38.         if(res == 0)  
  39.         {  
  40.             continue;  
  41.         }  
  42.         //物理帧头部占字节,然后是硬件类型,上层协议类型,硬件地址长度,IP地址长度,这四个占去字节,具体参看ARP帧的数据结构  
  43.         memcpy(&arp_op, pkt_data + 20, 2);//操作类型(请求或应答)  
  44.         memcpy(arp_sha, pkt_data + 22, 6);//源MAC  
  45.         memcpy(&arp_spa, pkt_data + 28, 4);//源IP      
  46.         memcpy(&arp_tpa, pkt_data + 38, 4);//目标IP      
  47.           
  48.         if(arp_op == htons(ARP_REPLY) && arp_spa == chLocalIP && arp_tpa == SPECIAL)  
  49.         {//是本机  
  50.             GetMacSignal = 1;  
  51.             pcap_close(pAdaptHandle);  
  52.             return arp_sha;  
  53.         }  
  54.         Sleep(100);//若不成功再等ms再发,让网卡歇歇  
  55.     }  
  56.     pcap_close(pAdaptHandle);  
  57.     return arp_sha;   

发送ARP请求线程

 

  1. void SendArpRequest(pcap_if_t* pDev, unsigned char* bLocalMac)  
  2. {//发送ARP请求  
  3.     pcap_addr_t* pAdr = 0;  
  4.     unsigned long chLocalIp = 0;//存放本地ip地址  
  5.     unsigned long arp_tpa = 0;  
  6.     unsigned long snd_tpa = 0;  
  7.     unsigned long nlNetMask = 0;  
  8.     int netsize = 0;  
  9.     const char* pDevName = strSelDeviceName.c_str();  
  10.     pcap_t* pAdaptHandle;  
  11.     char errbuf[PCAP_ERRBUF_SIZE + 1];  
  12.     //打开网卡适配器  
  13.     if((pAdaptHandle = pcap_open_live(pDev->name, 60, 0, 100, errbuf)) == NULL)  
  14.     {      
  15.         MessageBox(NULL, "无法打开适配器,可能与之不兼容!""Send", MB_OK);  
  16.         return;  
  17.     }  
  18.     unsigned char* arp_packet_for_req;  
  19.     arp_packet_for_req = BuildArpRequestPacket(bLocalMac, bLocalMac, chLocalIp, chLocalIp, 60);    //构造包  
  20.     unsigned long ulOldMask=0;  
  21.     for (pAdr = pDev->addresses; pAdr; pAdr = pAdr->next)  
  22.     {  
  23.         if (!nThreadSignal)  
  24.         {//判断线程是否应该中止  
  25.             break;  
  26.         }  
  27.         chLocalIp = ((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr;//得到本地ip  
  28.         if (!chLocalIp)   
  29.         {  
  30.             continue;  
  31.         }  
  32.         nlNetMask = ((struct sockaddr_in *)(pAdr->netmask))->sin_addr.S_un.S_addr;//得到子网掩码  
  33.         if(ulOldMask==nlNetMask)  
  34.         {  
  35.             continue;  
  36.         }  
  37.         ulOldMask=nlNetMask;  
  38.         netsize = ~ntohl(nlNetMask);//子网大小  
  39.         arp_tpa = ntohl(chLocalIp & nlNetMask);//IP地址  
  40.         for (int i=0; i < netsize; i++)  
  41.         {  
  42.             if (!nThreadSignal)   
  43.             {  
  44.                 break;  
  45.             }  
  46.             arp_tpa++;  
  47.             snd_tpa = htonl(arp_tpa);  
  48.             memcpy(arp_packet_for_req + 38, &snd_tpa, 4);//目的IP在子网范围内按序增长      
  49.             pcap_sendpacket(pAdaptHandle, arp_packet_for_req, 60);//发送ARP请求包  
  50.             Sleep(5);//休息一下再发ARP请求包  
  51.         }  
  52.     }  
  53. }  
  54. UINT StartArpScan(LPVOID mainClass)  
  55. {//发送ARP请求线程  
  56.     AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, 0, 1);//开始发送ARP请求包  
  57.     SendArpRequest(pDevGlobalHandle, bLocalMac);                                    //对选中设备的所有绑定的IP网段进行ARP请求  
  58.     AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, 0, 2);//全部ARP请求包发送完毕  
  59.     return 0;  

接收ARP响应线程

 

  1. UINT WaitForArpRepeatPacket(LPVOID mainClass)  
  2. {          
  3.     pcap_t* pAdaptHandle;                                                          
  4.     const char* pDevName = strSelDeviceName.c_str();  
  5.     char errbuf[PCAP_ERRBUF_SIZE + 1];   
  6.     //打开网卡适配器  
  7.     if((pAdaptHandle = pcap_open_live(pDevName, 60, 0, 100, errbuf)) == NULL)  
  8.     {      
  9.         MessageBox(NULL, "无法打开适配器,可能与之不兼容!""wait", MB_OK);  
  10.         return -1;  
  11.     }  
  12.     string ipWithMac;  
  13.     char* filter = "ether proto\\arp";  
  14.     bpf_program fcode;  
  15.     int res;  
  16.     unsigned short arp_op = 0;  
  17.     unsigned char arp_sha [6];  
  18.     unsigned long arp_spa = 0;  
  19.     struct pcap_pkthdr *header;  
  20.     const u_char *pkt_data;  
  21.     if (pcap_compile(pAdaptHandle, &fcode, filter, 1, (unsigned long)(0xFFFF0000)) < 0)  
  22.     {  
  23.         MessageBox(NULL,"过滤条件语法错误!""wait", MB_OK);  
  24.         return -1;  
  25.     }  
  26.     //set the filter  
  27.     if (pcap_setfilter(pAdaptHandle, &fcode) < 0)  
  28.     {  
  29.         MessageBox(NULL,"适配器与过滤条件不兼容!""wait", MB_OK);  
  30.         return -1;  
  31.     }  
  32.     while(1)  
  33.     {  
  34.         if (!nThreadSignal)   
  35.         {  
  36.             break;  
  37.         }  
  38.         int i = 0;  
  39.         ipWithMac = "";  
  40.         res = pcap_next_ex(pAdaptHandle, &header, &pkt_data);  
  41.         if (!res)  
  42.         {  
  43.             continue;  
  44.         }  
  45.         memcpy(&arp_op, pkt_data + 20, 2);//包的操作类型  
  46.         memcpy(arp_sha, pkt_data + 22, 6);//源MAC地址  
  47.         memcpy(&arp_spa, pkt_data + 28, 4);//源IP地址  
  48.         ipWithMac += IpToStr(arp_spa);  
  49.         for (int j = strlen(IpToStr(arp_spa)); j < 16; j++)  
  50.         {  
  51.             ipWithMac += " ";  
  52.         }  
  53.         ipWithMac += "  --*->   ";  
  54.         ipWithMac += MacToStr(arp_sha);  
  55.         for (i = 6; i > 0; i--)  
  56.         {                                                  
  57.             if (arp_sha[i - 1] != bLocalMac[i - 1])  
  58.             {  
  59.                 break;  
  60.             }  
  61.         }  
  62.         if(arp_op == htons(ARP_REPLY) && i)  
  63.         {  
  64.             AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, WPARAM(&ipWithMac), 0);//通知主线程更新界面  
  65.         }  
  66.     }                          
  67.     return 0;  

  主线程消息处理

 

  1. LRESULT CArpByWinpcapDlg::OnPacket(WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     string* transPack = (string*)wParam;  
  4.     //处理捕获到的数据包  
  5.     if (lParam == 0)  
  6.     {  
  7.         m_Mac_list.AddString(transPack->c_str());  
  8.         m_count = "发现 ";  
  9.         char buffer[5];  
  10.         itoa(m_Mac_list.GetCount(), buffer, 10);    //将数量转化为进制字符串;  
  11.         m_count += buffer;  
  12.         m_count += "  台活动主机";  
  13.     }  
  14.     else if (lParam == 1)  
  15.     {  
  16.         m_sending = "正在发送ARP请求包!";  
  17.     }  
  18.     else if (lParam == 2)  
  19.     {  
  20.         if (nThreadSignal)  
  21.         {  
  22.             m_sending = "全部ARP请求包发送完毕!";    //判断是自行发送完毕还是用户终止的?  
  23.         };  
  24.     }  
  25.     UpdateData(FALSE);  
  26.     return 0;  

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