一、安裝VS2013,下載wpdpack,為VS2010配置WinpCap環境: ⑴首先在View中選擇Property Manager,然後展開工程,再展開Debug|Win32 ,接著右擊 Mircrosoft.Cpp.Win32.user選擇Properties(此處設置全局有效) ⑵之後分三 ...
一、安裝VS2013,下載wpdpack,為VS2010配置WinpCap環境:
⑴首先在View中選擇Property Manager,然後展開工程,再展開Debug|Win32 ,接著右擊 Mircrosoft.Cpp.Win32.user選擇Properties(此處設置全局有效)
⑵之後分三步:
①設置環境目錄
在VC++ Directiories中 Include Directories和Library Directories中添加路徑。
假如將wpdpack放到c盤。則:
Include Directories:c:/wpdpack/Include;
Library Directories:c:/wpdpack/Lib;
註意分號!
②設置編譯條件
C/C++下Preprocessor(預處理器)的Preprocessor Definitions(預處理定義)
添加WPCAP;HAVE_REMOTE;
註意分號,每個預定義符用“;”分開。
③設置鏈接器
Linker(鏈接器)下的Input(輸入)中的Additional Dependencies(附加依賴項)中添加:
wpcap.lib;ws2_32.lib;(註意分號)
二、使用mfc實現可視化界面:
目的視圖:
1、新建項目:
選擇Visual C++ -> MFC -> MFC應用程式 –>修改項目名稱test1 -> 下一步 –> 選擇基於對話框 -> 完成
2、相關視圖介紹:
①解決方案資源管理器:可以看見所有的頭文件和源(.cpp)文件,此程式只需用到test1Dlg.cpp和test1Dlg.h。另外MFC中main函數被封裝起來了,並且我們也並不需要知道main函數在哪,因為我們希望實現的功能通常是觸發某個控制項,這個控制項的觸發函數為我們實現,並不需要將代碼寫到main函數內。
②類視圖:在類視圖中,我們可以看到三個類,此處只需要用到Ctest1Dlg,點擊類名,可以在下方很方便的找到類中的函數和變數。
③屬性管理器:在為VS配置全局環境時會用到。
④資源視圖:在test1 -> test1.rc -> Dialog -> IDD_TEST1_DIALOG可以看見自己設計的可視化界面。
⑤屬性:處理控制項時,在此處修改控制項的屬性。
3、相關控制項的使用:
①靜態文本框Static Text:caption修改文字內容
②編輯框Edit Control:Read Only設置是否只讀
③IP地址編輯框IP Address Control:用法與普通編輯框一樣,只不過讀取內容時可以使用GetAddress()函數。
④組合框Combo Box:Type分為三種:簡易(Simple)組合框、下拉式(Dropdown)組合框和下拉列表式(Drop List)組合框,這裡選擇Drop List。
三、詳細設計:
1.ARP發送中重要方法:
填充ARP包方法的流程圖:
四、添加函數:
1、 更改各控制項ID,並給部分空間增加變數。Combo Box的預設ID更改為IDC_NIC_COMBO,增加控制項變數m_comboNic;目的MAC地址的編輯框ID設為IDC_DESTI_MACADDRESS_EDIT,添加控制項變數為m_editDesti;目的IP地址的編輯框ID設為IDC_DESTI_IPADDRESS,添加控制項變數為m_ipaddressSesti;源MAC地址的編輯框ID設為IDC_SOURCE_MACADDRESS_EDIT,添加控制項變數為m_editSource;源IP地址的編輯框ID設為IDC_SOURCE_IPADDRESS,添加控制項變數為m_ipaddressSource;結果顯示編輯框ID設為IDC_RESULT_EDIT,添加控制項變數為m_editResult。
2、 依據ARP包的結構定義結構體,並將需要引入的頭文件、結構體和相關常量的定義寫入test1Dlg.h文件中。
#include "stdafx.h" #include <pcap.h> #define ETH_ARP 0x0806 //乙太網幀類型表示後面數據的類型,對於ARP請求或應答來說,該欄位的值為x0806 #define ARP_HARDWARE 1 //硬體類型欄位值為表示乙太網地址 #define ETH_IP 0x0800 //協議類型欄位表示要映射的協議地址類型值為x0800表示IP地址 #define ARP_REQUEST 1 //ARP請求 #define ARP_RESPONSE 2 //ARP應答 //14位元組乙太網首部 struct EthernetHeader { u_char DestMAC[6]; //目的MAC地址 6位元組 u_char SourMAC[6]; //源MAC地址 6位元組 u_short EthType; //上一層協議類型,如0x0800代表上一層是IP協議,0x0806為arp 2位元組 }; //28位元組ARP幀結構 struct ArpHeader { unsigned short hdType; //硬體類型 unsigned short proType; //協議類型 unsigned char hdSize; //硬體地址長度 unsigned char proSize; //協議地址長度 unsigned short op; //操作類型,ARP請求(1),ARP應答(2),RARP請求(3),RARP應答(4)。 u_char smac[6]; //源MAC地址 u_char sip[4]; //源IP地址 u_char dmac[6]; //目的MAC地址 u_char dip[4]; //目的IP地址 }; //定義整個arp報文包,總長度42位元組 struct ArpPacket { EthernetHeader ed; ArpHeader ah; };
3、 在Ctest1Dlg::OnInitDialog()中寫入初始化的界面的代碼。
/* 獲取本機設備列表 */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { m_comboNic.AddString(_T("Error in pcap_findalldevs!")); exit(1); } /* 列印列表 */ for (d = alldevs; d; d = d->next) { ++i; if (d->description) m_comboNic.AddString(LPCTSTR(CString(d->name))); else m_comboNic.AddString(_T("(No description available)")); } if (i == 0) { m_comboNic.AddString(_T("No interfaces found! Make sure WinPcap is installed.")); return -1; } // 預設選擇第一項 m_comboNic.SetCurSel(0); //目的MAC地址編輯框中預設顯示"00-00-00-00-00-00" SetDlgItemText(IDC_EDIT1, _T("00-00-00-00-00-00"));
4、 在確認按鈕的響應函數內添加以下代碼:
// 獲取組合框控制項的列表框中選中項的索引 inum = m_comboNic.GetCurSel(); /* 跳轉到選中的適配器 */ for (d = alldevs, i = 0; i<= inum - 1; d = d->next, i++); /* 打開設備 */ if ((adhandle = pcap_open(d->name, // 設備名 65536, // 65535保證能捕獲到不同數據鏈路層上的每個數據包的全部內容 PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式 1000, // 讀取超時時間 NULL, // 遠程機器驗證 errbuf // 錯誤緩衝池 )) == NULL) { m_editResult.SetWindowText(_T("Unable to open the adapter. \rIt is not supported by WinPcap")); /* 釋放設備列表 */ pcap_freealldevs(alldevs); exit(-1); } unsigned char sendbuf[42]; //arp包結構大小,42個位元組 BYTE IPByte[4]; m_ipaddressSesti.GetAddress(IPByte[0], IPByte[1], IPByte[2], IPByte[3]); BYTE IPByte2[4]; m_ipaddressSource.GetAddress(IPByte2[0], IPByte2[1], IPByte2[2], IPByte2[3]); CString str; char *c; BYTE mac[7] = { 0 };//源MAC地址 m_editSource.GetWindowText(str);//獲取字元串 c = cs2ca(str); //CString轉為char* sscanf_s(c, "%h2x-%h2x-%h2x-%h2x-%h2x-%h2x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); EthernetHeader eh; ArpHeader ah; if (IsDlgButtonChecked(IDC_RADIO1) == 1) { //請求報文 .....//相應代碼
} else if (IsDlgButtonChecked(IDC_RADIO2) == 1) { //應答報文 .....//相應代碼
} //構造一個ARP請求 memset(sendbuf, 0, sizeof(sendbuf)); //ARP清零 memcpy(sendbuf, &eh, sizeof(eh)); memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah)); //如果發送成功 if (pcap_sendpacket(adhandle, sendbuf, 42) == 0) { m_editResult.SetWindowText(_T("\nPacketSend succeed\n")); } else { m_editResult.SetWindowText(_T("\nPacketSendPacket in getmine Error\n")); } /* 釋放設備列表 */ pcap_freealldevs(alldevs);
其中主要遇到的困難是,如何獲取三個編輯框中用戶輸入的地址,將這種Cstring格式的地址轉為u_char格式的字元數組。IP ADDRESS CONTROL可以使用其函數GetAddress(IPByte[0], IPByte[1], IPByte[2], IPByte[3]);獲得。而MAC地址的編輯框獲得的字元串就不太好轉換了。碰過好多好多坑,試過好多好多方法之後,最終找到一種可行的方法:先把Cstring字元串利用函數轉換為char*型,再使用sscanf將每兩位代表十六進位的字元存在BYTE mac[7]數組中,但是貌似在vs2015中無法使用這個方法。
四、運行效果:
傳送門:
3.用sscanf轉換MAC字元串為BYTE數組時遇到的問題