C++外挂制作第四课【转】

社区服务
高级搜索
猴岛论坛辅助工具C++外挂制作第四课【转】
发帖 回复
正序阅读 最近浏览的帖子最近浏览的版块
1个回复

C++外挂制作第四课【转】

楼层直达
ゅ兔子哥

ZxID:2998095

等级: 上将
配偶: 老白兔。
音速图标啊图标6级7R!

举报 只看楼主 使用道具 楼主   发表于: 2009-06-14 0
大家耐心点,马上就完了。



环境: Windows XP SP2  ,Borland C++ Builder 平台下编译通过
对象目标: 网络游戏  武林外传

上一节只是说到从颜色方面入手做挂,这一节开始讲从分析游戏内存做挂。
武林外传游戏进程 elementclient.exe  没有加壳,这对我们分析有很大的好处。可以用CE分析游戏内存,也可以用OD 调试游戏。
CE 全名 Cheat Engine  ,是一款强大的分析游戏内存的工具,当然也有其他工具,不过我只熟悉这个,呵呵。
OD 全名 Ollydbg  ,一款调试工具。我们用它可以分析游戏的Call 和一些偏移等。

CE的用法,大家可以到广海游戏上看详细教程,这里就不贴上了,地址是
http://www.ghoffice.com/bbs/thread.php?fid-74-search--orderway-lastpost-asc-DESC-page-1.html
其实广海上面有很多高手的帖子和一些经验方法帖,还有很多教程帖,新手们可以从那里起步学习基础分析与制作,告诉大家哈,我也是从那里开始的,呵呵。
因为我们这里只是讲外挂制作,分析的地方很少,所以大部分的分析,我只是简单的带过,如果需要详细的资料,可以到广海上搜索一下,很多的。

如何设计一个外挂,对很多新手想必都是一个头疼的问题,除了一开始要大量的分析外,程序制作部分也是一个难关。那么多编译工具,该选择哪一款呢,这里,我推荐初学者选择VB ,有一定基础的可以直接选择C++ ,其中Borland C++ Builder 就是一个不错的编译工具。使用方法和VB一样简单。而VC++ 则是需要熟悉界面的制作才推荐选择。VB 版的武林助手源码以前发过,这里就不再发了,我们直接用C++ 开始制作新版的挂,也就是武林小秘。

假设前提我们已经得到了足够的信息和资料,例如基址,偏移等。
那么我们开始来试着读取一个偏移地址,例如人物的血值。
读取武林172版人物血值,首先打开BCB,开启后都会自动建立一个新的工程,我们就不新建了,在控件栏出选择按钮,在窗口里画出一个合适大小的按钮来,再选择Lable控件,照样画在窗口上,双击按钮,进入按钮代码部分。
想要读取其他进程的信息,我们首先要获得这个进程的ID,然后打开进程,获取信息,最后关闭打开的进程句柄。
这里假设游戏的基址是 0x930014  ,这个是BCB里十六进制的写法,以后都会这样写。
一级偏移是 0x24 ,人物当前血值的偏移是 0x25C ,下面开始写代码
在按钮的代码部分写如下代码:

DWORD eax,ecx,HP;
HANDLE mProcID;
DWORD hProcId;
HWND GameFormHwnd;
GameFormHwnd=FindWindow("QElementClient Window", "Element Client");

    GetWindowThreadProcessId(GameFormHwnd,&hProcId);
   
    mProcID = OpenProcess(PROCESS_ALL_ACCESS, false, hProcId);
    ReadProcessMemory(mProcID, LPVOID(0x930014), &eax, 4, 0);
    ReadProcessMemory(mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
    ReadProcessMemory(mProcID, LPVOID(ecx + 0x24), &eax, 4, 0);
    ReadProcessMemory(mProcID, LPVOID(eax + 0x25C), &HP, 4, 0);
    Label1->Caption= IntToStr(HP);

    CloseHandle(mProcID);

到这里,启动程序,就可以读取人物当前的血值了。
下面对上面的代码进行解释:

DWORD eax,ecx,HP;  定义DWORD类型的变量,就是无符号整形变量。

HANDLE mProcID;  定义HANDLE 类型的句柄变量

HWND GameFormHwnd;  定义 HWND 类型窗口句柄变量

GameFormHwnd=FindWindow("QElementClient Window", "Element Client");
利用API函数  FindWindow 我们可以得到游戏窗口的句柄,QElementClient Window 是类名,Element Client 是窗口标题 。

GetWindowThreadProcessId(GameFormHwnd,&hProcId);  进一步获得进程Pid 。这个很重要,我们是对进程操作,所以必须要得到进程Pid 。

mProcID = OpenProcess(PROCESS_ALL_ACCESS, false, hProcId);
这里是打开进程,我们操作其他进程或者和其他进程通信,都必须先打开这个进程,这是Windows的死规定。

ReadProcessMemory(mProcID, LPVOID(0x930014), &eax, 4, 0);
    ReadProcessMemory(mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
    ReadProcessMemory(mProcID, LPVOID(ecx + 0x24), &eax, 4, 0);
    ReadProcessMemory(mProcID, LPVOID(eax + 0x25C), &HP, 4, 0);
这里就是开始读取内存的地方了,利用ReadProcessMemory  API函数读取游戏进程的内容。从上至下就是指针的顺序  基址>一级偏移>二级偏移>人物血值偏移

Label1->Caption= IntToStr(HP);  把获得的值 HP 转换成字符类型,并赋值给Lable1的Caption属性。

CloseHandle(mProcID);  关闭打开的进程,有打开必有关闭,不然会造成资源浪费,后果很严重。

上面红色部分,就是我们需要获取信息的部分,在下面还可以获取更多的信息,例如:
ReadProcessMemory(mProcID, LPVOID(eax + 0x250), &ManLv, 4, 0);    //0x24C 人物等级
    ReadProcessMemory(mProcID, LPVOID(eax + 0x398), &mex, 4, 0);  //怪物名字偏移
    ReadProcessMemory(mProcID, LPVOID(mex), mname, 64, 0);    //存放字符的地址,读取后就是怪物的名字,(注意mex 变量需要先定义)
    ReadProcessMemory(mProcID, LPVOID(eax + 0x25C), &HP, 4, 0);        //596 当前体力  红
    ReadProcessMemory(mProcID, LPVOID(eax + 0x260), &MP, 4, 0);        //600 当前内力  蓝
    ReadProcessMemory(mProcID, LPVOID(eax + 0x274), &MaxHP, 4, 0);    //620 最大血值
    ReadProcessMemory(mProcID, LPVOID(eax + 0x278), &MaxMP, 4, 0);    //624 最大内力值
    ReadProcessMemory(mProcID, LPVOID(eax + 0x2DC), &Money, 4, 0);    //724 当前金钱值
    ReadProcessMemory(mProcID, LPVOID(eax + 0x7D4), &GWID, 4, 0);    //120版 偏移加 8 或地址 0x0354AF44 当前目标怪物ID ,为负就是怪,为正就是NPC或玩家,为0则怪物死亡,或没有选择怪物.
    ReadProcessMemory(mProcID, LPVOID(eax + 0x264), &Exp, 4, 0);    //0x25C 当前经验值,十进制
    ReadProcessMemory(mProcID, LPVOID(eax + 0x2D8), &GJDis, 4, 0);
    //升级经验值是一个地址 加 人物等级*4
    ReadProcessMemory( mProcID, LPVOID(MaxExpAdr + ManLv * 0x4), &MaxExp, 4, 0);      //0x930 人物升级经验值,十进制(MaxExpAdr 需要另外分析寻找)
    //ReadProcessMemory( mProcID, LPVOID(0x6020630), &MaxExp, 4, 0);
    ReadProcessMemory( mProcID, LPVOID(eax + 0x3C), &Mx, 4, 0);      //人物坐标 x  float 4字节
    ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &My, 4, 0);      //人物坐标 y  float 4字节
这里是一些基本的人物信息,在BCB里面读取游戏内存,一般就是这个模式: 找到需要处理的窗口的句柄,获取该句柄指向的进程Pid,打开进程,读取信息,关闭打开的进程。

这里要说下,LPVOID(eax + 0x44)  这个地方必须进程强制类型转换,不然可能会出错而无法编译。LPVOID 的意思就是强制转换为无类型指针 类型。

一个Lable 标签可以对应一个数据显示,当然也可以都显示在一个标签里,不过不推荐,有多少个数据需要显示,就应该每行画出一个Lable标签,格式上看起来都要舒服很多。

凡是都要知道,变量需要先定义后使用,如果你把上面这些代码直接复制到程序里,是行不通的,呵呵。


这一节到此结束,下一节我们进行界面设计和其他信息处理。
ゅ兔子哥

ZxID:2998095

等级: 上将
配偶: 老白兔。
音速图标啊图标6级7R!

举报 只看该作者 沙发   发表于: 2009-06-15 0
顶起
« 返回列表
发帖 回复