Chinaunix首页 | 论坛 | 博客
  • 博客访问: 16498225
  • 博文数量: 5645
  • 博客积分: 9880
  • 博客等级: 中将
  • 技术积分: 68081
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-28 13:35
文章分类

全部博文(5645)

文章存档

2008年(5645)

我的朋友

分类:

2008-04-28 21:32:25

下载本文示例代码
  上一节中我们说了外挂平台的搭建,我们做完了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 #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, PROCpfnCurrent, 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, LPARAMlParam){ /*在这里做自己想做的事情,剩下的让游戏的WndProc来处理*/ return CallWindowProc(gameproc, hwnd, message, wParam, lParam);}  这一节到这里就结束了,下一节开始游戏程序的研究。最好准备大话客户端9.16更新之前的最后一个版本,不使用最新的版本有下面的原因:  1、 如果对现在客户端作过多的透漏的话,将会发现做盗号类的程序比做外挂要简单,这不是我所希望看到的。  2、 新版本采用的加密办法(双精度浮点数加密)在讲解上非常的麻烦,不是一般人容易入门的,但解决的办法和9.16之前的版本一样,只是繁琐而以。  3、 脱壳后的程序有更多的需要人工识别的部分,这会造成不必要的麻烦,免得误导大家。  如果因为本教程引起其他的后果的话,则与本人无关,本人只讲技术实现。如果要转贴的话,请注明出处,如果有疑问或者商议的话,请发E-Mail到zeze0556@sina.com或者QQ:23033206留言,MSN:zeze0556@msn.com。另外请勿给我信箱发垃圾邮件,在添加好友的时候一定要写好附言,我已经被莫名其妙的广告信件和流言蜚语吓得没有胆了。算是我求各位大虾了   上一节中我们说了外挂平台的搭建,我们做完了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 #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, PROCpfnCurrent, 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, LPARAMlParam){ /*在这里做自己想做的事情,剩下的让游戏的WndProc来处理*/ return CallWindowProc(gameproc, hwnd, message, wParam, lParam);}  这一节到这里就结束了,下一节开始游戏程序的研究。最好准备大话客户端9.16更新之前的最后一个版本,不使用最新的版本有下面的原因:  1、 如果对现在客户端作过多的透漏的话,将会发现做盗号类的程序比做外挂要简单,这不是我所希望看到的。  2、 新版本采用的加密办法(双精度浮点数加密)在讲解上非常的麻烦,不是一般人容易入门的,但解决的办法和9.16之前的版本一样,只是繁琐而以。  3、 脱壳后的程序有更多的需要人工识别的部分,这会造成不必要的麻烦,免得误导大家。  如果因为本教程引起其他的后果的话,则与本人无关,本人只讲技术实现。如果要转贴的话,请注明出处,如果有疑问或者商议的话,请发E-Mail到zeze0556@sina.com或者QQ:23033206留言,MSN:zeze0556@msn.com。另外请勿给我信箱发垃圾邮件,在添加好友的时候一定要写好附言,我已经被莫名其妙的广告信件和流言蜚语吓得没有胆了。算是我求各位大虾了 下载本文示例代码


协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK协议型网络游戏外挂制作之APIHOOK
阅读(144) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~