|| 您现在的位置: 天下无挂网 >> 外挂文章 >> 游戏外挂制作 >> 外挂文章正文
:: 用户登录 ::

 
:: 专 题 栏 目 ::
:: 最新热门 ::
  • 没有热门外挂文章
  • :: 相关文章 ::
  • 协议型网络游戏外挂制作

  • 协议型网络游戏外挂制作之APIHOOK
    作者:不详 文章来源:不详 点击数: 更新时间:2005-8-19

        上一节中我们说了外挂平台的搭建,我们做完了Hook.dll和wg.exe,但如何让wg.exe调用Hook.dll中的函数,可以自己查
    看CB的教程或者到网上查查。在这里我是在wg.exe的Hook按钮事件中添加了下面的语句来实现:

    if(gamethreadid)
    {
     if(EnableHook(gamethreadid)==false)
      ShowMessage("error");

      你可以点击Hook按钮在游戏界面出来之后,然后在游戏界面中按F12键调出外挂的窗口。

      昨天的尾巴完事之后,开始今天的教程。今天我想说说APIHOOK。虽然APIHOOK在大话游戏的外挂制作中不是必须的,但为了按照一般的制作流程顺序,就先将这部分加入到里面去了。

      使用APIHOOK的原因也很简单,游戏肯定要调用某些系统函数,使用APIHOOK可以简单的查看一些关键的信息并进行修改(就这么简单的理由?是的,我们一向再用杀牛的刀宰鸡的。。。)。

      Jeffrey Richter用了大量的篇幅来讲如何插入DLL和挂接API,如果你不知道Jeffrey Richter是谁的话,总该知道《Windows核心编程》的作者吧,如果不知道,我倒,系统抛出例外,你是外星人吧。我们的程序运行在用户层上,J。R提出了两种办法,一种是改写代码,我刚开始也试图用这种办法,后来发现这种办法确实存在的漏洞多多,和J。R说的一
    样。最后还是采用操作模块的输入节了。

      在查看资料的过程中,我发现J。R的代码在中文Windows 2000上并不能运行(难道是外国人用的系统和中国的不一样?),后来只好J。R的思路,重新安排了一下函数,但大部分函数都一样的。为了方便,我没有在类中捕获LoadLibraryA、LoadLibraryW、LoadLibraryExA和LoadLibraryExW,也是因为我们的外挂程序运行的时候游戏的窗口已经出来了,该加载的一般都加载了。

      下面是我的APIHOOK类的源代码,该源代码是根据J.R的思路重新整理他的源代码来的:

    /*HookAPI.h*/
    #include "windows.h" 
    class CAPIHOOK
    {
     public:
      CAPIHOOK(PSTR pszCalleeModName,PSTR pszFuncName,PROC pfnHook,HANDLE prochandle,HMODULE hmod);
      ~CAPIHOOK();
      operator PROC(){return (m_pfnOrig);};
     public:
      static PVOID sm_pvMaxAppAddr;
      static CAPIHOOK* sm_pHead;
      CAPIHOOK* m_pNext;
      PCSTR m_pszCalleeModName;
      PCSTR m_pszFuncName;
      PROC m_pfnOrig;
      PROC m_pfnHook;
      BOOL m_fExcludeAPIHookMod;
      HMODULE m_module;
      HANDLE m_handle;
     private:
      pfnOrig,PROC pfnHook,BOOL fExcludeAPIHookMod);
      void WINAPI ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnOrig,PROC pfnHook,HMODULE
    hmodcaller,HANDLE handle);
      void WINAPI FixupNewlyLoadedModule(HMODULE hmod,DWORD dwFlags);
      FARPROC WINAPI GetProcAddress(HMODULE hmod,PCSTR pszProcName);
    };

    /*HookApi.cpp*/

    #include "hookapi.h"
    #include <assert.h>
    #include "imagehlp.h"
    PVOID CAPIHOOK::sm_pvMaxAppAddr = NULL;
    const BYTE cPushOpCode = 0x68;
    CAPIHOOK *CAPIHOOK::sm_pHead = NULL;

    CAPIHOOK::CAPIHOOK(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook,
    HANDLE prochandle, HMODULE hmod)
    {
     m_handle = prochandle;
     if (sm_pvMaxAppAddr == NULL)
     {
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      sm_pvMaxAppAddr = si.lpMaximumApplicationAddress;
     }
     m_pNext = sm_pHead;
     sm_pHead = this;
     m_pszCalleeModName = pszCalleeModName;
     m_pszFuncName = pszFuncName;
     m_pfnHook = pfnHook;
     m_pfnOrig = ::GetProcAddress(GetModuleHandleA(pszCalleeModName),m_pszFuncName);
     assert(m_pfnOrig != NULL);
     if (m_pfnOrig == NULL)
     {
      return;
     }
     if (m_pfnOrig > sm_pvMaxAppAddr)
     {
      PBYTE pb = (PBYTE)m_pfnOrig;
      if (pb[0] == cPushOpCode)
      {
       PVOID pv = *(PVOID*) &pb[1];
       m_pfnOrig = (PROC)pv;
      }
     }
     m_module = GetModuleHandle(pszCalleeModName);
     ReplaceIATEntryInOneMod(m_pszCalleeModName, m_pfnOrig, m_pfnHook, m_module,prochandle);
    }

    CAPIHOOK::~CAPIHOOK()
    {
     ReplaceIATEntryInOneMod(m_pszCalleeModName, m_pfnHook, m_pfnOrig, m_module,m_handle);
     CAPIHOOK *p = sm_pHead;
     if (p == this)
     {
      sm_pHead = p->m_pNext;
     }
     else
     {
      BOOL fFound = FALSE;
      for (; !fFound && (p->m_pNext != NULL); p = p->m_pNext)
      {
       if (p->m_pNext == this)
       {
        p->m_pNext = p->m_pNext->m_pNext;
        break;
       }
      }
      assert(fFound);
     }
    }

    void WINAPI CAPIHOOK::FixupNewlyLoadedModule(HMODULE hmod, DWORD dwFlags)
    {
     if ((hmod != NULL) && ((dwFlags &LOAD_LIBRARY_AS_DATAFILE) == 0))
     {
      for (CAPIHOOK *p = sm_pHead; p != NULL; p = p->m_pNext)
      {
       ReplaceIATEntryInOneMod(p->m_pszCalleeModName, p->m_pfnOrig, p->m_pfnHook,hmod, m_handle);
      }
     }
    }

    FARPROC WINAPI CAPIHOOK::GetProcAddress(HMODULE hmod, PCSTR pszProcName)
    {
     FARPROC pfn = ::GetProcAddress(hmod, pszProcName);
     CAPIHOOK *p = sm_pHead;
     for (; (pfn != NULL) && (p != NULL); p = p->m_pNext)
     {
      if (pfn == p->m_pfnOrig)
      {
       pfn = p->m_pfnHook;
       break;
      }
     }
     return (pfn);
    }

    void WINAPI CAPIHOOK::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, PROC
    pfnCurrent, PROC pfnHook, HMODULE hmodcaller, HANDLE handle)
    {
     ULONG ulSize;

     PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
     ImageDirectoryEntryToData(hmodcaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
     if (pImportDesc == NULL)
     {
      return ;
     }

     for (; pImportDesc->Name; pImportDesc++)
     {
      PSTR pszModName = (PSTR)((PBYTE)hmodcaller + pImportDesc->Name);
      if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
      {
       break;
      }
     }
     if (pImportDesc->Name == 0)
     {
      return ;
     }
     PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hmodcaller +
     pImportDesc->FirstThunk);
     for (; pThunk->u1.Function; pThunk++)
     {
      PROC *ppfn = (PROC*) &pThunk->u1.Function;
      BOOL fFound = (*ppfn == pfnCurrent);
      if (!fFound && (*ppfn > sm_pvMaxAppAddr))
      {
       PBYTE pbInFunc = (PBYTE) *ppfn;
       if (pbInFunc[0] == cPushOpCode)
       {
        ppfn = (PROC*) &pbInFunc[1];
        fFound = (*ppfn == pfnCurrent);
       }
      }
      if (fFound)
      {
       HANDLE handle1 = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
       GetCurrentProcessId());
       DWORD dwIdOld;
       VirtualProtectEx(handle1, ppfn, sizeof(pfnHook), PAGE_READWRITE, &dwIdOld);
       if (WriteProcessMemory(handle1, ppfn, &pfnHook, sizeof(pfnHook), NULL) == false)
       {
        return ;
       } 
       else
       { 
        VirtualProtectEx(handle1, ppfn, sizeof(pfnHook), dwIdOld, &dwIdOld);
        return ;
       }
      }
     }

      上面是APIHOOK的完整代码。下面是使用的例子(拦截WString2ID函数):

    typedef unsigned long(__stdcall *WString2ID)(char const*);
    unsigned long __stdcall myWString2ID(char const*);
    CAPIHOOK *My_WString2ID;
    My_WString2ID = new CAPIHOOK("windsoul.dll", "?WString2ID@@YGKPBD@Z",
    (PROC)myWString2ID, gamehandle, gameInstance); 
        自己的myWString2ID的实现:

    unsigned long __stdcall myWString2ID(char const *a)
    {
     // SendMessage(wghandle,WM_USER+1,(WPARAM)a,NULL);
     return (((WString2ID)My_WString2ID->m_pfnOrig)(a));

      下面是用来拦截游戏的WndProc函数的,当时写的时候为了全面,至于如何去用,随便自己了,反正我没有用。

    gamehWnd = GetActiveWindow();
    gamehandle =GetCurrentProcess();
    gameInstance = (HINSTANCE)GetWindowLong(gamehWnd, GWL_HINSTANCE);
    gameproc = (WNDPROC)SetWindowLong(gamehWnd, GWL_WNDPROC, (LONG) MyMsgProc); 

      自己用来替换游戏的WndProc函数:

    LRESULT APIENTRY MyMsgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
    lParam)
    {
     /*在这里做自己想做的事情,剩下的让游戏的WndProc来处理*/
     return CallWindowProc(gameproc, hwnd, message, wParam, lParam);

      这一节到这里就结束了,下一节开始游戏程序的研究。最好准备大话客户端9.16更新之前的最后一个版本,不使用最新的版本有下面的原因:

      1、 如果对现在客户端作过多的透漏的话,将会发现做盗号类的程序比做外挂要简单,这不是我所希望看到的。

      2、 新版本采用的加密办法(双精度浮点数加密)在讲解上非常的麻烦,不是一般人容易入门的,但解决的办法和9.16之前的版本一样,只是繁琐而以。

      3、 脱壳后的程序有更多的需要人工识别的部分,这会造成不必要的麻烦,免得误导大家。

    外挂文章录入:admin    责任编辑:admin 
  • 上一篇外挂文章:

  • 下一篇外挂文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口

    点击申请点击申请点击申请点击申请点击申请点击申请
    点击申请点击申请点击申请点击申请点击申请点击申请点击申请

    版权所有 Copyright? 2004-2008 天下无挂科技网 网站维护:GHOST
    网站域名:http://www.watxwg.com
    客服邮箱:txwgwa@163.com
    客服电话:13810978321
    客服 Q Q:12439470