您的位置:首页 > 其它

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

2010-04-23 23:25 447 查看

基于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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: