隨筆-17  評論-64  文章-79  trackbacks-1

          B. 打開相應網卡并設置為混雜模式:

          ?? 在此之前肯定要有一段讓用戶選擇網卡、并獲得用戶選擇的網卡的名字的代碼,既然上面已經可以獲得所有網卡的名字了,這段代碼就暫且略過了。

          ?? 我們主要是要用到 pcap_open_live 函數,不過這個函數 winpcap 的開發小組已經建議用 pcap_open 函數來代替,不過因為我的代碼里面用的就是 pcap_open_live ,所以也不便于修改了,不過 pcap_open_live 使用起來也是沒有任何問題的,下面是 pcap_open_live 的函數聲明:

          ?/*************************************************

          pcap_t* pcap_open_live? (? char *??? device,?

          ? ?????????????????????????? ?int??? snaplen,?

          ? int??? promisc,?

          ? int??? to_ms,?

          ? char *??? ebuf

          ?) ?

          ???? 功能:

          ?????????? 根據網卡名字打開網卡,并設置為混雜模式,然后返回其句柄

          ???? 參數:

          ?????????? Device? : 就是前前面我們獲得的網卡的名字;

          ?????????? Snaplen :? 我們從每個數據包里取得數據的長度,比如設置為 100 ,則每次我們只是獲得每個數據包 100 個長度的數據,沒有什么特殊需求的話就把它設置為 65535 最大值就可以了;

          ?????????? Promisc :這個參數就是設置是否把網卡設置為“混雜模式”,設置為 1 即可;

          ?????????? to_ms :?? 超時時間,毫秒,一般設置為 1000 即可。

          ???? 返回值:

          ?????????? pcap_t :? 類似于一個網卡“句柄”之類的,不過當然不是,這個參數是后面截獲數據要用到的。

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

          雖然看起來比較復雜,不過用起來還是非常簡單的,其實 1 行就 OK 了:

          ?? ? pcap_t* adhandle;

          ?????? char errbuf[PCAP_ERRBUF_SIZE];

          // 打開網卡,并且設置為混雜模式

          // pCardName 是前面傳來的網卡名字參數

          adhandle = pcap_open_live(pCardName,65535,1,1000,errbuf);

          ?

          C. 截獲數據包并保存為文件: ------------------------------------------------------

          ???? 當然,不把數據包保存為文件也可以,不過如果不保存的話,只能在截獲到數據包的那一瞬間進行分析,轉眼就沒了 ^_^

          所以,為了便于日后分析,所以高手以及我個人經常是把數據包保存下來的慢慢分析的。

          但是注意網絡流量,在流量非常大的時候注意硬盤空間呵呵,常常幾秒中就有好幾兆是很正常的事情。

          下面首先來詳細講解一下,這個步驟中需要用到的 winpcap 函數:

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

          pcap_dumper_t* pcap_dump_open? (? pcap_t *??? p,?

          ? ??????????????????????????????????? ?const char *??? fname

          ?)

          功能:

          ????? 建立或者打開存儲數據包內容的文件 , 并返回其句柄

          參數:

          ????? ?pcap_t *??? p???? :前面打開的網卡句柄;

          ????? const char * fname :要保存的文件名字 ???

          返回值:

          ?????? pcap_dumper_t* 保存文件的描述句柄,具體細節我們不用關心

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

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

          int pcap_next_ex? ????????(? pcap_t *??? p,?

          ? ??????????????????????????? ?struct pcap_pkthdr **??? pkt_header,?

          ? u_char **??? pkt_data

          ?) ?

          功能:

          ????? 從網卡或者數據包文件中讀取數據內容

          參數:

          ????? pcap_t *??? p:??? 網卡句柄

          ????? struct pcap_pkthdr ** pkt_header: 并非是數據包的指針,只是與數據包捕獲驅動有關的一個 Header

          ????? u_char ** pkt_data :指向數據包內容的指針 ,包括了協議頭 ??

          返回值:

          ????? ??? ?1 : 如果成功讀取數據包

          ????????? 0 pcap_open_live() 設定的超時時間之內沒有讀取到內容

          ????????? -1: 出現錯誤

          ????????? -2: 讀文件時讀到了末尾

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

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

          void pcap_dump? (? u_char *??? user,?

          ? ?????????????????????const struct pcap_pkthdr *??? h,?

          ? const u_char *??? sp

          ?) ??

          功能:

          ????? 將數據包內容依次寫入 pcap_dump_open ()指定的文件中

          參數:

          ????? u_char * user?? :? 網卡句柄

          ????? const struct pcap_pkthdr * h: 并非是數據包的指針,只是與數據包捕獲驅動有關的一個 Header

          ??? ? ?const u_char * sp 數據包內容指針 ???

          返回值:

          ????????? Void

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

          ? 下面給出一段完整的捕獲數據包的代碼,是在線程中寫的,為了程序清晰,我去掉了錯誤處理代碼以及線程退出的代碼,完整代碼可下載文后的示例源碼,老規矩,重要的步驟用粗體字標出。

          我們實際在捕獲數據包的時候也最好是把代碼放到另外的線程中。

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

          *?? 進程 :

          *?????????????????? 這個是程序的核心部分,完成數據包的截獲

          *???? 參數 :

          *?????????????????? pParam: 用戶選擇的用來捕獲數據的網卡的名字

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

          UINT CaptureThread(LPVOID pParam)

          {

          ?????? const char* pCardName=(char*)pParam;? ????????// 轉換參數,獲得網卡名字 ???????????????????????

          ?

          ?????? pcap_t* adhandle;

          ?????? char errbuf[PCAP_ERRBUF_SIZE];?????????????

          ?????? // 打開網卡,并且設置為混雜模式

          ? adhandle=pcap_open_live(pCardName,65535,1,1000,errbuf) ? ??? {

          ?

          ?????? pcap_dumper_t* dumpfile;

          // 建立存儲截獲數據包的文件

          ?????? dumpfile=pcap_dump_open(adhandle, "Packet.dat"); ???

          ?

          ?????? int re;

          ?????? pcap_pkthdr* header;????? // Header

          ?????? u_char* pkt_data;???????? // 數據包內容指針

          // 從網卡或者文件中不停讀取數據包信息

          ?????? while((re=pcap_next_ex(adhandle,&header,(const u_char**)&pkt_data))>=0)

          ? ??? {

          ??? ?????? // 將捕獲的數據包存入文件

          ????????????? pcap_dump((unsignedchar*)dumpfile,header,pkt_data); ?????

          ?????? }

          ?????? return 0;

          } ??

          將個線程加入到程序里面啟動以后。。。等等,如何來啟動這個線程就不用我說了吧,類似這樣的代碼就可以

          ::AfxBeginThread(CaptureThread,chNIC);? ???// chNIC 是網卡的名字 ,char* 類型

          啟動線程一段時間以后 ( 幾秒中就有效果了 ) ,可以看到數據包已經被成功的截獲下來,并存儲到程序目錄下的 Packet.dat 文件中。

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

          至此,數據包的截獲方法就講完了,大家看了這篇文章,其實你就一定也明白了,無論是 raw socket 的方法還是 winpcap 的方法,其實都很簡單的,真的沒有什么東西,只是會讓不明白原理的人看起來很神秘而已, isn’t it?

          呵呵,不過也不要高興的太早,這個保存下來的數據包文件,你可以試著用 UltraEdit 打開這個文件看看,是不是大部分都是亂碼?基本上沒有什么可讀性,這是因為:

          此時捕獲到的數據包并不僅僅是單純的數據信息,而是包含有 IP 頭、 TCP 頭等信息頭的最原始的數據信息,這些信息保留了它在網絡傳輸時的原貌。通過對這些在低層傳輸的原始信息的分析可以得到有關網絡的一些信息。由于這些數據經過了網絡層和傳輸層的打包,因此需要根據其附加的幀頭對數據包進行分析。

          呵呵,所以我們要走的路還很長,這只是剛剛入門而已 ^_^

          posted on 2007-02-16 15:53 飛鳥 閱讀(552) 評論(0)  編輯  收藏 所屬分類: VC
          主站蜘蛛池模板: 荥经县| 江永县| 吴桥县| 平度市| 阜南县| 新巴尔虎左旗| 修文县| 江山市| 洛扎县| 石城县| 南宁市| 宽甸| 西华县| 高雄市| 秦皇岛市| 吉水县| 突泉县| 青龙| 尚义县| 怀仁县| 馆陶县| 博罗县| 长泰县| 永嘉县| 苗栗县| 池州市| 娱乐| 兴仁县| 云霄县| 洛南县| 永平县| 婺源县| 揭西县| 莱西市| 博白县| 大同市| 土默特右旗| 庐江县| 涟源市| 黄陵县| 沁水县|