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

ARP帧数据结构

#define BROADMAC        {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} //广播MAC
#define EH_TYPE            0x0806                            //ARP类型
#define ARP_HRD            0X0001                            //硬件类型:以太网接口类型为        
#define ARP_PRO            0x0800                            //协议类型:IP协议类型为X0800
#define ARP_HLN            0x06                            //硬件地址长度:MAC地址长度为B
#define ARP_PLN            0x04                            //协议地址长度:IP地址长度为B
#define ARP_REQUEST        0x0001                            //操作:ARP请求为
#define ARP_REPLY        0x0002                            //操作:ARP应答为
#define ARP_THA            {0,0,0,0,0,0}                    //目的MAC地址:ARP请求中该字段没有意义,设为;ARP响应中为接收方的MAC地址
#define ARP_PAD            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} //18字节的填充数据
#define SPECIAL            0x70707070                        //定义获得自己MAC地址的特殊源IP,.112.112.112
#define ETH_HRD_DEFAULT    {BROADMAC, {0,0,0,0,0,0}, htons(EH_TYPE)} //广播ARP包帧头
#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}
#define IPTOSBUFFERS 12
#define WM_PACKET    WM_USER + 105    //用户自定义消息

struct ethernet_head
{
// 物理帧帧头结构
    unsigned char dest_mac[6];                                    //目标主机MAC地址(6字节)
    unsigned char source_mac[6];                                //源端MAC地址(6字节)
    unsigned short eh_type;                                        //以太网类型(2字节)
};
struct arp_head
{
//ARP数据帧
    unsigned short hardware_type;                                //硬件类型:以太网接口类型为
    unsigned short protocol_type;                                //协议类型:IP协议类型为X0800
    unsigned char add_len;                                        //硬件地址长度:MAC地址长度为B
    unsigned char pro_len;                                        //协议地址长度:IP地址长度为B
    unsigned short option;                                        //操作:ARP请求为,ARP应答为

    unsigned 
char sour_addr[6];                                    //源MAC地址:发送方的MAC地址
    unsigned long sour_ip;                                        //源IP地址:发送方的IP地址
    unsigned char dest_addr[6];                                    //目的MAC地址:ARP请求中该字段没有意义;ARP响应中为接收方的MAC地址
    unsigned long dest_ip;                                        //目的IP地址:ARP请求中为请求解析的IP地址;ARP响应中为接收方的IP地址
    unsigned char padding[18];
};

struct arp_packet                                        //最终arp包结构
{//物理帧结构
    ethernet_head eth;                                    //以太网头部
    arp_head arp;                                        //arp数据包头部
};

获取本机的网络适配器

    int i = 1;
    
string strDev = "";
    m_Dev.AddString(
"经分析,本系统网络适配器列表如下:");
    pcap_if_t
* alldevs = 0
    pcap_if_t
* pDev = 0;
    pcap_addr_t
* pAdr = 0;
    
char errbuf[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(((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr);
                    
if(IpToStr(((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr)[0!= '0')
                    {
                        m_Dev_No 
= i;
                        UpdateData(FALSE);
//传递变量值去界面
                    }
                    strDev 
+= " & [";
                    strDev 
+= IpToStr(((struct sockaddr_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地址

unsigned char* BuildArpRequestPacket(unsigned char* source_mac, unsigned char* arp_sha, unsigned long chLocalIP, unsigned long arp_tpa, int PackSize)
{
//封装ARP请求包
    static arp_packet arpPackStru;
    
static const arp_packet arpDefaultPack= {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 (unsigned char *)&arpPackStru;
}
unsigned 
char* GetSelfMac(char* pDevName, unsigned long chLocalIP)
{
//获得本机MAC地址,pDevName为网卡名称,chLocalIP为本机IP地址
    pcap_t* pAdaptHandle;                                                
    
char errbuf[PCAP_ERRBUF_SIZE + 1]; 
    
//打开网卡适配器
    if((pAdaptHandle = pcap_open_live(pDevName, 601100, errbuf)) == NULL)
    {    
        MessageBox(NULL, 
"无法打开适配器,可能与之不兼容!""Note", MB_OK);
        
return NULL;
    }
    
struct pcap_pkthdr *header;//包头部
    const u_char *pkt_data;//包数据部
    int res;
    unsigned 
short arp_op;
    
static unsigned char arp_sha[6];
    unsigned 
long arp_spa = 0;
    unsigned 
long arp_tpa = 0;
    unsigned 
char source_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 + 202);//操作类型(请求或应答)
        memcpy(arp_sha, pkt_data + 226);//源MAC
        memcpy(&arp_spa, pkt_data + 284);//源IP    
        memcpy(&arp_tpa, pkt_data + 384);//目标IP    
        
        
if(arp_op == htons(ARP_REPLY) && arp_spa == chLocalIP && arp_tpa == SPECIAL)
        {
//是本机
            GetMacSignal = 1;
            pcap_close(pAdaptHandle);
            
return arp_sha;
        }
        Sleep(
100);//若不成功再等ms再发,让网卡歇歇
    }
    pcap_close(pAdaptHandle);
    
return arp_sha; 
}

发送ARP请求线程

void SendArpRequest(pcap_if_t* pDev, unsigned char* bLocalMac)
{
//发送ARP请求
    pcap_addr_t* pAdr = 0;
    unsigned 
long chLocalIp = 0;//存放本地ip地址
    unsigned long arp_tpa = 0;
    unsigned 
long snd_tpa = 0;
    unsigned 
long nlNetMask = 0;
    
int netsize = 0;
    
const char* pDevName = strSelDeviceName.c_str();
    pcap_t
* pAdaptHandle;
    
char errbuf[PCAP_ERRBUF_SIZE + 1];
    
//打开网卡适配器
    if((pAdaptHandle = pcap_open_live(pDev->name, 600100, errbuf)) == NULL)
    {    
        MessageBox(NULL, 
"无法打开适配器,可能与之不兼容!""Send", MB_OK);
        
return;
    }
    unsigned 
char* arp_packet_for_req;
    arp_packet_for_req 
= BuildArpRequestPacket(bLocalMac, bLocalMac, chLocalIp, chLocalIp, 60);    //构造包
    unsigned long ulOldMask=0;
    
for (pAdr = pDev->addresses; pAdr; pAdr = pAdr->next)
    {
        
if (!nThreadSignal)
        {
//判断线程是否应该中止
            break;
        }
        chLocalIp 
= ((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr;//得到本地ip
        if (!chLocalIp) 
        {
            
continue;
        }
        nlNetMask 
= ((struct sockaddr_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 (int i=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请求包
        }
    }
}
UINT StartArpScan(LPVOID mainClass)
{
//发送ARP请求线程
    AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, 01);//开始发送ARP请求包
    SendArpRequest(pDevGlobalHandle, bLocalMac);                                    //对选中设备的所有绑定的IP网段进行ARP请求
    AfxGetApp()->m_pMainWnd->SendMessage(WM_PACKET, 02);//全部ARP请求包发送完毕
    return 0;
}

接收ARP响应线程

UINT WaitForArpRepeatPacket(LPVOID mainClass)
{        
    pcap_t
* pAdaptHandle;                                                        
    
const char* pDevName = strSelDeviceName.c_str();
    
char errbuf[PCAP_ERRBUF_SIZE + 1]; 
    
//打开网卡适配器
    if((pAdaptHandle = pcap_open_live(pDevName, 600100, errbuf)) == NULL)
    {    
        MessageBox(NULL, 
"无法打开适配器,可能与之不兼容!""wait", MB_OK);
        
return -1;
    }
    
string ipWithMac;
    
char* filter = "ether proto\\arp";
    bpf_program fcode;
    
int res;
    unsigned 
short arp_op = 0;
    unsigned 
char arp_sha [6];
    unsigned 
long arp_spa = 0;
    
struct pcap_pkthdr *header;
    
const u_char *pkt_data;
    
if (pcap_compile(pAdaptHandle, &fcode, filter, 1, (unsigned long)(0xFFFF0000)) < 0)
    {
        MessageBox(NULL,
"过滤条件语法错误!""wait", MB_OK);
        
return -1;
    }
    
//set the filter
    if (pcap_setfilter(pAdaptHandle, &fcode) < 0)
    {
        MessageBox(NULL,
"适配器与过滤条件不兼容!""wait", MB_OK);
        
return -1;
    }
    
while(1)
    {
        
if (!nThreadSignal) 
        {
            
break;
        }
        
int i = 0;
        ipWithMac 
= "";
        res 
= pcap_next_ex(pAdaptHandle, &header, &pkt_data);
        
if (!res)
        {
            
continue;
        }
        memcpy(
&arp_op, pkt_data + 202);//包的操作类型
        memcpy(arp_sha, pkt_data + 226);//源MAC地址
        memcpy(&arp_spa, pkt_data + 284);//源IP地址
        ipWithMac += IpToStr(arp_spa);
        
for (int j = 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);//通知主线程更新界面
        }
    }                        
    
return 0;
}

  主线程消息处理

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

  

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

posted on 2009-01-04 21:28  Phinecos(洞庭散人)  阅读(10600)  评论(7编辑  收藏  举报

导航