您的当前位置:首页 > 焦点 > 学习使用的工具:逆向工具集 正文

学习使用的工具:逆向工具集

时间:2024-04-29 17:36:28 来源:网络整理 编辑:焦点

核心提示

热血江湖外挂 1.0:最新版人物信息基址:0x02C166D8;最新版背包

学习使用的工具:逆向工具集

热血江湖外挂

  • 1.0:最新版人物信息基址:0x02C166D8;最新版背包存放基址:0x02E3B3E4
  • 2.0:最新版物品使用call 为0x00838480
  • 3.0:
    • 人物基址:0x02C176D8‬;
    • 背包存放基址:0x02E3C3E4;
    • 游戏主窗口基址:0x01195F88;
    • 使用物品的学习向工CALL:0x008384F0;
    • 人物动作基址:0x02E3CD58;
    • 动作使用的CALL:0x007139E0;
    • 所有对象数组:0x2E64A28;
    • 怪物基址:0x427FBA0
    • 角色对象基址:0x427FBA0
  • 一般游戏开发的时候,相关的使用数据都是放到一个结构或者是一个类中,那么这些数据的具逆具集内存地址相距的比较近;
  • 一般内存地址使用CE工具逆向出来后表示为Client.exe+278A75C,表示软件地址加上偏移量为其基址
  • 生命值PH: Client.exe+278A75C = 02B8A758
  • 内功值MH: Client.exe+278A75C = 02B8A75C
  • 进行商品的学习向工买卖实现金币值的变动
  • 基址:Client.exe+278A7BC = 02B8A7BC
  • OD软件的使用
    • 使用dd 02B8A758 查找到人物属性基址块
  • 人物属性值以及对应的内存地址
  • 基址 02B8A6D8
    • +0:人物名字
    • +80:生命值(红/HP)
    • +84:内功值(蓝/MP)
    • +88:愤怒值
    • +8C:最大生命值
    • +90:最大内功值
    • +94:最大值愤怒值
    • +98:当前经验值
    • +A0:升级到下一级要的经验值
    • 势力
    • +36:名声
    • +34:一字节空间表示等级
    • +35:一字节空间表示 几转
    • +AC:历练
    • 制造
    • 熟练度
    • 灵兽持有
    • 精力
    • +C8:攻击
    • 武器命中
    • +CC:防御
    • 武器防御
    • +D0:命中
    • 对人战斗
    • +D4:回避
    • 对怪攻击
    • 武功回避
    • 对怪防御
    • +B0:心
    • +B4:气
    • +B8:体
    • +BC:魂
    • +E4:金币值
  • 气功值分析
    • 气功点数:基址 + F0 = 02b8a7c8
    • 第num个气功的点数:(一个字节)02B8A6D8+0f0+4*num
    • 可能是第num个气功的ID(没有就为0):02B8A6D8+0f0+4*num+2
  • 注入DLL

    • 创建MFC DLL

      创建MFC_DLL

  • 在添加窗口后,需要进行配置,使用才能在动态链接库注入后显示窗口

    • 为窗口添加Class

    • 修改MFC_DLL.cpp的具逆具集代码

    • 使用注入工具讲编译生成的DLL 注入到游戏进程中

      • 注:DoModal() 函数是以阻塞的方式去执行的,所以会造成线程阻塞

      • 解决方式:将DoModal() 放到新的学习向工线程去执行

      • 实现窗口关闭后自动释放DLL

    使用代码实现动态连接库的注入

    • 使用到的windows API
      • HWND FindWindow(lpClassName, lpWindowNAme)
        • 通过类名指针或窗口名指针获取窗口句柄
      • DWORD GetWindowThreadProcessId(hwnd(窗口句柄), lpdwProcessId)
        • 获取窗口线程句柄的ID(lpdwProcessId)
      • HANDLE WINAPI OpenProcess(dwDesiredAccess(访问权限), bInheritHandle, dwProcessId)
        • 开启并创建一个本地进程
      • LPVOID WINAPI VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect)
        • 分配内存空间
      • BOOL WINAPI WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten)
        • 向内存中写入数据
      • HANDLE WINAPI CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId)
        • 为进程创建一个线程
      • DWORD WINAPI WaitForSingleObject(hHandle, dwMilliseconds)
        • 等待单个对象执行后再进行操作
      • BOOL WINAPI CloseHandle(hObject)
        • 关闭句柄
      • BOOL WINAPI VirtualFreeEx(hProcess, lpAddress, dwSize, dwFreeType)
        • 释放内存空间
      • BOOL WINAPI CloseHandle(hObject)
        • 关闭句柄
  • 步骤
    1. 获取窗口对应的进程的PID
    2. 根据PID 获取进程
    3. 获取游戏进程的PID
    4. 根据PID 获取进程
    5. 在目标进程分配内存空间,方便写入DLL 全路径
    6. 将DLL 全路径写入到目标进程
    7. 远程注入DLL
    8. 等待目标进程执行完成
    9. 释放进程空间
    10. 关闭线程句柄
  • 整数
    • QWORD 类型变量 nq前缀 //8字节 无符号整数 不能表示负数
    • DWORD 类型变量 nd前缀 //4字节 无符号整数 不能表示负数
    • WORD 类型变量 nw前缀 //2字节 无符号整数 不能表示负数
    • BYTE 类型变量 nb前缀 //1字节 无符号整数 不能表示负数
    • int 带符号类型 ni前缀 //4字节 带符号整数 可表示正负数
    • _int64 带符号整型 ni64//8字节 带符号整数 不能表示负数
    • UINT 类型变量 ui前缀 // 无符号整数 一般是使用4字节
    • //浮点数
    • float 单精度浮点数 fl前缀
    • double 双精度浮点数 fd前缀
  • 字符串
    • char*和char [] sz前缀 //PCHAR szp
  • CString str前缀
  • 结构名 T开头全大写
  • 类名 C开头单词首字大写

整合游戏数据步骤

  1. 新建解决方案GameData

  2. 创建头文件BaseGame.h和 StructGame.h


    • BaseGame.h

    • StructGame.h
  3. 创建源文件StructGame.cpp


    • StructGame.cpp
  • 配置链接库路径

    • 配置 附加包含目录

    • 配置 添加库目录

  • 配置编译输出路径

    • 修改输出目录

  • 在游戏中,对应的具逆具集物品都会有一个结构/类,包含了物品的学习向工一些信息
  • 使用物品实际上调用了应该CALL
以金疮药为例
  • 寻CALL 的过程

    • 使用CE工具找到对象地址指针

    • 去查看访问改指针的地址

    • 使用OD 工具对这些地址进行动态调试

    • 远程注入代码(使用金疮药)

背包数据的分析
  • 背包在游戏中一般会写成应该结构体/类来存放物品对象
  • 物品对象在背包中使用数组的形式存在
  • 汇编中数组的访问方式一般是 数组基址 + 4 * i(' i '为数组下标)
  • 查找背包数组基址:
    • 找到背包的物品格
    • 反复讲里面的物品拿出/放入
    • 使用CE工具进程分析
  • 结果
    • 存放背包基址的内存空间:0x02DAF3E4
    • 第num 个格子的数据获取
      • *背包基址+num*4+0x43C
      • 注:0x43 是偏移量
      • 物品对象指针 + 0x64 = 物品名字
      • 物品对象指针 + 0xf9 = 对物品的描述
      • 物品对象指针 + 0xC4C = 物品剩余数量

封装背包结构体

实现初始化方法(getDate())

调试调用

文件结构

封装函数

  • 定义基址
  • 定义结构
  • 实现方法
  • 调用方法,实现物品的使用使用
  • 文件结构

造成异常的原因:

  • 游戏主线程与外挂线程同时访问共享数据区域,造成程序异常
  • 让两个线程依次使用共享数据或者将注入线程到主线程

模拟游戏主线程和辅助线程同时执行

  • 代码
  • 异常

解决方式

  • 将程序注入到主线程

  • 使用临界区

    • 1

    • 2、具逆具集代码

  • 关键词

  • 分析思路:从怪物明显的学习向工属性入手:名字、血量

    1*4+427EBA0 //怪物列表基址(1-5)

    +8 种类/2E:怪物

    +354 显示血条

    +C 怪物选中参数

    +5f4 怪物血量

    +5f8 怪物等级

    +360 怪物名字

    +1060 怪物位置X

    +1068 怪物位置Y

    +3C0 怪物生命状态 0活/1死

    [0427EBA0] //角色对象指针

    +8 //角色分类31人物/2E

    +18 //角色名字

  • 定义基址

  • 定义结构

  • 实现结构方法

  • 在HOOK 内定义测试方法

  • 实现

  • 控件调用

  • 目录结构

    img

  • 思路:
    • 通过选中的对象逆向回溯出动作的数组
    • 通过动作对象访问逆向回溯到攻击CALL 附近
    • 封包断点bp WSASend
  1. 通过选中动作,利用CE 查找基址

  2. 使用OD 分析访问内存信息,具逆具集得到基址

    动作公式:[02e3bd58]+43c+4*0

  3. 找动作的CALL

    • 使用CE 分析动作对象的调用访问

    • 得到一下信息

    • 使用OD分析得动作CALL为

  • 封装动作对象
  • 封装动作对象列表
  • 封装使用对象功能函数

封装

  1. 封装基址

  2. 封装结构

  3. 实现结构方法

  4. 添加消息类型

  5. 在主线程内调用结构体方法

  6. 发送消息到主线程

  7. 绑定控件,执行方法

  • 文件结构

    img

  • 实现怪物选中
  • 可能情况:
    • 选怪变量被赋值
    • 怪物是否被选中的属性

选怪功能相关地址

  • 玩家:

    [2E63A24] //存放的玩家对象的地址

    +3428 玩家是否被选中

  • 怪物:

    [2E63A24]+1A64

    选中怪物时,传入怪物的选中ID

    没选中怪物时,值为0xFFFF