万王之王 KOK King of Kings

 找回密码
 加入我们
查看: 795|回复: 1

关于向游戏远程注入外挂代码样例

[复制链接]
发表于 2010-6-27 11:57 | 显示全部楼层 |阅读模式
将这些代码注入到被外挂游戏程序进程内存空间中,不然游戏进程根本不会访问到替代函数代码。注入方法有很多,如利用全局钩子注入、利用注册表注入挡截user32库中的api函数、利用createremotethread注入(仅限于 nt/2000)、利用bho注入等。在后面的实例中,将继续利用这个全局钩子。至于其它几种注入方法,如果感兴趣可参阅msdn有关内容。
  有了以上理论基础,下面就开始制作一个挡截messageboxa和recv函数的实例,在开发游戏外挂程序 时,可以此实例为框架,加入相应的替代函数和处理代码即可。此实例的开发过程如下:

  (1) 打开前面创建的activekey项目。

  (2) 在activekey.h文件中加入hookapi结构,此结构用来存储被挡截api函数名称、原api函数地址和替代函数地址。

   typedef struct tag_hookapi
   {
   lpcstr szfunc;//被hook的api函数名称。
   proc pnewproc;//替代函数地址。
   proc poldproc;//原api函数地址。
   }hookapi, *lphookapi;

  (3) 打开activekey.cpp文件,首先加入一个函数,用于定位输入库在输入数据段中的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));
    //根据输入库名称循环检查所有的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;
   }

  再加入一个函数,用来定位被挡截api函数的iat项并修改其内容为替代函数地址。代码如下:

   extern "c" __declspec(dllexport)
   hookapibyname( hmodule hmodule, lpcstr szimportmod, lphookapi phookapi)
   //其中,hmodule为进程模块句柄;szimportmod为输入库名称;phookapi为hookapi结构指针。
   {
    //定位 szimportmod输入库在输入数据段中的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));
    //循环查找被截api函数的iat项,并使用替代函数地址修改其值。
   while(porigthunk->u1.function)
{
 //检测此thunk是否为 iat项。
if((porigthunk->u1.ordinal & image_ordinal_flag) != image_ordinal_flag)
{
  //获取此iat项所描述的函数名称。
  pimage_import_by_name pbyname =(pimage_import_by_name)((dword)hmodule+(dword)(porigthunk->u1.addressofdata));
 if(pbyname->name[0] == '\0') return false;
  //检测是否为挡截函数。
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函数地址。
      if(phookapi->poldproc == null)
phookapi->poldproc = (proc)prealthunk->u1.function;
  //修改api函数iat项内容为替代函数地址。
prealthunk->u1.function = (pdword)phookapi->pnewproc;
//恢复修改页保护属性。
dword dwoldprotect;
       virtualprotect(mbi_thunk.baseaddress, mbi_thunk.regionsize, mbi_thtnk.protecu, &dwoldprotect);
      }
}
  porigthunk++;
  prealthunk++;
}
   setlasterror(error_success); //设置错误为error_success,表示成功。
  return true;
   }

  (4) 定义替代函数,此实例中只给messageboxa和recv两个api进行挡截。代码如下:

   static int winapi messageboxa1 (hwnd hwnd , lpctstr lptext, lpctstr lpcaption, uint utype)
   {
    //过滤掉原messageboxa的正文和标题内容,只显示如下内容。
return messagebox(hwnd, "hook api ok!", "hook api", utype);
   }
   static int winapi recv1(socket s, char far *buf, int len, int flags )
   {
   //此处可以挡截游戏服务器发送来的网络数据包,可以加入分析和处理数据代码。
    return recv(s,buf,len,flags);
   }

  (5) 在keyboardproc函数中加入激活挡截api代码,在if( wparam == 0x79 )语句中后面加入如下else if语句:

   ......
   //当激活f11键时,启动挡截api函数功能。
   else if( wparam == 0x7a )
   {
    hookapi api[2];
api[0].szfunc ="messageboxa";//设置被挡截函数的名称。
api[0].pnewproc = (proc)messageboxa1;//设置替代函数的地址。
api[1].szfunc ="recv";//设置被挡截函数的名称。
api[1].pnewproc = (proc)recv1; //设置替代函数的地址。
//设置挡截user32.dll库中的messageboxa函数。
hookapibyname(getmodulehandle(null),"user32.dll",&api[0]);
// 设置挡截wsock32.dll库中的recv函数。
hookapibyname(getmodulehandle(null),"wsock32.dll",&api[1]);
   }
   ......

  (6) 在activekey.cpp中加入头文件声明 "#include "wsock32.h"。 从“工程”菜单中选择“设置”,弹出project setting对话框,选择link标签,在“对象/库模块”中输入ws2_32..lib。

  (7) 重新编译activekey项目,产生activekey.dll文件,将其拷贝到simulate.exe目录下。运行simulate.exe并启动全局钩子。激活任意应用程序,按f11键后,运行此程序中可能调用messageboxa函数的操作,看看信息框是不是有所变化。同样,如此程序正在接收网络数据包,就可以实现封包功能了。
发表于 2013-3-9 09:54 | 显示全部楼层
这游戏好玩吗
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

小黑屋|手机版|万王之王 king of kings

GMT+8, 2024-4-21 00:17

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表