郁金香商业辅助教程 2016 笔记 1~5

一、分析角色 HP/MP 地址

我们的目标是这个,热血江湖。我们要找出基本信息中,所有数据的地址。

我们要用到一款工具,CE。打开之后点击左上角打开进程,会弹出进程列表,我们需要选择游戏的进程。

我们可以点击下面的“窗口列表”,然后从打开的窗口中搜索,这样可能比较好找。

由于 HP 数值变动较快,我们把扫描类型改为“两者之间的数值”,在上面把数值设置为 352 和 370(视具体情况而定),然后点“首次扫描”。

左边就会出现结果。因为结果太多,我们不知道是哪个,需要进一步筛选。

我们把扫描类型改为“增加的数值”,点击“再次扫描”。这个很重要,因为再次扫描是在上一次的结果中搜索,可以缩小范围。游戏中一些值是不变的,可以过滤一些。

我们双击唯一的结果,它会在底部的列表中出现,双击描述可以修改名称。双击地址会弹出这样一个框。

我们可以看到,地址采用模块名称(基址)加偏移来描述。这是因为一些模块是共享库,加载时会改变基址。因为我们这是一个 EXE,不需要这个名称也可以。

接下来我们尝试寻找 MP(蓝的那个)的地址。我们不需要重新搜索。我们假设程序以int保存这些数值,而int在 windows x86/x64 上是四个字节。我们还假设这些东西是挨着存储的。所以我们将那个地址加四。

我们看到右边的 251 正好的游戏的 MP,说明我们找对了。

二、分析角色金钱基址

我们查看金币数量,是 173061:

这个数值不太可能有重的,所以我们直接搜索:

我们选上面那个,因为它和我们上节课的地址在一个段里面。

我们找到了金钱的地址。但这样一个一个找太麻烦了,有没有可能一次找到全部呢?

首先记下基本信息:

我们打开 OD 并用它附加游戏。

然后执行dd 2f86170,在左下角的窗口中,我们可以看到这个地址附近的数据。

我们双击第一行第一列,将第一列转换为偏移形式:

我们看到第二列是十六进制形式,需要将其转换为十进制。

地址数值属性
(0x2f86170)+0x0381HP
0x4252MP
0x8390愤怒值
0xc381最大 HP
0x10252最大 MP
0x141000最大愤怒值
0x18 QWORD12185经验值
0x20 QWORD24782下一级所需的经验值
0x2810
0x2c27138历练
0x3051
0x3454
0x3831
0x3c91
0x400
0x440

我们可以根据数值猜出绝大部分。但是 HP 之前还有个昵称,这里没有,可能我们需要向前找找。

我们点击右键,点击“文本->ASCII(32 字符)”:

-0x80的地方找到了角色名称。我们切换为十六进制视图,然后把这个地方作为新的基址:

我们得到了一些新的东西:

地址数值属性
(0x2f860f0)+0x0 STR-角色名称
0x3011
0x34 BYTE0x17等级
0x35 BYTE0x1几转
0x36 STR-名声

并且之前那些地址需要加上0x80,这里就不再写一遍了。

我们回到 CE,可以点击右边的“手动加入地址”,保存它们。

三、分析角色气功加点

这次我们要分析角色的气功点数:

我们首先寻找第一个,因为其它气功很可能在第一个后面。

并且,我们不知道这个属性用几个字节来表示。但如果多于一个字节,那么14应该在它的最低字节。也就是说,无论怎么表示,我们都可以搜索一个字节14

(实际上气功点数最大为 20,剩余点数最大为 100,不超出一个字节的最大值。就算它多于一个字节,高字节也用不上。)

搜索结果太多了,我们让它变化一下,给它加一点变成 15,然后再搜。

最上面的两个以0x02f开头,和上一节的其它数据在同一个段里面。那么到底哪个是呢?

我们用 OD 附加进程(其它很多软件都可以),查看具体的内存布局。首先是第一个0x02f861e4

0x02f861e4是第一个气功点数,每隔0x4就有一个气功点数。0x02f861e0是剩余点数。所有点数都是一字节。

然后是第二个0x02f888a0

这个地址中没有剩余点数,而且都是紧密挨着的。

下面我们验证一下,将第二个气功的点数加一。

这是第一个地址0x02f861e0

我们看到第二个气功的点数变成了 2。

然后是第二个地址0x02f888a0

也变了,说明两个地址都有效。我们选择第一个,因为它和我们上一节的基址近一些。我们减一下,得到第一个地址的偏移是0xf0

下面我们总结一下信息:

地址数值属性
(0x2f860f0)+0xf0 BYTE2气功剩余点数
0xf4 BYTE15第一个气功点数
0xf0+4*i BYTE-i个气功点数

四、注入 DLL

一般来说,在同一个进程中读取数据比较方便。所以我们编写 DLL,将其注入同一个进程中。

打开 VS,新建项目,选择“MFC DLL”。创建项目完成后,我们的目录是这样:

接下来我们创建窗口,点击资源视图(左下角),然后右键添加资源对话框(Dialog):

然后我们新建类CMainDialogWnd,使用 MFC 创建类向导:

然后打开“源文件->MainDialogWnd.h”,代码是这样。

class CMainDialogWnd: public CDialogEx
{
    DECLARE_DYNAMIC(CMainDialogWnd)

public:
    CMainDialogWnd(CWnd* pParent=NULL); //标准构造函数
    virtual ~CMainDialogWnd();

    //对话框数据
    enum { IDD = IDD_DIALOG1 }

protected:
    virtual void DoDataExchange(CDataExchange* pDX) //DDX/DDV 支持

    DECLARE_MESSAGE_MAP()
}

我们打开MFC_DLL.cpp,创建全局变量:

CMainDialogWnd *PMainDialog;

CMFC_DLLApp::InitInstance中添加:

PMainDialog = new CMainDialogWnd;
PMainDialog->DoModal();
delete PMainDialog;
// 释放 DLL,以便反复注入
FreeLibraryAndExitThread(theApp.m_hInstance, 1);

但这样有个问题,这个窗口是模态的。窗口显示的时候会卡住游戏。我们可以将其放到子线程中。把上面的代码移到一个函数中:

DWORD WINAPI ShowDialog(LPARAM lpData) 
{
    PMainDialog = new CMainDialogWnd;
    PMainDialog->DoModal();
    delete PMainDialog;
    // 释放 DLL,以便反复注入
    FreeLibraryAndExitThread(theApp.m_hInstance, 1);

    return TRUE;
}

CMFC_DLLApp::InitInstance中编写:

CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ShowDialog, NULL, NULL, NULL);

我们编译它,在debug目录下面得到MFC_DLL.dll。然后我们打开CodeInEx注入工具,点击左上角的按钮:

我们首先在上面的列表中选择要注入的进程,然后点击下面的“注入DLL”按钮,会弹出一个选择框。我们在里面选择刚才的 DLL。

之后我们发现我们的窗口打开了,并且游戏还有反应。

五、手动编写注入代码

上一节中,我们使用工具来注入 DLL。这一节我们尝试自己编程来实现。

首先新建 Win32 控制台项目,在“源文件”目录下创建InjectDll.cpp(名字不重要)。

我们首先要获取窗体类名,之后要拿它获取窗口句柄。为什么这样,是因为窗体类名是永远不变的,句柄可能每次启动都要变。我们打开Spy++

句柄是D3D Window。我们在代码开头定义一个常量:

#define GameClassName "D3D Window"

我们还需要定义 DLL 的路径:

#define DllFullPath "path\\to\\your\\dll"

之后我们编写函数InjectDll

bool InjectDll() 
{
    // 根据窗口类名获得句柄
    HWND hWnd = FindWindow(GameClassName, NULL);
    if(hWnd == NULL) 
        return false;

    DWORD pid = 0;
    // 根据窗口句柄获取 PID
    GetWindowThreadProcessId(hWnd, &pid);
    if(pid == 0)
        return false;

    // 根据 PID 获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if(hProcess == NULL)
        return false;

    // 在游戏内存中分配一片空间
    LPVOID address = VirtualAllocEx(hProcess, NULL, 256, MEM_COMMIT, PAGE_READWRITE);
    if(address == NULL)
        return false;

    // 写入 DLL 全路径名
    DWORD bytesWritten;
    WriteProcessMemory(hProcess, address, DllFullPath, strlen(DllFullPath) + 1, &bytesWritten);
    if(bytesWritten < strlen(DllFullPath))
        return false;

    // 在目标进程中启动线程
    // 加载动态链接库
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, address, NULL, NULL);

    // 等待
    WaitForSingleObject(hThread, 0xffffffff);

    // 回收
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, address, 256, MEM_DECOMMIT);
    CloseHandle(hProcess);

    return true;
}

然后编写main

int main() 
{
    // 注入 DLL 代码
    printf("注入 DLL\n");
    if(!InjectDll())
        printf("注入 DLL 失败\n");

    // 让控制台停住
    getchar();

    return 0;
}

编译运行之后,DLL 就被注入,我们也就能看到熟悉的窗口了。

免key版,511U盘资源,速度很快!经测试全部可下 课程分四个大章节 初级篇,中级篇,进阶篇,高级篇 初级篇内容:编写一个完整的,简单的外挂 C++的数据类型:Byte,Word,DWORD,int,float API函数的调mouse_event,GetWindowRect,SetCursorPos,FindWindow,SendMessage) CE5.4工具的使用方法 中级篇内容:调试工具的使用技巧,功能CALL的概念 调试工具OD1.1的使用技巧(如硬件断点,条件断点,内存断点。 常用汇编指令与对应高级语言的转换。 游戏功能CALL概念 找第一个功能CALL 外挂框架的构建(通用) 进阶篇内容:分析游戏内部数据,分析常用功能CALL 游戏数据实践找各种功能CALL(如打怪,选怪,物品使用,技能栏之类)及相应的代码编写 高级篇内容:编写完整外挂 完成一个相对完整的外挂,实现 自动挂机,打怪,存放物品之类的功能 1 入门篇.以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最简单的外挂(实现游戏开局) a、鼠拟鼠标单击mouse_event b、鼠标指针移动还原 c、集成到startgame函数里 1.2、用CE查找棋盘数据 1.2.1、CE中的数据类型 a、数据类型:Bit,Byte,Word,Dword,float,double b、用CE查找出坐位号; c、保存分析数据 1.2.2、编程读出坐位号; a、远程读取进程数据 b、打开远程进程 c、读取远程进程数据 1.2.3、用CE查出棋盘基址; a、找棋盘数据基址 b、分析棋盘数据结构 1.2.4、读出当前棋盘数据 a、编程读出棋盘数据 b、棋盘数据显示出来 1.3、用模拟技术编制外挂 1.3.1 分析棋子与棋盘坐标关系 a、鼠标软件模拟,函数SendMessage b、分析窗口内棋子相对坐标X,Y c、软件模拟点击棋盘坐标x,y处的棋子 1.3.2 消掉一对棋子的算法框架 a、遍历棋盘同类型棋子配对 b、构建算法框架 1.3.3 (Check2p)大致框架(算法核心) a、在这一对棋子间找相通路径的原理 b、(Check2p函数)框架代码 c、(CheckLine函数)检测2点是否有连通. 1.3.4 CheckLine实现 a、CheckLine函数实现 b、Check2p核心代码架构 1.3.5 Check2p完整代码实现 1.3.6 编写完整外挂,界面美化 1.4、游戏加速.去掉对动画效果.非HOOK 1.4.1:用OD找出 动画延时代码 1.4.2:写代码去掉延时,实现游戏加速 2 中级篇 以热血江湖为例 2.1、分析前的准备..CALL简介: 2.1.1、CALL调用示例分析.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值