apa

时间:2024.5.4

第一篇 手把手教你玩转ARP包

目录:

一. 关于ARP协议的基础知识

1. ARP的工作原理

2. ARP包的格式

作者:

CSDN VC/MFC 网络编程 PiggyXP ^_^

一. 关于ARP协议的基础知识

1.ARP的工作原理

本来我不想在此重复那些遍地都是的关于ARP的基本常识,但是为了保持文章的完整性以及照顾初学者,我就再啰嗦一些文字吧,资深读者可以直接跳过此节。

我们都知道以太网设备比如网卡都有自己全球唯一的MAC地址,它们是以MAC地址来传输以太网数据包的,但是它们却识别不了我们IP包中的IP地址,所以我们在以太网中进行IP通信的时候就需要一个协议来建立IP地址与MAC地址的对应关系,以使IP数据包能发到一个确定的地方去。这就是ARP(Address Resolution Protocol,地址解析协议)。

讲到此处,我们可以在命令行窗口中,输入

arp –a

来看一下效果,类似于这样的条目

210.118.45.100 00-0b-5f-e6-c5-d7 dynamic

就是我们电脑里存储的关于IP地址与MAC地址的对应关系,dynamic表示是临时存储在ARP缓存中的条目,过一段时间就会超时被删除(xp/2003系统是2分钟)。

这样一来,比如我们的电脑要和一台机器比如210.118.45.1通信的时候,它会首先去检查arp缓存,查找是否有对应的arp条目,如果没有,它就会给这个以太网络发ARP请求包广播询问210.118.45.1的对应MAC地址,当然,网络中每台电脑都会收到这个请求包,但是它们发现210.118.45.1并非自己,就不会做出相应,而210.118.45.1就会给我们的电脑回复一个ARP应答包,告诉我们它的MAC地址是xx-xx-xx-xx-xx-xx,于是我们电脑的ARP缓存就会相应刷新,多了这么一条:

210.118.45.1 xx-xx-xx-xx-xx-xx dynamic

为什么要有这么一个ARP缓存呢,试想一下如果没有缓存,我们每发一个IP包都要发个广播查询地址,岂不是又浪费带宽又浪费资源?

而且我们的网络设备是无法识别ARP包的真伪的,如果我们按照ARP的格式来发送数据包,只要信息有效计算机就会根据包中的内容做相应的反应.

试想一下,如果我们按照ARP响应包的相应的内容来刷新自己的ARP缓存中的列表,嘿嘿,那我们岂不是可以根据这点在没有安全防范的网络中玩些ARP包的小把戏了?在后面的文章里我就手把手来教你们如何填充发送ARP包,不过先别急,我们再继续学点基础知识^_^

2.ARP包的格式

apa

=======================================================================

3.ARP包的填充 1) 请求包的填充:

比如我们的电脑MAC地址为 aa-aa-aa-aa-aa-aa,IP为 192.168.0.1 我们想要查询 192.168.0.99的MAC地址,应该怎么来做呢?

apa

apa

unsigned short unsigned short unsigned char unsigned char unsigned short unsigned char unsigned long unsigned char unsigned long unsigned char HW_Type; Prot_Type; /* hardware address */ /* protocol address */ HW_Addr_Len; Prot_Addr_Len; Opcode; /* length of hardware address */ /* length of protocol address */ /* ARP/RARP */ Send_HW_Addr[6]; /* sender hardware address */ Send_Prot_Addr; /* sender protocol address */ Targ_HW_Addr[6]; /* target hardware address */ Targ_Prot_Addr; /* target protocol address */ padding[18];

} ARPFRAME, *PARPFRAME;

// ARP Packet = DLC header + ARP Frame

typedef struct tagARPPacket

{

这些结构体一定能看懂吧,在程序中就是对号入座就好了

................. DLCHEADER ARPFRAME dlcHeader; arpFrame; } ARPPACKET, *PARPPACKET;

================================================================== . 填充数据包

下面我举个填充包头的例子,我首先定义个了一个转换字符的函数,如下

/****************************************************************************

* Name & Params::

* formatStrToMAC

* (

* const LPSTR lpHWAddrStr : 用户输入的MAC地址字符串

* unsigned char *HWAddr : 返回的MAC地址字符串(赋给数据包结构体) * )

* Purpose:

* 将用户输入的MAC地址字符转成数据包结构体需要的格式

****************************************************************************/

void formatStrToMAC(const LPSTR lpHWAddrStr, unsigned char *HWAddr) {

unsigned int i, index = 0, value, temp;

unsigned char c;

_strlwr(lpHWAddrStr); // 转换成小写

for (i = 0; i < strlen(lpHWAddrStr); i++)

{

c = *(lpHWAddrStr + i);

if (( c>='0' && c<='9' ) || ( c>='a' && c<='f' ))

{

if (c>='0' && c<='9') temp = c - '0'; // 数字

if (c>='a' && c<='f') temp = c - 'a' + 0xa; // 字母

if ( (index % 2) == 1 )

{

value = value*0x10 + temp;

HWAddr[index/2] = value;

}

else value = temp;

index++;

}

if (index == 12) break;

}

}

// 开始填充各个字段

ARPPACKET ARPPacket; // 定义ARPPACKET结构体变量

memset(&ARPPacket, 0, sizeof(ARPPACKET)); // 数据包初始化

formatStrToMAC(“DLC源MAC字符串”,ARPPacket.dlcHeader.SrcMAC); // DLC帧头 formatStrToMAC(“DLC目的MAC字符串”,ARPPacket.dlcHeader.DesMAC);

formatStrToMAC(“ARP源MAC字符串”,ARPPacket.arpFrame.Send_HW_Addr); // 源MAC

ARPPacket.arpFrame.Send_Prot_Addr = inet_addr(srcIP); // 源IP

formatStrToMAC(“ARP目的MAC字符串”,ARPPacket.arpFrame.Targ_HW_Addr); // 目的MAC

ARPPacket.arpFrame.Targ_Prot_Addr = inet_addr(desIP); // 目的IP

ARPPacket.arpFrame.Opcode = htons((unsigned short)arpType); // arp包类型

// 自动填充的常量

ARPPacket.dlcHeader.Ethertype = htons((unsigned short)0x0806); // DLC Header的以太网类型

ARPPacket.arpFrame.HW_Type = htons((unsigned short)1); // 硬件类型

ARPPacket.arpFrame.Prot_Type = htons((unsigned short)0x0800); // 上层协议类型 ARPPacket.arpFrame.HW_Addr_Len = (unsigned char)6; // MAC地址长度 ARPPacket.arpFrame.Prot_Addr_Len = (unsigned char)4; // IP地址长度

That’s all ! ^_^

填充完毕之后,我们需要做的就是把我们的ARPPACKET结构体发送出去

2.发送ARP数据包:

我们发送ARP包就要用到winpcap的api了,具体步骤及函数是这样的,为了简单易懂,我把错误处理的地方都去掉了,详见代码

/**********************************************************************

* Name & Params::

* SendARPPacket()

* Purpose:

* 发送ARP数据包

* Remarks:

* 用的是winpcap的api函数

***********************************************************************/

void SendARPPacket()

{

char *AdapterDeviceName =GetCurAdapterName(); // 首先获得获得网卡名字

lpAdapter = PacketOpenAdapter(AdapterDeviceName); // 根据网卡名字打开网卡

lpPacket = PacketAllocatePacket(); // 给PACKET结构指针分配内存

PacketInitPacket(lpPacket, &ARPPacket, sizeof(ARPPacket)); //初始化PACKET结构指针 // 其中的ARPPacket就是我们先前填充的ARP包

PacketSetNumWrites(lpAdapter, 1); // 每次只发送一个包

PacketSendPacket(lpAdapter, lpPacket, true) // Send !!!!! ^_^

PacketFreePacket(lpPacket); // 释放资源

PacketCloseAdapter(lpAdapter);

}

呵呵,至此,关于ARP包最关键的部分就讲完了,你现在就可以来随心所欲的发送自己的ARP包了

既然作为一篇“科普文章”,接下来我再讲一讲与整个项目有关的附加步骤以及说明

三.附加步骤以及说明

1. 如何在VC中使用winpcap驱动

虽然winpcap开发包使用起来非常简便,但是前期准备工作还是要费一番功夫的,缺一不可。^_^

首先就是要安装它的驱动程序了,可以到它的主页下载,更新很快的

http://winpcap.polito.it/install/default.htm

下载WinPcap auto-installer (driver +DLLs),直接安装就好了,或者我提供的代码包里面也有。

希望以后用winpcap作开发的朋友,还需要下载 Developer's pack,解压即可。

然后,需要设置我们工程的附加包含目录为我们下载Developer's pack开发包的Inclulde目录,连接器的附加依赖库设置为Developer's pack的lib目录。

当然,因为我们的工作比较简单,就是借用winpcap发送数据包而已,所以只用从 winpcap开发包的include文件夹中,拷贝Packet32.h,到我们的工程来,并且包含它就可 以,但是要注意,Packet32.h本身还要包含一个Devioctl.h,也要一并拷贝进来,当然还有运 行库Packet.lib,一共就是需要拷贝3个文件了,如果加入库不用我多说了吧,在工程里面设 置,或者是在需要它的地方加入 #pragma comment(lib, "Packet.lib")了。

整个项目其实可以分为四个部分,填充数据包、发送数据包、枚举系统网卡列表和 相关信息以及枚举系统ARP缓存列表,下面我再讲一下如何获得系统的网卡以及ARP列 表,这两个部分都要用到IP Helper的api,所以要包含<Iphlpapi.h>以及库文件Iphlpapi.lib, 其实都是很简单的,只用寥寥几行就OK了

2. 枚举系统网卡以及信息

最好是先定义关于网卡信息的一个结构体,这样显得结构比较清晰

// 网卡信息

typedef struct tagAdapterInfo

{

char szDeviceName[128]; // 名字

char szIPAddrStr[16]; // IP

char szHWAddrStr[18]; // MAC

DWORD dwIndex; // 编号

}INFO_ADAPTER, *PINFO_ADAPTER;

/*********************************************************************

* Name & Params::

* AddAdapInfoToList

* (

* CListCtrl& list : CARPPlayerDlg传入的list句柄

* )

* Purpose:

* 获得系统的网卡信息,并将其添加到list控件中

* Remarks:

* 获得网卡IP及MAC用到了IpHelper api GetAdaptersInfo

******************************************************************/

void AddAdapInfoToList(CListCtrl& list)

{

char tempChar;

ULONG uListSize=1;

PIP_ADAPTER_INFO pAdapter; // 定义PIP_ADAPTER_INFO结构存储网卡信息

int nAdapterIndex = 0;

DWORD dwRet = GetAdaptersInfo((PIP_ADAPTER_INFO)&tempChar, &uListSize);//关键函数

if (dwRet == ERROR_BUFFER_OVERFLOW)

{

PIP_ADAPTER_INFO pAdapterListBuffer = (PIP_ADAPTER_INFO)new(char[uListSize]); dwRet = GetAdaptersInfo(pAdapterListBuffer, &uListSize);

if (dwRet == ERROR_SUCCESS)

{

pAdapter = pAdapterListBuffer;

while (pAdapter) // 枚举网卡然后将相关条目添加到List中 {

// 网卡名字

CString strTemp = pAdapter->AdapterName;

strTemp = "//Device//NPF_" + strTemp; // 加上前缀

list.InsertItem(nAdapterIndex,strTemp);

strcpy(AdapterList[nAdapterIndex].szDeviceName,strTemp);

// IP

strcpy(AdapterList[nAdapterIndex].szIPAddrStr,

pAdapter->IpAddressList.IpAddress.String );

list.SetItemText(nAdapterIndex,1,AdapterList[nAdapterIndex].szIPAddrStr);

// MAC

formatMACToStr( AdapterList[nAdapterIndex].szHWAddrStr, pAdapter->Address ); list.SetItemText(nAdapterIndex,2,AdapterLis[nAdapterIndex].szHWAddrStr); // 网卡编号

AdapterList[nAdapterIndex].dwIndex = pAdapter->Index;

pAdapter = pAdapter->Next;

nAdapterIndex ++;

}

delete pAdapterListBuffer;

}

}

}

2)获取ARP条目列表

// ARP条目信息

typedef struct tagARPInfo

{

char szIPAddrStr[16]; // IP

char szHWAddrStr[18]; // MAC

DWORD dwType; // 类型

}INFO_ARP, *PINFO_ARP;

/**********************************************************************

* Name & Params::

* AddARPInfoToList

* (

* CListCtrl& list : CARPPlayerDlg传入的list句柄

* const short nAdapterIndex : 用户选中的网卡编号

* )

* Purpose:

* 读入系统的ARP缓存列表,.并添加到对话框中

* Remarks:

* 用到了IpHelper api GetIpNetTable

* 而且用到了WinSock的api,所以要包含<WinSock2.h>

*****************************************************************/

void AddARPInfoToList(CListCtrl& list,const short nAdapterIndex)

{

char tempChar;

DWORD dwListSize = 1;

DWORD dwRet;

in_addr inaddr;

list.DeleteAllItems();

dwRet = GetIpNetTable((PMIB_IPNETTABLE)&tempChar, &dwListSize, TRUE); // 关键函数

if (dwRet == ERROR_INSUFFICIENT_BUFFER)

{

PMIB_IPNETTABLE pIpNetTable = (PMIB_IPNETTABLE)new(char[dwListSize]); dwRet = GetIpNetTable(pIpNetTable, &dwListSize, TRUE);

if (dwRet == ERROR_SUCCESS)

{

for (int i=0; i<(int)pIpNetTable->dwNumEntries; i++)

{

// IP

inaddr.S_un.S_addr = pIpNetTable->table[i].dwAddr;

strcpy( ARPList[i].szIPAddrStr, inet_ntoa(inaddr) );

// MAC

formatMACToStr( ARPList[i].szHWAddrStr, pIpNetTable->table[i].bPhysAddr ); // Type

ARPList[i].dwType = pIpNetTable->table[i].dwType;

if (AdapterList[nAdapterIndex].dwIndex !=

pIpNetTable->table[i].dwIndex) continue;

list.InsertItem(i,ARPList[i].szIPAddrStr);

list.SetItemText(i,1,ARPList[i].szHWAddrStr);

switch(ARPList[i].dwType) { // 根据type的值来转换成字符显示

case 3:

list.SetItemText(i,2,"Dynamic");

break;

case 4:

list.SetItemText(i,2,"Static");

break;

case 1:

list.SetItemText(i,2,"Invalid");

default:

list.SetItemText(i,2,"Other");

}

}

}

delete pIpNetTable;

}

}

这样一来,我们基本上大功告成了,其他还有一些东西在这里就不讲了,大家可以下载我的代码看看就好了。

下面我们来用ARP包玩一些小把戏 ^_^。

apa

呵呵类似的伎俩还有很多,不过只停留在这点东西上也没什么意思,还是看看稍微高深一点的吧^_^

2. ARP欺骗

因为在以太网里,网络设备就是靠MAC信息来识别的计算机的,比如A电脑知道MAC地址为

22-22-22-22-22-22的电脑是B,而如果我给A发送一个ARP响应包,告诉它我的MAC是

22-22-22-22-22-22的话,A同样会认为我的计算机是B了,那么好,我们设想有这么一个环境,

A的防火墙只对IP为192.168.0.2 MAC为 22-22-22-22-22-22的B有信任关系,而且A打开

了21端口提供FTP服务,正常情况下因为防火墙的缘故我们的计算机是连不到A的,

于是我们想办法让B down掉,或者在它关机的时候,我们把我们的IP改成B的192.168.0.2,然后给A发送一个ARP回应包,告诉A更新一下ARP缓存列表,192.168.0.2的IP映射到我们的 MAC地址上来,于是,奇迹出现了,我们可以连到A的FTP上了,防火墙失效了^_^

不过这个办法只能在同网段内生效,如果我们和A不在一个网段内,那就要复杂的多了,还要

配合ICMP的重定向来控制报文的路由,这个我准备在以后阐述ICMP包的时候详细讲解,就不再此多说了。

3. 基于ARP欺骗的监听原理

监听的技术有很多了,不过我们常用的sniffer工具只能在基于hub的网络中起作用,碰到哪

怕是交换机都无能为力了,这个时候我们的ARP欺骗技术就派上用场了。

还是假设有三台主机A,B,还有我们的主机,位于同一个交换式局域网中

A与B正在通信,如果我们想要刺探A――>B通信的内容,于是我们就可以给A发送一个伪造

的ARP回应包,告诉A,B的IP对应的MAC条目为我们的MAC地址,于是,A也就会相应的刷新自己的ARP缓存,将发给B的数据,源源不断的发送到我们的主机上来,这样我就可以对接收到的数据包进行分析就好了,达到了监听的目的。当然,因为动态ARP缓存是动态的,有超时时间的,所以我们必须每隔一段时间就给A发送一个ARP回应包

虽然我们这样达到了目的,但是A到B的通信却被停止了,为了不让B发现,我们还要对每次

接收到的数据包进行转发,全部都转发给B,这样就天衣无缝了^_^

同样的,如果我们还想监听B ? A的数据包,一样给B发一个ARP回应包,告诉B,A的IP

对应的MAC是我们的主机MAC,于是B到A的数据包也源源不断的发到我们的主机上来了,当然我们也是一样要对这些数据包进行转发,如图:

A <------> 我们的主机 <------> B

一切都无误的话,A和B的通信内容就这样不知不觉的被我们监听到了^_^

具体的代码实现由于篇幅的关系我就不放在这里讲了,如果需要我就专门另写篇文章附上完整代码吧

更多相关推荐:
fangle supplier change application

DearsupplierShanghaifangleautopartscoltdDirectMaterialSuppliers尊敬的上海方科汽车部件有限公司的直接材料供应商Thisletterisaremind...

免责声明范本

免责声明本人于时间受聘于单位为了避免权属纠纷特做如下说明本人证书只负责该单位的升级资质和年检不用于工程施工与招投标如使用本人证书参与工程而引起的纠纷和造成的一切后果其责任概由单位承担与本人无关特此声明声明人身份...

手机APP测试流程规范

手机APP测试流程规范一、流程图测试周期测试周期一般为两周(10个工作日),根据项目情况以及版本质量可适当缩短或延长测试时间。正式测试前先向主管确认项目排期。1.测试资源测试任务开始前,检查各项测试资源。1.产…

手机app测试方法

1APP测试基本流程11流程图仍然为测试环境12测试周期测试周期可按项目的开发周期来确定测试时间一般测试时间为两三周即15个工作日根据项目情况以及版本质量可适当缩短或延长测试时间正式测试前先向主管确认项目排期1...

App测试流程及测试点(个人整理版)

1APP测试基本流程11流程图仍然为测试环境15个工作日根据项目情况以及版本质量可适当缩短或延长测试时间正式测试前先向主管确认项目排期13测试资源测试任务开始前检查各项测试资源产品功能需求文档产品原型图产品效果...

手机APP产品测试用例实例与模版

中国电信XXX项目功能测试用例撰稿人XXXXX信息网络有限责任公司20xx年X月XX日目录1概述311编写目的312读者对象313参考资料32ANDROID测试用例421登陆注册422文件上传423文件收藏52...

装箱单样本Packing List

DONGFANGELECTRICCORPORATION115FirstSectionofWestYihuanAvenueChengduSichuan610041PRChinaTel860287012336Fax...

packing list(装箱单)

广东省纺织品进出口针织品有限公司1GUANGDONGTEXTILESIMPampEXPKNITWEARSCOMPANYLIMITED15FGUANGDONGTEXTILESMANSION168XIAOBEIRO...

装箱单 Packing list 模板

装箱单 Packing list 模板,内容附图。

装箱单报检模板-英语-packing list

WOODEDROUNDSTICKGRADEA5000PCSCARTON860CARTONS13502KGS13158KGS2758CBMTOTAL860CARTONS13502KGS13158KGS2758CBM...

外贸PI格式

外贸中PI是什么意思外贸PI指外贸的形式#5@p估价#5@p和备考货单等外贸PI也可作为买方向银行申请向卖方支付货款开立信用证等依据合理运用外贸PI能够为卖家提供更多的商品详细信息外贸中PI是什么意思外贸PI是指外贸的...

PI 格式

PI格式1公司名PMKEXCOMPMKE地址CentredaffairesEGB5avenueGeorgesBataille60330LEPLESSISBELLEVILLEContactZHANGJIETel0...

ppap范本(1篇)