青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Xiao.Zhu C++

Xiao.Zhu C++

  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  29 隨筆 :: 14 文章 :: 17 評論 :: 0 Trackbacks
通過對動作模擬技術的介紹,我們對游戲外掛有了一定程度上的認識,也學會了使用動作模擬技術來實現(xiàn)簡單的動作模擬型游戲外掛的制作。這種動作模擬型游戲外掛有一定的局限性,它僅僅只能解決使用計算機代替人力完成那么有規(guī)律、繁瑣而無聊的游戲動作。但是,隨著網(wǎng)絡游戲的盛行和復雜度的增加,很多游戲要求將客戶端動作信息及時反饋回服務器,通過服務器對這些動作信息進行有效認證后,再向客戶端發(fā)送下一步游戲動作信息,這樣動作模擬技術將失去原有的效應。為了更好地 外掛 這些游戲,游戲外掛程序也進行了升級換代,它們將以前針對游戲用戶界面層的模擬推進到數(shù)據(jù)通訊層,通過封包技術在客戶端擋截游戲服務器發(fā)送來的游戲控制數(shù)據(jù)包,分析數(shù)據(jù)包并修改數(shù)據(jù)包;同時還需按照游戲數(shù)據(jù)包結構創(chuàng)建數(shù)據(jù)包,再模擬客戶端發(fā)送給游戲服務器,這個過程其實就是一個封包的過程。
  封包的技術是實現(xiàn)第二類游戲外掛的最核心的技術。封包技術涉及的知識很廣泛,實現(xiàn)方法也很多,如擋截 WinSock 、擋截 API 函數(shù)、擋截消息、 VxD 驅動程序等。在此我們也不可能在此文中將所有的封包技術都進行詳細介紹,故選擇兩種在游戲外掛程序中最常用的兩種方法:擋截 WinSock 和擋截 API 函數(shù)。
   1  擋截WinSock
  眾所周知, Winsock Windows 網(wǎng)絡編程接口,它工作于 Windows 應用層,它提供與底層傳輸協(xié)議無關的高層數(shù)據(jù)傳輸編程接口。在 Windows 系統(tǒng)中,使用 WinSock 接口為應用程序提供基于 TCP/IP 協(xié)議的網(wǎng)絡訪問服務,這些服務是由 Wsock32.DLL 動態(tài)鏈接庫提供的函數(shù)庫來完成的。
  由上說明可知,任何 Windows 基于 TCP/IP 的應用程序都必須通過 WinSock 接口訪問網(wǎng)絡,當然網(wǎng)絡游戲程序也不例外。由此我們可以想象一下,如果我們可以控制 WinSock 接口的話,那么控制游戲客戶端程序與服務器之間的數(shù)據(jù)包也將易如反掌。按著這個思路,下面的工作就是如何完成控制 WinSock 接口了。由上面的介紹可知, WinSock 接口其實是由一個動態(tài)鏈接庫提供的一系列函數(shù),由這些函數(shù)實現(xiàn)對網(wǎng)絡的訪問。有了這層的認識,問題就好辦多了,我們可以制作一個類似的動態(tài)鏈接庫來代替原 WinSock 接口庫,在其中實現(xiàn) WinSock32.dll 中實現(xiàn)的所有函數(shù),并保證所有函數(shù)的參數(shù)個數(shù)和順序、返回值類型都應與原庫相同。在這個自制作的動態(tài)庫中,可以對我們感興趣的函數(shù)(如發(fā)送、接收等函數(shù))進行擋截,放入外掛控制代碼,最后還繼續(xù)調(diào)用原 WinSock 庫中提供的相應功能函數(shù),這樣就可以實現(xiàn)對網(wǎng)絡數(shù)據(jù)包的擋截、修改和發(fā)送等封包功能。
  下面重點介紹創(chuàng)建擋截 WinSock 外掛程序的基本步驟:
   (1)  創(chuàng)建 DLL 項目,選擇 Win32 Dynamic-Link Library ,再選擇 An empty DLL project
   (2)  新建文件 wsock32.h ,按如下步驟輸入代碼:
    加入相關變量聲明:
    HMODULE hModule=NULL; // 模塊句柄
    char buffer[1000]; // 緩沖區(qū)
    FARPROC proc; // 函數(shù)入口指針 
    定義指向原WinSock庫中的所有函數(shù)地址的指針變量,因WinSock庫共提供70多個函數(shù),限于篇幅,在此就只選擇幾個常用的函數(shù)列出,有關這些庫函數(shù)的說明可參考MSDN相關內(nèi)容。
    // 定義指向原 WinSock 庫函數(shù)地址的指針變量。
    SOCKET (__stdcall *socket1)(int ,int,int);// 創(chuàng)建 Sock 函數(shù)。
    int   (__stdcall *WSAStartup1)(WORD,LPWSADATA);// 初始化 WinSock 庫函數(shù)。
    int   (__stdcall *WSACleanup1)();// 清除 WinSock 庫函數(shù)。
    int (__stdcall *recv1)(SOCKET ,char FAR * ,int ,int );// 接收數(shù)據(jù)函數(shù)。
    int (__stdcall *send1)(SOCKET ,const char * ,int ,int);// 發(fā)送數(shù)據(jù)函數(shù)。
    int (__stdcall *connect1)(SOCKET,const struct sockaddr *,int);// 創(chuàng)建連接函數(shù)。
    int (__stdcall *bind1)(SOCKET ,const struct sockaddr *,int );// 綁定函數(shù)。
    ...... 其它函數(shù)地址指針的定義略。 
   (3)  新建 wsock32.cpp 文件,按如下步驟輸入代碼:
    加入相關頭文件聲明:
    #include <windows.h>
    #include <stdio.h>
    #include "wsock32.h" 
    添加DllMain函數(shù),在此函數(shù)中首先需要加載原WinSock庫,并獲取此庫中所有函數(shù)的地址。代碼如下:
    BOOL WINAPI DllMain (HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved)
    {
     if(hModule==NULL){
      // 加載原 WinSock 庫,原 WinSock 庫已復制為 wsock32.001
    hModule=LoadLibrary("wsock32.001"); 
   }
     else return 1;
//
獲取原 WinSock 庫中的所有函數(shù)的地址并保存,下面僅列出部分代碼。
if(hModule!=NULL){
      // 獲取原 WinSock 庫初始化函數(shù)的地址,并保存到 WSAStartup1 中。
proc=GetProcAddress(hModule,"WSAStartup");
    WSAStartup1=(int (_stdcall *)(WORD,LPWSADATA))proc;
      // 獲取原 WinSock 庫消除函數(shù)的地址,并保存到 WSACleanup1 中。
     proc=GetProcAddress(hModule i,"WSACleanup");
     WSACleanup1=(int (_stdcall *)())proc;
      // 獲取原創(chuàng)建 Sock 函數(shù)的地址,并保存到 socket1 中。
     proc=GetProcAddress(hModule,"socket");
      socket1=(SOCKET (_stdcall *)(int ,int,int))proc;
      // 獲取原創(chuàng)建連接函數(shù)的地址,并保存到 connect1 中。
      proc=GetProcAddress(hModule,"connect");
      connect1=(int (_stdcall *)(SOCKET ,const struct sockaddr *,int ))proc;
      // 獲取原發(fā)送函數(shù)的地址,并保存到 send1 中。
      proc=GetProcAddress(hModule,"send");
      send1=(int (_stdcall *)(SOCKET ,const char * ,int ,int ))proc;
      // 獲取原接收函數(shù)的地址,并保存到 recv1 中。
      proc=GetProcAddress(hModule,"recv");
      recv1=(int (_stdcall *)(SOCKET ,char FAR * ,int ,int ))proc;
      ...... 其它獲取函數(shù)地址代碼略。
    }
    else return 0;
    return 1;
    定義庫輸出函數(shù),在此可以對我們感興趣的函數(shù)中添加外掛控制代碼,在所有的輸出函數(shù)的最后一步都調(diào)用原WinSock庫的同名函數(shù)。部分輸出函數(shù)定義代碼如下:
// 庫輸出函數(shù)定義。
//WinSock
初始化函數(shù)。
     int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData)
     {
      // 調(diào)用原 WinSock 庫初始化函數(shù)
      return WSAStartup1(wVersionRequired,lpWSAData);
     }
     //WinSock 結束清除函數(shù)。
     int PASCAL FAR WSACleanup(void)
     {
      return WSACleanup1(); // 調(diào)用原 WinSock 庫結束清除函數(shù)。
     }
     // 創(chuàng)建 Socket 函數(shù)。
     SOCKET PASCAL FAR socket (int af, int type, int protocol)
     {
      // 調(diào)用原 WinSock 庫創(chuàng)建 Socket 函數(shù)。
      return socket1(af,type,protocol);
     }
     // 發(fā)送數(shù)據(jù)包函數(shù)
     int PASCAL FAR send(SOCKET s,const char * buf,int len,int flags)
     {
    // 在此可以對發(fā)送的緩沖 buf 的內(nèi)容進行修改,以實現(xiàn)欺騙服務器。
   外掛代碼 ......
    // 調(diào)用原 WinSock 庫發(fā)送數(shù)據(jù)包函數(shù)。
      return send1(s,buf,len,flags);
     }
//
接收數(shù)據(jù)包函數(shù)。
     int PASCAL FAR recv(SOCKET s, char FAR * buf, int len, int flags)
     {
    // 在此可以擋截到服務器端發(fā)送到客戶端的數(shù)據(jù)包,先將其保存到 buffer 中。
    strcpy(buffer,buf);
    // buffer 數(shù)據(jù)包數(shù)據(jù)進行分析后,對其按照玩家的指令進行相關修改。
   外掛代碼 ......
    // 最后調(diào)用原 WinSock 中的接收數(shù)據(jù)包函數(shù)。
      return recv1(s, buffer, len, flags);
      }
     ....... 其它函數(shù)定義代碼略。 
   (4) 、新建 wsock32.def 配置文件,在其中加入所有庫輸出函數(shù)的聲明,部分聲明代碼如下:
    LIBRARY "wsock32"
    EXPORTS 
     WSAStartup @1
    WSACleanup @2
     recv @3
     send @4
     socket @5
    bind @6
    closesocket @7
    connect @8 
    ...... 其它輸出函數(shù)聲明代碼略。
   (5) 、從 工程 菜單中選擇 設置 ,彈出 Project Setting 對話框,選擇 Link 標簽,在 對象 / 庫模塊 中輸入 Ws2_32.lib
   (6) 、編譯項目,產(chǎn)生 wsock32.dll 庫文件。
   (7) 、將系統(tǒng)目錄下原 wsock32.dll 庫文件拷貝到被外掛程序的目錄下,并將其改名為 wsock.001 ;再將上面產(chǎn)生的 wsock32.dll 文件同樣拷貝到被外掛程序的目錄下。重新啟動游戲程序,此時游戲程序將先加載我們自己制作的 wsock32.dll 文件,再通過該庫文件間接調(diào)用原 WinSock 接口函數(shù)來實現(xiàn)訪問網(wǎng)絡。上面我們僅僅介紹了擋載 WinSock 的實現(xiàn)過程,至于如何加入外掛控制代碼,還需要外掛開發(fā)人員對游戲數(shù)據(jù)包結構、內(nèi)容、加密算法等方面的仔細分析(這個過程將是一個艱辛的過程),再生成外掛控制代碼。關于數(shù)據(jù)包分析方法和技巧,不是本文講解的范圍,如您感興趣可以到網(wǎng)上查查相關資料。
   2. 擋截 API
  擋截 API 技術與擋截 WinSock 技術在原理上很相似,但是前者比后者提供了更強大的功能。擋截 WinSock 僅只能擋截 WinSock 接口函數(shù),而擋截 API 可以實現(xiàn)對應用程序調(diào)用的包括 WinSock API 函數(shù)在內(nèi)的所有 API 函數(shù)的擋截。如果您的外掛程序僅打算對 WinSock 的函數(shù)進行擋截的話,您可以只選擇使用上小節(jié)介紹的擋截 WinSock 技術。隨著大量外掛程序在功能上的擴展,它們不僅僅只提供對數(shù)據(jù)包的擋截,而且還對游戲程序中使用的 Windows API 或其它 DLL 庫函數(shù)的擋截,以使外掛的功能更加強大。例如,可以通過擋截相關 API 函數(shù)以實現(xiàn)對非中文游戲的漢化功能,有了這個利器,可以使您的外掛程序無所不能了。
  擋截 API 技術的原理核心也是使用我們自己的函數(shù)來替換掉 Windows 或其它 DLL 庫提供的函數(shù),有點同擋截 WinSock 原理相似吧。但是,其實現(xiàn)過程卻比擋截 WinSock 要復雜的多,如像實現(xiàn)擋截 Winsock 過程一樣,將應用程序調(diào)用的所有的庫文件都寫一個模擬庫有點不大可能,就只說 Windows API 就有上千個,還有很多庫提供的函數(shù)結構并未公開,所以寫一個模擬庫代替的方式不大現(xiàn)實,故我們必須另謀良方。
  擋截 API 的最終目標是使用自定義的函數(shù)代替原函數(shù)。那么,我們首先應該知道應用程序何時、何地、用何種方式調(diào)用原函數(shù)。接下來,需要將應用程序中調(diào)用該原函數(shù)的指令代碼進行修改,使它將調(diào)用函數(shù)的指針指向我們自己定義的函數(shù)地址。這樣,外掛程序才能完全控制應用程序調(diào)用的 API 函數(shù),至于在其中如何加入外掛代碼,就應需求而異了。最后還有一個重要的問題要解決,如何將我們自定義的用來代替原 API 函數(shù)的函數(shù)代碼注入被外掛游戲程序進行地址空間中,因在 Windows 系統(tǒng)中應用程序僅只能訪問到本進程地址空間內(nèi)的代碼和數(shù)據(jù)。
  綜上所述,要實現(xiàn)擋截 API 函數(shù),至少需要解決如下三個問題:
   ●  如何定位游戲程序中調(diào)用 API 函數(shù)指令代碼?
   ●  如何修改游戲程序中調(diào)用 API 函數(shù)指令代碼?
   ●  如何將外掛代碼(自定義的替換函數(shù)代碼)注入到游戲程序進程地址空間?
  下面我們逐一介紹這幾個問題的解決方法:
   (1)  、定位調(diào)用 API 函數(shù)指令代碼
  我們知道,在匯編語言中使用 CALL 指令來調(diào)用函數(shù)或過程的,它是通過指令參數(shù)中的函數(shù)地址而定位到相應的函數(shù)代碼的。那么,我們?nèi)绻軐ふ业匠绦虼a中所有調(diào)用被擋截的 API 函數(shù)的 CALL 指令的話,就可以將該指令中的函數(shù)地址參數(shù)修改為替代函數(shù)的地址。雖然這是一個可行的方案,但是實現(xiàn)起來會很繁瑣,也不穩(wěn)健。慶幸的是, Windows 系統(tǒng)中所使用的可執(zhí)行文件( PE 格式)采用了輸入地址表機制,將所有在程序調(diào)用的 API 函數(shù)的地址信息存放在輸入地址表中,而在程序代碼 CALL 指令中使用的地址不是 API 函數(shù)的地址,而是輸入地址表中該 API 函數(shù)的地址項,如想使程序代碼中調(diào)用的 API 函數(shù)被代替掉,只用將輸入地址表中該 API 函數(shù)的地址項內(nèi)容修改即可。具體理解輸入地址表運行機制,還需要了解一下 PE 格式文件結構,其中圖三列出了 PE 格式文件的大致結構。

  圖三: PE 格式大致結構圖 (003.jpg)
   PE 格式文件一開始是一段 DOS 程序,當你的程序在不支持 Windows 的環(huán)境中運行時,它就會顯示 “This Program cannot be run in DOS mode” 這樣的警告語句,接著這個 DOS 文件頭,就開始真正的 PE 文件內(nèi)容了。首先是一段稱為 “IMAGE_NT_HEADER” 的數(shù)據(jù),其中是許多關于整個 PE 文件的消息,在這段數(shù)據(jù)的尾端是一個稱為 Data Directory 的數(shù)據(jù)表,通過它能快速定位一些 PE 文件中段( section )的地址。在這段數(shù)據(jù)之后,則是一個 “IMAGE_SECTION_HEADER” 的列表,其中的每一項都詳細描述了后面一個段的相關信息。接著它就是 PE 文件中最主要的段數(shù)據(jù)了,執(zhí)行代碼、數(shù)據(jù)和資源等等信息就分別存放在這些段中。
  在所有的這些段里,有一個被稱為 “.idata” 的段(輸入數(shù)據(jù)段)值得我們?nèi)プ⒁猓摱沃邪恍┍环Q為輸入地址表( IAT Import Address Table )的數(shù)據(jù)列表。每個用隱式方式加載的 API 所在的 DLL 都有一個 IAT 與之對應,同時一個 API 的地址也與 IAT 中一項相對應。當一個應用程序加載到內(nèi)存中后,針對每一個 API 函數(shù)調(diào)用,相應的產(chǎn)生如下的匯編指令: 
   JMP DWORD PTR [XXXXXXXX] 
  或
   CALL DWORD PTR [XXXXXXXX]
  其中, [XXXXXXXX] 表示指向了輸入地址表中一個項,其內(nèi)容是一個 DWORD ,而正是這個 DWORD 才是 API 函數(shù)在內(nèi)存中的真正地址。因此我們要想攔截一個 API 的調(diào)用,只要簡單的把那個 DWORD 改為我們自己的函數(shù)的地址。
   (2)  、修改調(diào)用 API 函數(shù)代碼
  從上面對 PE 文件格式的分析可知,修改調(diào)用 API 函數(shù)代碼其實是修改被調(diào)用 API 函數(shù)在輸入地址表中 IAT 項內(nèi)容。由于 Windows 系統(tǒng)對應用程序指令代碼地址空間的嚴密保護機制,使得修改程序指令代碼非常困難,以至于許多高手為之編寫 VxD 進入 Ring0 。在這里,我為大家介紹一種較為方便的方法修改進程內(nèi)存,它僅需要調(diào)用幾個 Windows 核心 API 函數(shù),下面我首先來學會一下這幾個 API 函數(shù):
    DWORD VirtualQuery(
    LPCVOID lpAddress, // address of region
    PMEMORY_BASIC_INFORMATION lpBuffer, // information buffer
    DWORD dwLength // size of buffer
    ); 
  該函數(shù)用于查詢關于本進程內(nèi)虛擬地址頁的信息。其中, lpAddress 表示被查詢頁的區(qū)域地址; lpBuffer 表示用于保存查詢頁信息的緩沖; dwLength 表示緩沖區(qū)大小。返回值為實際緩沖大小。
    BOOL VirtualProtect(
    LPVOID lpAddress, // region of committed pages
    SIZE_T dwSize, // size of the region
    DWORD flNewProtect, // desired access protection
    PDWORD lpflOldProtect // old protection
    ); 
  該函數(shù)用于改變本進程內(nèi)虛擬地址頁的保護屬性。其中, lpAddress 表示被改變保護屬性頁區(qū)域地址; dwSize 表示頁區(qū)域大小; flNewProtect 表示新的保護屬性,可取值為 PAGE_READONLY PAGE_READWRITE PAGE_EXECUTE 等; lpflOldProtect 表示用于保存改變前的保護屬性。如果函數(shù)調(diào)用成功返回 “T” ,否則返回 “F”
  有了這兩個 API 函數(shù),我們就可以隨心所欲的修改進程內(nèi)存了。首先,調(diào)用 VirtualQuery() 函數(shù)查詢被修改內(nèi)存的頁信息,再根據(jù)此信息調(diào)用 VirtualProtect() 函數(shù)改變這些頁的保護屬性為 PAGE_READWRITE ,有了這個權限您就可以任意修改進程內(nèi)存數(shù)據(jù)了。下面一段代碼演示了如何將進程虛擬地址為 0x0040106c 處的字節(jié)清零。
    BYTE* pData = 0x0040106c;
    MEMORY_BASIC_INFORMATION mbi_thunk; 
    // 查詢頁信息。
    VirtualQuery(pData, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)); 
    // 改變頁保護屬性為讀寫。
    VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize, 
    PAGE_READWRITE, &mbi_thunk.Protect); 
    // 清零。
    *pData = 0x00;
    // 恢復頁的原保護屬性。
    DWORD dwOldProtect; 
    VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize, 
    mbi_thunk.Protect, &dwOldProtect); 
   (3) 、注入外掛代碼進入被掛游戲進程中
  完成了定位和修改程序中調(diào)用 API 函數(shù)代碼后,我們就可以隨意設計自定義的 API 函數(shù)的替代函數(shù)了。做完這一切后,還需要將這些代碼注入到被外掛游戲程序進程內(nèi)存空間中,不然游戲進程根本不會訪問到替代函數(shù)代碼。注入方法有很多,如利用全局鉤子注入、利用注冊表注入擋截 User32 庫中的 API 函數(shù)、利用 CreateRemoteThread 注入(僅限于 NT/2000 )、利用 BHO 注入等。因為我們在動作模擬技術一節(jié)已經(jīng)接觸過全局鉤子,我相信聰明的讀者已經(jīng)完全掌握了全局鉤子的制作過程,所以我們在后面的實例中,將繼續(xù)利用這個全局鉤子。至于其它幾種注入方法,如果感興趣可參閱 MSDN 有關內(nèi)容。
  有了以上理論基礎,我們下面就開始制作一個擋截 MessageBoxA recv 函數(shù)的實例,在開發(fā)游戲外掛程序 時,可以此實例為框架,加入相應的替代函數(shù)和處理代碼即可。此實例的開發(fā)過程如下:
   (1)  打開前面創(chuàng)建的 ActiveKey 項目。
   (2)  ActiveKey.h 文件中加入 HOOKAPI 結構,此結構用來存儲被擋截 API 函數(shù)名稱、原 API 函數(shù)地址和替代函數(shù)地址。
    typedef struct tag_HOOKAPI 
   
    LPCSTR szFunc;// HOOK API 函數(shù)名稱。
    PROC pNewProc;// 替代函數(shù)地址。
    PROC pOldProc;// API 函數(shù)地址。
    }HOOKAPI, *LPHOOKAPI; 
   (3)  打開 ActiveKey.cpp 文件,首先加入一個函數(shù),用于定位輸入庫在輸入數(shù)據(jù)段中的 IAT 地址。代碼如下:
    extern "C" __declspec(dllexport)PIMAGE_IMPORT_DESCRIPTOR 
    LocationIAT(HMODULE hModule, LPCSTR szImportMod) 
    // 其中, hModule 為進程模塊句柄; szImportMod 為輸入庫名稱。
   
    // 檢查是否為 DOS 程序,如是返回 NULL ,因 DOS 程序沒有 IAT
    PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule; 
    if(pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) return NULL; 
     // 檢查是否為 NT 標志,否則返回 NULL
     PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader+ (DWORD)(pDOSHeader->e_lfanew)); 
     if(pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; 
     // 沒有 IAT 表則返回 NULL
     if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0) return NULL; 
     // 定位第一個 IAT 位置。  
     PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDOSHeader + (DWORD)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); 
     // 根據(jù)輸入庫名稱循環(huán)檢查所有的 IAT ,如匹配則返回該 IAT 地址,否則檢測下一個 IAT
     while (pImportDesc->Name) 
    
      // 獲取該 IAT 描述的輸入庫名稱。
    PSTR szCurrMod = (PSTR)((DWORD)pDOSHeader + (DWORD)(pImportDesc->Name)); 
    if (stricmp(szCurrMod, szImportMod) == 0) break; 
    pImportDesc++; 
    
     if(pImportDesc->Name == NULL) return NULL; 
    return pImportDesc; 
   
  再加入一個函數(shù),用來定位被擋截 API 函數(shù)的 IAT 項并修改其內(nèi)容為替代函數(shù)地址。代碼如下:
    extern "C" __declspec(dllexport) 
    HookAPIByName( HMODULE hModule, LPCSTR szImportMod, LPHOOKAPI pHookApi) 
    // 其中, hModule 為進程模塊句柄; szImportMod 為輸入庫名稱; pHookAPI HOOKAPI 結構指針。
   
     // 定位 szImportMod 輸入庫在輸入數(shù)據(jù)段中的 IAT 地址。
     PIMAGE_IMPORT_DESCRIPTOR pImportDesc = LocationIAT(hModule, szImportMod); 
   if (pImportDesc == NULL) return FALSE; 
     // 第一個 Thunk 地址。
     PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->OriginalFirstThunk)); 
    // 第一個 IAT 項的 Thunk 地址。
     PIMAGE_THUNK_DATA pRealThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->FirstThunk)); 
     // 循環(huán)查找被截 API 函數(shù)的 IAT 項,并使用替代函數(shù)地址修改其值。
    while(pOrigThunk->u1.Function) 

  // 檢測此 Thunk 是否為 IAT 項。
if((pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG) 
{
   // 獲取此 IAT 項所描述的函數(shù)名稱。
  PIMAGE_IMPORT_BY_NAME pByName =(PIMAGE_IMPORT_BY_NAME)((DWORD)hModule+(DWORD)(pOrigThunk->u1.AddressOfData)); 
  if(pByName->Name[0] == ‘\\0‘) return FALSE; 
   // 檢測是否為擋截函數(shù)。
if(strcmpi(pHookApi->szFunc, (char*)pByName->Name) == 0) 
   { 
        MEMORY_BASIC_INFORMATION mbi_thunk;
        // 查詢修改頁的信息。
        VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)); 
//
改變修改頁保護屬性為 PAGE_READWRITE
        VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect); 
//
保存原來的 API 函數(shù)地址。
      if(pHookApi->pOldProc == NULL) 
pHookApi->pOldProc = (PROC)pRealThunk->u1.Function; 
  //修改API函數(shù)IAT項內(nèi)容為替代函數(shù)地址。
pRealThunk->u1.Function = (PDWORD)pHookApi->pNewProc; 
//
恢復修改頁保護屬性。
DWORD dwOldProtect; 
       VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect); 
      } 

  pOrigThunk++; 
  pRealThunk++; 

  SetLastError(ERROR_SUCCESS); //設置錯誤為ERROR_SUCCESS,表示成功。
  return TRUE; 
   
   (4)  定義替代函數(shù),此實例中只給 MessageBoxA recv 兩個 API 進行擋截。代碼如下:
    static int WINAPI MessageBoxA1 (HWND hWnd , LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
    {
     // 過濾掉原 MessageBoxA 的正文和標題內(nèi)容,只顯示如下內(nèi)容。
return MessageBox(hWnd, "Hook API OK!", "Hook API", uType); 
   
    static int WINAPI recv1(SOCKET s, char FAR *buf, int len, int flags )
    {
    // 此處可以擋截游戲服務器發(fā)送來的網(wǎng)絡數(shù)據(jù)包,可以加入分析和處理數(shù)據(jù)代碼。
    return recv(s,buf,len,flags);
   
   (5)  KeyboardProc 函數(shù)中加入激活擋截 API 代碼,在 if( wParam == 0X79 ) 語句中后面加入如下 else if 語句:
    ......
    // 當激活 F11 鍵時,啟動擋截 API 函數(shù)功能。
    else if( wParam == 0x7A )
   
     HOOKAPI api[2];
api[0].szFunc ="MessageBoxA";//
設置被擋截函數(shù)的名稱。
api[0].pNewProc = (PROC)MessageBoxA1;//
設置替代函數(shù)的地址。
api[1].szFunc ="recv";//
設置被擋截函數(shù)的名稱。
api[1].pNewProc = (PROC)recv1; //
設置替代函數(shù)的地址。
//
設置擋截 User32.dll 庫中的 MessageBoxA 函數(shù)。
HookAPIByName(GetModuleHandle(NULL),"User32.dll",&api[0]);
//
設置擋截 Wsock32.dll 庫中的 recv 函數(shù)。
HookAPIByName(GetModuleHandle(NULL),"Wsock32.dll",&api[1]);
    }
    ...... 
   (6)  ActiveKey.cpp 中加入頭文件聲明  "#include "wsock32.h"  工程菜單中選擇設置,彈出Project Setting對話框,選擇Link標簽,在對象/庫模塊中輸入Ws2_32..lib
   (7)  重新編譯 ActiveKey 項目,產(chǎn)生 ActiveKey.dll 文件,將其拷貝到 Simulate.exe 目錄下。運行 Simulate.exe 并啟動全局鉤子。激活任意應用程序,按 F11 鍵后,運行此程序中可能調(diào)用 MessageBoxA 函數(shù)的操作,看看信息框是不是有所變化。同樣,如此程序正在接收網(wǎng)絡數(shù)據(jù)包,就可以實現(xiàn)封包功能了。
posted on 2007-04-28 15:56 Xiao.Zhu 閱讀(758) 評論(0)  編輯 收藏 引用
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久久一区二区三区四区| 欧美亚洲视频一区二区| 国语自产精品视频在线看8查询8| 久久久久久高潮国产精品视| 国产女优一区| 欧美特黄视频| 老司机67194精品线观看| 亚洲缚视频在线观看| 欧美综合国产| 欧美三级视频在线| 欧美高清视频免费观看| 亚洲一二三四久久| 亚洲一区二区视频| 亚洲视频免费在线| 一区二区高清在线观看| 99国产精品久久久久老师| 亚洲高清视频中文字幕| 国产精品video| 国产精品久久久久99| 欧美日韩在线一区二区三区| 欧美日韩一区二区视频在线 | 洋洋av久久久久久久一区| 久久国产精品72免费观看| 欧美精品一区二区三区蜜桃| 国产精品自拍小视频| 日韩一区二区免费高清| 美女久久网站| 亚洲免费在线电影| 久久久欧美精品sm网站| 国产亚洲欧美激情| 欧美一区二区视频免费观看| 亚洲片在线观看| 久久久免费精品视频| 亚洲电影第1页| 美女久久网站| 欧美xxxx在线观看| 91久久中文字幕| 亚洲国产高清一区二区三区| 久久综合精品国产一区二区三区| 亚洲欧美激情精品一区二区| 久久亚洲电影| 老色批av在线精品| 亚洲三级电影全部在线观看高清| 美国成人毛片| 欧美xxx在线观看| 一区二区三区日韩欧美| 亚洲午夜一区| 欧美午夜精品| 国产美女精品一区二区三区| 国产精品一区二区久久精品| 久久精品一级爱片| 久久久亚洲综合| 99re热这里只有精品免费视频| 亚洲精品一区在线观看| 国产欧美日韩91| 欧美成人国产va精品日本一级| 欧美成人高清| 午夜精品久久久久久久白皮肤| 久久亚洲精品网站| 香蕉视频成人在线观看| 男同欧美伦乱| 久久综合色综合88| 国产精品美女一区二区| 欧美大片在线看| 国产欧美日韩精品丝袜高跟鞋| 欧美成人一区二区在线| 国产日韩欧美中文在线播放| 亚洲美女精品久久| 韩国一区二区在线观看| 亚洲午夜在线视频| 日韩一二三在线视频播| 久久精品一区蜜桃臀影院| 亚洲视频精品| 欧美日韩一区二区三区免费 | 国产精品青草综合久久久久99| 久久国产手机看片| 欧美一区二区大片| 国产一区二区三区成人欧美日韩在线观看 | 欧美在线电影| 久久久久综合网| 亚洲天堂成人在线观看| 午夜精品国产更新| 国产九九精品视频| 久久国产精彩视频| 欧美高清视频免费观看| 亚洲精品美女91| 国产精品都在这里| 亚洲一区二区三区四区中文| 欧美一区免费| 亚洲精品日韩综合观看成人91| 欧美日韩无遮挡| 久久狠狠久久综合桃花| 91久久精品国产91性色tv| 亚洲视频福利| 亚洲精品中文字幕女同| 国产区亚洲区欧美区| 欧美高清在线视频| 亚洲免费一区二区| 欧美电影在线观看| 久久爱www久久做| 一区二区三区黄色| 亚洲高清在线播放| 国产亚洲精品成人av久久ww| 欧美激情综合| 老司机免费视频一区二区三区 | 午夜在线不卡| a4yy欧美一区二区三区| 在线免费不卡视频| 国产亚洲毛片在线| 亚洲成人在线视频网站| 欧美一区2区视频在线观看| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 久久精品一区二区国产| 国产精品99久久久久久久久| 亚洲电影免费在线| 久久精品女人天堂| 亚洲小说欧美另类社区| 夜夜精品视频| 亚洲一区二区免费看| 这里只有精品视频在线| 亚洲免费人成在线视频观看| 香蕉乱码成人久久天堂爱免费 | 亚洲韩国日本中文字幕| 欧美国产日韩精品免费观看| 亚洲国产一区二区三区a毛片| 久久久精品一区二区三区| 久久免费黄色| 午夜老司机精品| 国产农村妇女毛片精品久久莱园子| 日韩午夜三级在线| 伊人久久成人| 欧美激情一区二区三区在线视频观看 | 久热精品在线视频| 亚洲午夜羞羞片| 国产欧美日韩亚洲精品| 久久精品官网| 欧美亚洲一区| 久久九九99视频| 亚洲国产日韩在线| 亚洲婷婷在线| 欧美黑人国产人伦爽爽爽| 亚洲国产一区二区三区在线播 | 亚洲无毛电影| 欧美激情一区二区三区蜜桃视频 | 亚洲美女黄色片| 亚洲午夜小视频| 亚洲国产精品一区在线观看不卡 | 亚洲欧洲日产国产综合网| 亚洲欧美激情一区二区| 久久久久国色av免费看影院| 国产精品社区| 亚洲欧美精品在线观看| 在线亚洲欧美视频| 老牛影视一区二区三区| 红桃视频成人| 免费视频一区二区三区在线观看| 日韩一级大片在线| 欧美精品一区二区精品网| 亚洲欧洲在线视频| 亚洲国产精品一区二区三区| 久久男人资源视频| 黄色成人av| 欧美大片免费观看| 老司机精品视频一区二区三区| 伊人成年综合电影网| 免费在线成人| 欧美大片在线观看| 亚洲午夜精品视频| 亚洲色图制服丝袜| 国产欧美 在线欧美| 久久精品国产欧美激情| 免费在线国产精品| 亚洲淫性视频| 久久综合给合久久狠狠色| 亚洲国产高清一区二区三区| 99re热这里只有精品视频| 国产欧美精品xxxx另类| 欧美国产视频一区二区| 一区二区欧美视频| 国内精品久久久| 亚洲日本成人| 在线精品视频在线观看高清 | 久久久久久久激情视频| 久久一二三四| 久久婷婷久久| 国产伦一区二区三区色一情| 亚洲日本中文| 亚洲精品日韩在线| 欧美α欧美αv大片| 免费一级欧美片在线观看| 国产日韩一区二区| 亚洲一区二区在线看| 亚洲美女精品久久| 欧美成人精品福利| 狂野欧美性猛交xxxx巴西| 国产一区二区三区高清| 亚洲免费视频一区二区| 欧美一区二区三区四区视频 | 亚洲自拍偷拍福利| 亚洲精选国产|