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

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

作者: Phinecos(洞庭散人)  来源: 博客园  发布时间:2009-01-04 21:28  阅读:2124 次   原文链接   [收藏]  

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,  60 1 100 , 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  +   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);
            
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,  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 );     // 构造包
    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,  0 1 ); // 开始发送ARP请求包
    SendArpRequest(pDevGlobalHandle, bLocalMac);                                     // 对选中设备的所有绑定的IP网段进行ARP请求
    AfxGetApp() -> m_pMainWnd -> SendMessage(WM_PACKET,  0 2 ); // 全部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,  60 0 100 , 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  +   20 2 ); // 包的操作类型
        memcpy(arp_sha, pkt_data  +   22 6 ); // 源MAC地址
        memcpy( & arp_spa, pkt_data  +   28 4 ); // 源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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值