作者:
CSDN? VC/MFC 網(wǎng)絡編程
PiggyXP ?^_^
?
? 目錄:
二。發(fā)送數(shù)據(jù)包的編程實現(xiàn)
?? 1.? 填充數(shù)據(jù)包
?? 2.? 發(fā)送數(shù)據(jù)包
三。一些附加步驟及說明
?? 1.? 如果在VC中使用winpcap
?? 2.? 獲得網(wǎng)卡信息列表
?? 3.? 獲得系統(tǒng)ARP信息列表
?
?????????................緊接上
文................
?
1.???????
填充數(shù)據(jù)包
?
下面我舉個填充包頭的例子,我首先定義個了一個轉換字符的函數(shù),如下
?
/****************************************************************************
?*?? Name & Params::
?*???????????? formatStrToMAC
?*???????????? (
?*???????????????? const LPSTR lpHWAddrStr : 用戶輸入的MAC地址字符串
?*???????????????? unsigned char *HWAddr :?? 返回的MAC地址字符串(賦給數(shù)據(jù)包結構體)
?*???????????? )
?*?? Purpose:
?*???????????? 將用戶輸入的MAC地址字符轉成數(shù)據(jù)包結構體需要的格式
?****************************************************************************/
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';??????????????????????? ?// 數(shù)字
???????????? ? 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));??????????? ??????????// 數(shù)據(jù)包初始化
?
???? 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的以太網(wǎng)類型
???? ARPPacket.arpFrame.HW_Type = htons((unsigned short)1);???????????// 硬件類型
???? ARPPacket.arpFrame.Prot_Type = htons((unsigned short)0x0800);??? // 上層協(xié)議類型
???? ARPPacket.arpFrame.HW_Addr_Len = (unsigned char)6;???????????????? // MAC地址長度
???? ARPPacket.arpFrame.Prot_Addr_Len = (unsigned char)4;?????????????? // IP地址長度
?
That’s all ! ^_^
填充完畢之后,我們需要做的就是把我們的ARPPACKET結構體發(fā)送出去
?
2.發(fā)送ARP數(shù)據(jù)包:
?
我們發(fā)送ARP包就要用到winpcap的api了,具體步驟及函數(shù)是這樣的,為了簡單易懂,我把錯誤處理的地方都去掉了,詳見代碼
/**********************************************************************
*??? Name & Params::
*???????????? SendARPPacket()
*??? Purpose:
*???????????? 發(fā)送ARP數(shù)據(jù)包
*??? Remarks:
*???????????? 用的是winpcap的api函數(shù)
***********************************************************************/
void SendARPPacket()
{
???? char *AdapterDeviceName =GetCurAdapterName(); ????// 首先獲得獲得網(wǎng)卡名字
?
???? lpAdapter = PacketOpenAdapter(AdapterDeviceName);???? // 根據(jù)網(wǎng)卡名字打開網(wǎng)卡
?
???? lpPacket = PacketAllocatePacket();????????? ?????// 給PACKET結構指針分配內存
?
???? PacketInitPacket(lpPacket, &ARPPacket, sizeof(ARPPacket));?//初始化PACKET結構指針
?????????????????????? ??????????????????????// 其中的ARPPacket就是我們先前填充的ARP包
?
???? PacketSetNumWrites(lpAdapter, 1);????? ?????????// 每次只發(fā)送一個包
?
???? PacketSendPacket(lpAdapter, lpPacket, true)????? ?// Send !!!!! ^_^
?
???? PacketFreePacket(lpPacket);???????????????????? // 釋放資源
???? PacketCloseAdapter(lpAdapter);
}
?
呵呵,至此,關于ARP包最關鍵的部分就講完了,你現(xiàn)在就可以來隨心所欲的發(fā)送自己的ARP包了
?
既然作為一篇“科普文章”,接下來我再講一講與整個項目有關的附加步驟以及說明
?
三.附加步驟以及說明
1. 如何在VC中使用winpcap驅動
?????? 雖然winpcap開發(fā)包使用起來非常簡便,但是前期準備工作還是要費一番功夫的,缺一不可。^_^
?????? 首先就是要安裝它的驅動程序了,可以到它的主頁下載,更新很快的
???? 下載WinPcap auto-installer (driver +DLLs),直接安裝就好了,或者我提供的代碼包里面也有。
???? 希望以后用winpcap作開發(fā)的朋友,還需要下載 Developer's pack,解壓即可。
????
??????? 然后,需要設置我們工程的附加包含目錄為我們下載Developer's pack開發(fā)包的Inclulde目錄,連接器的附加依賴庫設置為Developer's pack的lib目錄。
?????? 當然,因為我們的工作比較簡單,就是借用winpcap發(fā)送數(shù)據(jù)包而已,所以只用從
winpcap開發(fā)包的include文件夾中,拷貝Packet32.h,到我們的工程來,并且包含它就可
以,
但是要注意,Packet32.h本身還要包含一個Devioctl.h,也要一并拷貝進來,當然還有運
行庫Packet.lib,一共就是需要拷貝3個文件了,如果加入庫不用我多說了吧,在工程里面設
置,或者是在需要它的地方加入#pragma comment(lib, "Packet.lib")了。
?
??????? 整個項目其實可以分為四個部分,填充數(shù)據(jù)包、發(fā)送數(shù)據(jù)包、枚舉系統(tǒng)網(wǎng)卡列表和
相關信息以及枚舉系統(tǒng)ARP緩存列表,下面我再講一下如何獲得系統(tǒng)的網(wǎng)卡以及ARP列
表,這兩個部分都要用到IP Helper的api,所以要包含<Iphlpapi.h>以及庫文件Iphlpapi.lib,
其實都是很簡單的,只用寥寥幾行就OK了
2.???? 枚舉系統(tǒng)網(wǎng)卡以及信息
最好是先定義關于網(wǎng)卡信息的一個結構體,這樣顯得結構比較清晰
// 網(wǎng)卡信息
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:
*???????????? 獲得系統(tǒng)的網(wǎng)卡信息,并將其添加到list控件中
*??? Remarks:
*???????????? 獲得網(wǎng)卡IP及MAC用到了IpHelper api GetAdaptersInfo
******************************************************************/
void AddAdapInfoToList(CListCtrl& list)
{
???? char tempChar;
???? ULONG uListSize=1;
???? PIP_ADAPTER_INFO pAdapter;?????????? // 定義PIP_ADAPTER_INFO結構存儲網(wǎng)卡信息
???? int nAdapterIndex = 0;
?
???? DWORD dwRet = GetAdaptersInfo((PIP_ADAPTER_INFO)&tempChar, &uListSize);//關鍵函數(shù)
?
???? 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)????????????????????????????????????????? ??? // 枚舉網(wǎng)卡然后將相關條目添加到List中
???? {
??????? // 網(wǎng)卡名字
????????? 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);
????????? // 網(wǎng)卡編號
????????? 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 :?? 用戶選中的網(wǎng)卡編號
*???????????? )
*??? Purpose:
*???????????? 讀入系統(tǒng)的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);? // 關鍵函數(shù)
???? 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) {?????????? // 根據(jù)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包玩一些小把戲 ^_^。