二. 發送ARP包的編程實現
1. 填充數據包
上面的那些關于ARP包各個字段的表格,對應在程序里就是結構體,對應于上面的表格,于是我們需要三個下面這樣的結構體
// DLC Header
typedef struct tagDLCHeader
{
unsigned char DesMAC[6]; /* destination HW addrress */
unsigned char SrcMAC[6]; /* source HW addresss */
unsigned short Ethertype; /* ethernet type */
} DLCHEADER, *PDLCHEADER;
// ARP Frame
typedef struct tagARPFrame
{
unsigned short HW_Type; /* hardware address */
unsigned short Prot_Type; /* protocol address */
unsigned char HW_Addr_Len; /* length of hardware address */
unsigned char Prot_Addr_Len; /* length of protocol address */
unsigned short Opcode; /* ARP/RARP */
unsigned char Send_HW_Addr[6]; /* sender hardware address */
unsigned long Send_Prot_Addr; /* sender protocol address */
unsigned char Targ_HW_Addr[6]; /* target hardware address */
unsigned long Targ_Prot_Addr; /* target protocol address */
unsigned char padding[18];
} ARPFRAME, *PARPFRAME;
// ARP Packet = DLC header + ARP Frame
typedef struct tagARPPacket
{
DLCHEADER dlcHeader;
ARPFRAME arpFrame;
} ARPPACKET, *PARPPACKET;
這些結構體一定能看懂吧,在程序中就是對號入座就好了
1. 填充數據包
下面我舉個填充包頭的例子,我首先定義個了一個轉換字符的函數,如下
/****************************************************************************
* 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.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
******************************************************************/
**************************
delete pIpNetTable;
}
}
這樣一來,我們基本上大功告成了,其他還有一些東西在這里就不講了,大家可以下載我的代碼看看就好了。
下面我們來用ARP包玩一些小把戲 ^_^。
四.ARP包的游戲
既然我們可以自己來填充數據包,那么來玩些ARP的“小游戲”欺騙就是易如反掌了,當然,是在沒有安全防護的網絡里 ,比如只有hub或者交換機把你們相連,而沒有路由分段……^_^
下面我就由淺入深的講一些介紹一些關于ARP的小伎倆。
1. 小伎倆
1) 你可以試著發一個請求包廣播,其中的ARP幀里關于你的信息填成這樣:
(為了節省篇幅,我只寫需要特別指出的填充字段)
發送方MAC
|
6
|
隨便亂填一個錯誤的
|
發送方IP
|
4
|
填上你的IP
|
出現什么結果?是不是彈出一個IP地址沖突的提示?呵呵,同樣的道理,如果發送方IP填成別人的,然后每隔1秒發一次………..-_-b
2) 比如你們都靠一個網關192.168.0.1 上網 ,如果你想讓192.168.0.77 上不了網,就可以偽裝成網關給192.168.0.77發一個錯誤的ARP響應包, like this
發送方MAC
|
6
|
隨便亂填一個錯誤的
|
發送方IP
|
4
|
網關IP 192.168.0.1
|
接收方就填192.168.0.77的相關信息,發送之后,它還能上網不?
這樣能折騰他好一陣子了,只要它的系統得不到正確的到網關的ARP映射表它就一直上不了網了