1. 程式人生 > >【原創】我的畢業設計論文——利用HOOK技術實現應用層網路抓包

【原創】我的畢業設計論文——利用HOOK技術實現應用層網路抓包

 成都東軟資訊科技職業學院04級畢業論文

 利用HOOK技術實現應用層網路抓包

 班級: 視覺化程式設計2班 
導師: 李        丹 
學號: 04311110210 


姓名: 劉   海   平 

 
摘  要


    資料包抓取(攔截)技術,主要應用在資訊保安相關領域,特別是防火牆技術。隨著網路遊戲產業日益興旺,後來出現很多針對不同遊戲的外掛,這些外掛也使用到抓包技術,但是與其他抓包技術很大不同的是,外掛技術中的抓包技術必須達到能順利擷取、完成對資料包的修改、再次傳送出去等一系列特殊要求,基於以上要求,所以必須在應用層完成資料包的抓取、修改。
    本畢業設計論文介紹了在WINDOWS環境下,利用HOOK、DLL等技術,實現網路函式的攔截,從而實現在應用層完成資料包的抓取。

關鍵字:HOOK 、DLL、外掛、資料包抓取

 SUMMARY


    Data packet blocking technique is primarily used in information security field, especially firewall technique. As network game industry grows thriftier, lots of plus for different game appeared. These plus has used data packet blocking technique, too.But the difference to the other packet blocking technique is that in plus technique, packet blocking technique must accomplish requirements such as, blocking data favoringly, modify the data packet and then send them out again, etc. Based on these requirements, we must achieve data blocking, modification at the application layer.
 My dissertation introduces a method to implement the network packet blocking using techniques as HOOK, DLL, etc, under the windows environment. Then accordingly accomplish the data packet scratching at the application layer.

Keyword: HOOK 、DLL 、plus 、Block data packet

                                目      錄

1. 引言  4
2. 需求分析 5
2.1. 背景 5
2.2. 基本需求  5
2.3. 功能需求  5
2.4. 設計約束 5
3. 系統設計 6
3.1. 技術原理   6
3.1.1. DLL原理簡介  6
3.1.2. HOOK原理簡介 7
3.1.3. API函式攔截簡介 7
3.2. 抓包程式原理 7
3.3. 抓包程式功能模組設計 8
3.4. 結構設計 8
4. 程式實施   9
4.1. HOOK核心程式碼 9
4.2. 函式攔截核心程式碼 10
4.3. 記憶體修改核心程式碼  11
4.4. DLL函式匯出 12
4.5. EXE前臺程式碼功能說明 12
5. 結論 13
6. 參考文獻  13
7. 致謝 14

 
引言


    隨著網遊的發展,出現了越來越多的遊戲外掛。從市場的角度來說,遊戲外掛打破了遊戲運營商的“遊戲規則”,所以越來越多的遊戲運營商開始設定“反外掛”的部門;從技術的角度上來說,遊戲外掛是屬於WINDOWS核心程式設計技術的範疇,對於學習WINDOWS核心程式設計很有現實性的價值。所以本人選擇此課題作為畢業設計,想通過它學習到更多的WINDOWS核心技術。
    本論文主要分為八個章節,從抓包軟體的需求、設計、實施三個組成部分。以下為各章內容簡介:
    第一章 引言,對論文的框架進行一個大概的描述。
    第二章 需求分析,概述抓包程式的需求、背景知識以及對該技術的發展方向的一個簡單概述。
    第三章 系統設計,介紹的本課題的設計方案、設計原理以及各個模組的劃分。
    第四章 程式實施,根據系統設計,編寫程式的程式碼,且會講解本課題部分主要的核心程式碼。
    第五章 結論,通過本次畢業設計的完成,本人從中的收穫,以及對畢業設計的一個總結。
    第六章 參考文獻,在本人完成該畢業設計的過程中,所參考過的資料。
    第七章 致謝。

  需求分析
背景
    對於一個商業軟體來說,防止不法侵犯是個很重要的問題。這種問題在網路遊戲中體現的比較突出。隨著網路遊戲被越來越多的人所熟知,網遊外掛也漸漸走入了人們的視線。網遊外掛的泛濫,給遊戲運營商帶來了不小的損失。後來遊戲運營商為了防止遊戲玩家使用外掛,還提出過:一旦系統發現某個玩家使用外掛,那麼就對其帳號進行查封。因為遊戲執行商的這個做法,甚至還有玩家將運營商告上法庭。那麼這裡又涉及到虛擬財產的問題。由於中國對這方面的立法還比較欠缺,所以對於運營商也好、對於遊戲玩家也好,可能這不是最優的解決方案。
    因此,遊戲運營商家需要從外掛的開發開始著手,研究其技術特點,從自身完成反外掛的功能,這才是根本的問題解決之道。
    而在遊戲外掛中,一般為有資料包攔截、解密、修改、加密封包等步驟。一般反外掛的工作都在資料包攔截和加密這兩大模組完成。由於加密技術比較難,研究的成本相對較高,加之任何密文都有被破解的一天。所以從防止資料包攔截入手,可以以最少的投入獲得理想的效果。
    所謂知自知彼,百戰不殆。本論文就是研究在遊戲外掛技術中常用的資料包擷取方式,為反外掛技術的研究做一個基礎的鋪墊。
基本需求
完成網路資料包的抓取。
留出可修改資料包的介面,以便後期完成資料包修改。
功能需求
完成具有資料包的抓取的DLL模組
在前臺完成資料包的列印
設計約束
   本課題屬於WINDOWS核心程式設計的範疇,而且涉及道記憶體的屬性修改等問題。所有錯誤的設計和程式碼的編寫錯誤可能導致系統的不穩定、甚至崩潰。所有在完成課題的時必須從分考慮系統的穩定性。此外還應考慮是否能方便資料包的修改,是否能承受大量的資料包的抓取等問題。
系統設計
技術原理 
    本課題主要有三個主要的技術要點,以下是各個技術要點的原理簡介。
DLL原理簡介
    DLL 是一個包含可由多個程式同時使用的程式碼和資料的庫。使用 DLL 有助於促進程式碼的模組化、程式碼重用、記憶體的有效使用和減少所佔用的磁碟空間。因此,作業系統和程式能夠更快地載入和執行,並且在計算機中佔用較少的磁碟空間。
    一旦DLL的檔案映像被對映到程序的地址空間種,DLL函式就可以供程序種執行的所有執行緒使用。(如圖4.1)
                           DLL原理(圖4.1)
 第一個地址的              DLL的虛擬記憶體             第二個地址的
  程序空間                                               程序空間
 

 
DLL 的優點:
下表說明了當程式使用 DLL 時提供的一些優點:
• 使用較少的資源
    當多個程式使用同一個函式庫時,DLL 可以減少在磁碟和實體記憶體中載入的程式碼的重複量。這不僅可以大大影響在前臺執行的程式,而且可以大大影響其他在 Windows 作業系統上執行的程式。
• 推廣模組式體系結構
    DLL 有助於促進模組式程式的開發。這可以幫助您開發要求提供多個語言版本的大型程式或要求具有模組式體系結構的程式。模組式程式的一個示例是具有多個可以在執行時動態載入的模組的計帳程式。
• 簡化部署和安裝
    當 DLL 中的函式需要更新或修復時,部署和安裝 DLL 不要求重新建立程式與該 DLL 的連結。此外,如果多個程式使用同一個 DLL,那麼多個程式都將從該更新或修復中獲益。當您使用定期更新或修復的第三方 DLL 時,此問題可能會更頻繁地出現。


HOOK原理簡介
    鉤子(Hook),是Windows訊息處理機制的一個平臺,應用程式可以在上面設定子程以監視指定視窗的某種訊息,而且所監視的視窗可以是其他程序所建立的。當訊息到達後,在目標視窗處理函式之前處理它。鉤子機制允許應用程式截獲處理window訊息或特定事件。
鉤子實際上是一個處理訊息的程式段,通過系統呼叫,把它掛入系統。每當特定的訊息發出,在沒有到達目的視窗前,鉤子程式就先捕獲該訊息,亦即鉤子函式先得到控制權。這時鉤子函式即可以加工處理(改變)該訊息,也可以不作處理而繼續傳遞該訊息,還可以強制結束訊息的傳遞。HOOK機制如圖4.2
        HOOK 機制  (圖4.2)

數攔截簡介
    Api攔截並不是一個新的技術,很多商業軟體都採用這種技術。對windows的Api函式的攔截,不外乎兩種方法,第一種是Mr. Jeffrey Richter 的修改exe檔案的模組輸入節,種方法,很安全,但很複雜,而且有些exe檔案,沒有Dll的輸入符號的列表,有可能出現攔截不到的情況。第二種方法就是常用的JMP XXX的方法,雖然很古老,卻很簡單實用。本課題採用第二種方法,利用WINDOWS為我們提供的API,較為簡單的實現API函式攔截的功能。

抓包程式原理
    本課題的程式主要就是將HOOK、DLL和API函式攔截三個技術結合,實現資料包抓取,其基本原理如下:
    首先是利用HOOK技術完成訊息的截獲,提取出我們感興趣的訊息;再利用API攔截技術,攔截相應的網路程式的SOCKET網路函式;最後利用DLL技術將HOOK和API攔截的程式碼封裝。利用EXE程式將DLL對映到程序中。等到由HOOK掛載的程式的網路函式被呼叫時,引起API函式攔截,從而攔截相應的網路函式。最後,從網路函式中提取我們想要得到的資料包。
抓包程式功能模組設計
    該抓包程式分為:DLL模組和EXE模組兩大模組。
    DLL部分主要完成HOOK鉤子的掛載、API函式的攔截和處理攔截到的網路函式。
 EXE程式部分主要完成把DLL對映到程序空間,接受資料包內容的輸入和管理鉤子的安裝、解除安裝。
 
           DLL 模組部分                  DLL 載入模組

 結構設計
    由EXE將DLL載入到當前程序空間以後,DLL模組會注入到目標程序當中。當監測到有網路套節字的傳送、接受時,呼叫DLL模組中的API攔截函式。經過DLL中的API處理,再把網路函式發出。

 程式實施 
HOOK核心程式碼
    HOOK部分主要完成對特定目標程式的訊息鉤子的掛載,從而實現與目標程序共享DLL的程式碼和資料。該抓包程式完成以上功能,主要通過FindWindowEx()函式查詢CALSS NAME(可以用SPY++確定目標程式的CLASS NAME)來確定目標程式的控制代碼。從而確定目標執行緒的標識,再使用SetWindowsHookEx()掛載訊息鉤子。
    這樣,一旦目標程式(執行緒)啟動,那麼該程式的所有訊息都必須先經過我們的DLL模組,待我們處理完自己感興趣的訊息之後,再將訊息發出。
    具體程式碼如下,以下程式碼中,還加入了一些異常檢測部分:

    g_hArmIns = FindWindowEx(NULL,NULL,/*"目標程式CLASS NAME"*/,NULL);
    //查詢目標執行緒的控制代碼
 dwThreadID = GetWindowThreadProcessId(g_hArmIns,NULL);
    //儲存執行緒的標識
 if (dwThreadID==NULL)  //異常檢測
 {
  MessageBox(hwnd,"要被注入的程式沒有被開啟","錯誤",MB_OK);
 }
 else if (g_hInsMouse != NULL && g_hInsKeyboard!=NULL)
 {
  MessageBox(hwnd,"你已經注入了,無需多次注入","錯誤",MB_OK);
 }
    else
 {
        g_hInsMsg=SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,
                                 GetModuleHandle("dllname"),dwThreadID);
     //安裝訊息鉤子,其具體引數意義,請參看MSDN。
    }


函式攔截核心程式碼
    函式攔截部分主要完成網路函式的替換。首先動態載入wsock32.dll,所有的網路接受、傳送函式都在此DLL中;然後利用GetProcAddress()函式,從DLL中獲得我我們想要截獲的網路函式的首地址,並儲存;其次使用匯編語言再儲存一個我們要攔截的函式的副本,以便後期恢復;最後再次使用匯編,使我們的函式的地址覆蓋我們要攔截的網路函式。
    這樣,當系統呼叫網路函式傳送、接受資料的時候,實際上就是呼叫的我們自己編寫的函式,從而實現函式攔截的功能。
    具體程式碼如下:
 hModule = LoadLibrary("wsock32.dll");
 //載入wsock32.dll模組
 pfSend = GetProcAddress(hModule,"send");
 //從wsock32.dll模組中獲得SEND函式入口地址
 if(pfSend==NULL)
  return false;
 // 儲存 pfSend 的一個副本 -- oldSend
    _asm
 {
  lea edi,oldSend
  mov esi,pfSend
  cld
  movsd
  movsb
 }
  newSend[0] = 0xe9;  //jmp MySend的相對指令
 //利用我們的MySend函式替換pfSend函式入口
 _asm
 {
  lea eax,MySend
  mov ebx,pfSend
  sub eax,ebx
  sub eax,5
  mov dword ptr [newSend+1],eax
 }

   以上兩段程式碼只是完成WSOCK32.DLL中的SEND函式攔截。我們知道網路函式都有SEND和RECV兩種狀態,而且常用的網路連線方式又有TCP和UDP兩種。所以我們還應該完成RECV、SENDTO(UDP傳送)、RECVTO(UDP接受)的函式攔截,基本方式通SEND。


記憶體修改核心程式碼
    記憶體修改是本程式比較關鍵的一段待程式碼。因為WINDOWS的記憶體是具有保護機制的。每個程序有自己私有的4GB的虛擬地址空間,EXE和DLL程式被對映到底部的2GB的地址上。WINDOWS為了安全,嚴格的標記此2GB記憶體空間,所有EXE和DLL的程式碼都是標記為只讀的,因此一個程序想要訪問另一個程序的棧、全域性記憶體或者堆記憶體是不可能的。因此我們必須通過WINDOWS給我們提供的API函式修改記憶體的屬性。
    以下就是將記憶體修改為可寫狀態的程式碼:
void _stdcall sendHookOn() //send
{
    HANDLE hProc;
    dwIdOld=dwIdNew;
    hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
    //得到所屬程序的控制代碼
    VirtualProtectEx(hProc,pfSend,5,PAGE_READWRITE,&dwIdOld);
    //修改所屬程序中send的前5個位元組的屬性為可寫
    WriteProcessMemory(hProc,pfSend,newSend,5,0);
    //將所屬程序中send的前5個位元組改為JMP 到MySend
    VirtualProtectEx(hProc,pfSend,5,dwIdOld,&dwIdOld);
    //修改所屬程序中send的前5個位元組的屬性為原來的屬性
    bHook=true;
}

    當我不們不再需要修改記憶體內容的時候,我們應該將記憶體還原為以前的只讀狀態,這樣才不會破壞WINDOWS的記憶體結構,以下程式碼就是完成所述功能。

void _stdcall sendHookOff()
{
    HANDLE hProc;
    dwIdOld=dwIdNew;
    hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
    VirtualProtectEx(hProc,pfSend,5,PAGE_READWRITE,&dwIdOld);
    WriteProcessMemory(hProc,pfSend,oldSend,5,0);
    VirtualProtectEx(hProc,pfSend,5,dwIdOld,&dwIdOld);
    bHook=false;
}

    以上兩段程式碼只是完成TCP中的SEND函式的修改。我們知道網路函式都有SEND和RECV兩種狀態,而且常用的網路連線方式又有TCP和UDP兩種。所以我們在還應該完成RECV、SENDTO(UDP傳送)、RECVTO(UDP接受)。基本方式同SEND。

DLL函式匯出
    當我們完成DLL功能模組時,我們要講DLL中的功能函式匯出成規則的函式名。因為C++編譯器在編譯的時候會對函式名進行改編,這樣我們想呼叫自己DLL中的函式就會遇到困難,所以我們要指定要匯出的函式的名稱,這樣才能方便我們的呼叫。
    有兩種方法可以解決以上問題:
    方法一:
   在要匯出的全域性函式名之前加上這樣一句:  extern "C"  _declspec(dllexport) 它表明,將一個DLL中的函式匯出,並且遵守標準C的呼叫約定。
    方法二:
    使用模組定義檔案(.def),並將其加入到工程中,新增如下程式碼:
    LIBRARY  (動態連結庫名)
    EXPORTS  (以下列出要匯出的函式名)

EXE前臺程式碼功能說明
    EXE前臺主要完成鉤子掛載的安裝、解除安裝和接受DLL的模組的訊息,並在其視窗中打印出資料包。
    EXE部分使用MFC的對話方塊,主要完成的工作有:
    使用_declspec(dllexport)接受匯出的函式。因為在EXE前臺要呼叫DLL中的函式,就必須告訴EXE,這個函式是從DLL中獲得,不然系統會報告,未定義函式的錯誤。
    編寫訊息相應程式碼,完成鉤子的安裝和解除安裝,當EXE得到DLL中的函式時,需要在前臺啟動鉤子。具體步驟為:新增一個按鈕、新增其點選事件響應函式、呼叫DLL中的函式。
    處理使用者自定義訊息,因為我們在DLL中把資料包的地址和大小以訊息的形式傳送到EXE端處理,所以我們EXE端必須響應DLL端發出的訊息,具體步驟為:1、在標頭檔案中定義訊息型別。2、在訊息對映巨集中新增訊息對映。3、在CPP檔案中根據訊息對映,新增訊息處理函式。
    列印資料包到視窗中,根據訊息中的資料包地址和長度,打印出資料包的內容。
   


結論
    通過這次畢業設計,本人不僅熟悉了WINDOWS的核心程式設計、深入的學習HOOK等技術上的收穫,而且明顯的感覺自己的自學能力得到的很大的提升。
 在畢業設計的這段時間和過程中,可以深切地體會到,通過實際地進行軟體的開發和程式的設計是對所學知識的再認識和更進一步的理解和運用。
    總之,覺得此次畢業設計受益頗深,在學習相關知識的基礎上能夠充分的運用於實際,並在實際操作中進一步提高了自己的學習能力。因此,本次畢業設計是對大學兩年所學知識的檢驗,同時也是對以後的學習和工作的幫助和啟迪。

參考文獻
圖書類:

作者:Jeffrey Richter 書名:《WINDOWS 核心程式設計》
    出版單位:MICROSOFT PRESS

作者:George Shepherd 、David J.Kruglinski 書名:《VC.NET 技術內幕》  
    出版單位:MICROSOFT PRESS

作者:Charles Petzold 書名:《WINDOWS 程式設計》
    出版單位:MICROSOFT PRESS

作者: Prasad Dabak 、Milind Borate、Sandeep Phadke
書名:《Undocumented Windows NT 中文版》  出版單位:M&T

網上資料類:

致謝
    本論文的完成,首先要感謝我的父母對我多年養育以及對我學業的支援。要知道在我初中的時候父母為我學習計算機付出了不小的代價。
    其次,感謝我的指導老師李丹,感謝你花費了很多很多的時間給予我指導,我才有可能完成此論文。
    然後,感謝我的各位朋友,因為你們在我成長的路上,也給了我很多幫助。
    最後,感謝上帝,呵呵,你讓我生活在一個如此美好的世界!! ^_^