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

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

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

楼层直达
ゅ兔子哥

ZxID:2998095

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

举报 只看楼主 使用道具 楼主   发表于: 2009-06-14 0
先谢谢大家这么支持,好不容易才整理好的。


CE 的下载地址: http://www.ghoffice.com/bbs/read.php?tid-26455.html
或者在广海游戏论坛里面有汉化版的CE。 广海游戏论坛地址:http://www.ghoffice.com/bbs/thread.php?fid-74.html


上节如果完成后,界面应该是像这样的
 

可以看出,这样很不美观,呵呵,所以这一节我们就来设计下界面和最基本的读取人物其他信息。
我们的目的是把界面设计成如下图片所示的样子,当然怎么排列还是看自己喜欢,呵呵。
   

一个按钮,一个时钟控件,其他都是标签,按着一定的排列画在窗口上。
按钮可以在上方 Standard 栏找到,时钟控件可以在 System 栏找到。
我们利用时钟控件,就可以实现循环读取游戏的数据了,这一次的代码将会和上一次的有点改变。
下面我们开始写代码:

首先,选择时钟控件,将 Interval 属性设置为 100 ,意思就是1秒钟读取10次数据。Enabled 属性设置为False 。
双击按钮,进入代码界面,写下如下代码

    FirstAdr= 0x930014;
    GameFormHwnd=FindWindow("QElementClient Window", "Element Client");
    if(!GameFormHwnd)
    {
        ShowMessage("游戏没有启动,请先启动游戏并完全进入游戏!");
        return ;
    }
    GetWindowThreadProcessId(GameFormHwnd,&hProcId);
    Timer1->Enabled=true;

和上一次的差别是,我们把读取数据的代码放到时钟控件里,这里只做游戏的开启判断和数据初始化。

然后双击时钟控件,由于所有的数据都在时钟控件里面读取,所以代码有点多:

HANDLE mProcID;
    DWORD eax,ecx, mex,tmp1,tmp2;
    AnsiString ms; //byte dcode;
    WCHAR mname[64];
    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);
    ReadProcessMemory(mProcID, LPVOID(eax + 0x250), &ManLv, 4, 0);    //0x24C 人物等级
    ReadProcessMemory(mProcID, LPVOID(eax + 0x398), &mex, 4, 0);  //怪物名字
    ReadProcessMemory(mProcID, LPVOID(mex), mname, 64, 0);
    ManName=mname;
    ReadProcessMemory( mProcID, LPVOID(eax + 0x244), &ManID, 4, 0);      //人物 ID
    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 + 0x3C), &Mx, 4, 0);      //人物坐标 x  float 4字节
    ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &My, 4, 0);      //人物坐标 y  float 4字节
    //怪物信息
    //---------------------------------------------------------
    if( GWID > 0x80000000)    //大于0x80000000为怪物或NPC
    {
        WCHAR Buff[64];
        ReadProcessMemory( mProcID, LPVOID(FirstAdr), &eax, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x8), &eax, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(eax + 0x20), &ecx, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x24), &tmp1, 4, 0);  //读出怪物数组的最大值
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x18), &tmp2, 4, 0);  //读出怪物列表的首地址
        if(GWID!=0) eax = tmp2 + (GWID % tmp1) * 0x4;
        ReadProcessMemory( mProcID, LPVOID(eax), &ecx, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x4), &eax, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(eax + 0x134), &GWHP, 4, 0); //怪物当前血值
        ReadProcessMemory( mProcID, LPVOID(eax + 0x14C), &GWMaxHP, 4, 0); //怪物血值上限
        //ReadProcessMemory( mProcID, LPVOID(eax + 0xB4), &GWType, 4, 0);    //选中类型
        //ReadProcessMemory( mProcID, LPVOID(eax + 0x120), &GWTypeID, 4, 0); //怪物类
        ReadProcessMemory( mProcID, LPVOID(eax + 0x128), &GWLv, 2, 0);
        ReadProcessMemory( mProcID, LPVOID(eax + 0x3C), &GWMx, 4, 0);  //怪物X坐标
        ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &GWMy, 4, 0);  //怪物Y坐标
        ReadProcessMemory( mProcID, LPVOID(eax + 0x234), &MtoG, 4, 0);  //怪物距离
        //怪物名称部分------------------------------------
        ReadProcessMemory( mProcID, LPVOID(eax + 0x210), &ecx, 4, 0);  //怪物名字
        ReadProcessMemory( mProcID, LPVOID(ecx), Buff, 64, 0);
        GWName = Buff;
       
    }
    else if(GWID < 0x80000000 && GWID >0)    //玩家
    {
        WCHAR Buff2[64];
        ReadProcessMemory( mProcID, LPVOID(FirstAdr), &eax, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(eax + 0x1C), &ecx, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x24), &eax, 4, 0);
        //-------------------------------------------------------
        ReadProcessMemory( mProcID, LPVOID(eax + 0x138), &ecx, 4, 0);
        //-------------------------------------------------------
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x24), &tmp1, 4, 0);  //读出怪物数组的最大值
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x18), &tmp2, 4, 0);  //读出怪物列表的首地址
        if(GWID!=0) eax = tmp2 + (GWID % tmp1) * 0x4;
        ReadProcessMemory( mProcID, LPVOID(eax), &ecx, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(ecx + 0x4), &eax, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(eax + 0x25C), &GWHP, 4, 0); //选中人物当前血值
        ReadProcessMemory( mProcID, LPVOID(eax + 0x274), &GWMaxHP, 4, 0); //选中人物血值上限
        ReadProcessMemory( mProcID, LPVOID(eax + 0x250), &GWLv, 2, 0);
        //ReadProcessMemory( mProcID, LPVOID(eax + 0xB4), &GWType, 4, 0);  //选中类型
        ReadProcessMemory( mProcID, LPVOID(eax + 0x3C), &GWMx, 4, 0);  //怪物X坐标
        ReadProcessMemory( mProcID, LPVOID(eax + 0x44), &GWMy, 4, 0);  //怪物Y坐标
        ReadProcessMemory( mProcID, LPVOID(eax + 0x4D0), &MtoG, 4, 0);    //人与人距离
        if( GWID == ManID && GWID!=0)
        {
            GWHP = HP;
            GWMaxHP = MaxHP;
            GWMx = Mx;
            GWMy = My;
        }
        //选择人物名字部分----------------------------------------
        ReadProcessMemory( mProcID, LPVOID(eax + 0x398), &ecx, 4, 0);
        ReadProcessMemory( mProcID, LPVOID(ecx), Buff2, 64, 0);
        GWName = Buff2;
    }
    //下面开始显示数据
    LbName->Caption="人物: " + ManName;
    LbLv->Caption = "等级: " + AnsiString(ManLv);
    LbId->Caption = "ID: " + AnsiString(ManID);
    LbManPos->Caption = "坐标: X: " + ms.FormatFloat("0.0",Mx) + "  Y: " +
    ms.FormatFloat("0.0",My);
    LbHP->Caption= "HP: " + IntToStr(HP) + " / " + IntToStr(MaxHP);
    LbMP->Caption= "MP: " + IntToStr(MP) + " / " + IntToStr(MaxMP);
    LbExp->Caption = "Exp: " + IntToStr(Exp);
    LbMon->Caption = "金钱: " + AnsiString(Money / 10000) + "金 " +  AnsiString((Money % 10000) / 100) +
    "银 " + AnsiString(Money % 100) +    "铜";
    if( GWID > 0)
    {
        if( GWID == ManID)
            Form1->LbObj->Caption = "目标: " + AnsiString(ManLv) + "级 ID:" +
            AnsiString(ManID) + " " + ManName;
        else
            Form1->LbObj->Caption = "目标: " + AnsiString(GWLv) + "级 ID:" +
            AnsiString(GWID) + " " + GWName;
    }
    else
        Form1->LbObj->Caption = "目标: ";
    LbObjHP->Caption="目标HP: " + IntToStr(GWHP) + " / " + IntToStr(GWMaxHP);
    LbObjPos->Caption = "坐标: X: " + ms.FormatFloat("0.0",GWMx) + "  Y: " + ms.FormatFloat("0.0",GWMy) + "  距离: " + ms.FormatFloat("0.0",MtoG);
    //显示段完
    CloseHandle(mProcID);

以上就是在时钟控件里的代码。
另外,我们需要定义一些全局变量,在

#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

这些代码下面,加入以下代码

DWORD FirstAdr;
DWORD ShutTime,hProcId,ManID,HP,MaxHP,MP,MaxMP,Money;
DWORD GWID,GWMaxHP,GWHP,ObjHP,ObjMaxHP,ObjID,Exp,MaxExp,ExpLvUp;
HWND GameFormHwnd;
long ManLv,GWLv;
float MtoG,AreaMtoG,GWMx,GWMy,Mx,My;
AnsiString ManName,GWName;


到这里,完成读取基本信息的制作。
调试运行没有错误后,我们显示的结果图如下:
   


我把Unit1.CPP 的完整代码存到一个文本文件里提供下载。

这一节就说这么多勒,还有些事要处理。如果有什么不明白的地方,可以发帖或回帖,有空我就来回复下,呵呵。
_______ゞ傻.

ZxID:4512567

等级: 大校
昨天 ,今天, 明天, 轮回不断。

举报 只看该作者 板凳   发表于: 2009-06-15 0
虽然看不懂...但顶你下
昨天 ,今天, 明天, 轮回不断。
ゅ兔子哥

ZxID:2998095

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

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