内容参考于:易道云信息技术研究院VIP课
上一个内容:77.网游逆向分析与插件开发-背包的获取-物品类的C++还原-CSDN博客
码云地址(ui显示角色数据 分支):https://gitee.com/dye_your_fingers/sro_-ex.git
码云版本号:a235362f248f4d865056675b60500382b6747f53
代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-背包类的C++还原与获取物品名称.zip
链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg
提取码:q9n5
--来自百度网盘超级会员V4的分享
HOOK引擎,文件名为:黑兔sdk.zip
链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw
提取码:78h8
--来自百度网盘超级会员V4的分享
以 修复角色名与等级显示问题-CSDN博客它的代码为基础进行修改
需要使用x96dbg逆向一下,来到0x787022位置(这个位置是在 背包结构与指针的逆向分析 这里分析出来的),从下图中的函数里看出,基本都是围绕这个3几几,所以结构体大小搞成0x400就行
然后打开 ReClass.NET,设置大小0x400,十进制是1024
然后得到背包结构地址:
涉及到的内容:
背包结构:背包结构与指针的逆向分析,x96dbg索引地址 0x787022
物品名:物品名称与物品编号的映射关系分析,x96dbg索引地址 0x739915
Res.cpp文件的修改,新加 ReadItemTitle函数、_ReadItemTitle变量初始化
#include "pch.h"
#include "Res.h"
// 这里为了给 _ReadTitle 默认值,防止编译不通过
Res::PROC_LP Res::_ReadTitle{};
Res::PROC_LP Res::_ReadItemTitle{};
PSROSTRING Res::ReadTitle(wchar_t* index)
{
/**
获取按钮文字通过逆向分析,看出是一个thiscall
在调用获取文字函数时给ecx赋值了,这是典型的thiscall方式
下方(this->*_ReadTitle)(index)写法翻译成汇编就会是
mov ecx,this
mov eax, [ecx+xxx];
push index
call eax
大概就会变成上方四行代码,也就是一个thiscall
如果穿插汇编代码,会很lou,这样用c++写就很优雅
*/
return (this->*_ReadTitle)(index);
}
PSROSTRING Res::ReadItemTitle(LPVOID ptr)
{
return (this->*_ReadItemTitle)(ptr);
}
Res.h文件的修改,新加 ReadItemTitle函数、_ReadItemTitle函数指针类型变量声明、PROC_LP函数指针,删除了 PROC_WCHAR1函数指针
#pragma once
#include "SRO_String.h"
// sro_string通过逆向分析,文字获取方式得到的一个结构体
typedef class Res
{
// 定义一个函数指针
typedef PSROSTRING(Res::* PROC_LP)(LPVOID);
public:
// 给函数指针声明一个变量
static PROC_LP _ReadTitle;
static PROC_LP _ReadItemTitle;
// 封装 _ReadTitle 使用时比较好用
PSROSTRING ReadTitle(wchar_t* index);
// 可以获取物品名
PSROSTRING ReadItemTitle(LPVOID ptr);
}*PRes;
GameBase.cpp,修改了 Init函数
#include "pch.h"
#include "GameBase.h"
GameBase* _pgamebase;
void GameBase::Init()
{
unsigned* addrRead = (unsigned*)0x1256E3C;
SRO_Res = (PRes)0x1036518;
SRO_Notice = (PNotice)addrRead[0];
addrRead = (unsigned*)0x1037D3C;
SRO_Player = (PAIM)addrRead[0];
InitClassProc(&Res::_ReadTitle, 0x9A46C0);
InitClassProc(&Res::_ReadTitle, 0x9A4640);
InitClassProc(&Res::_ReadTitle, 0x9A4640);
InitClassProc(&Notice::_NormalNotice, 0x848580);
InitClassProc(&Notice::_NetNotice, 0x844E40);
InitClassProc(&Notice::_ChatNotice, 0x844E80);
InitClassProc(&ITEM::_GetItemRes, 0x995800);
}
void GameBase::InitClassProc(LPVOID proc_addr, unsigned value)
{
unsigned* uWrite = (unsigned*)proc_addr;
uWrite[0] = value;
}
GameBase::GameBase()
{
_pgamebase = this;
// Init();// 初始化机制,完成游戏与我们dll的对接
}
GameBase.h文件的修改,新加引入 ITEM.h 头文件
#pragma once
#include "Res.h"
#include "Notice.h"
#include "AIM.h"
#include "ITEM.h"
class GameBase
{
void InitClassProc(LPVOID proc_addr, unsigned value);
public:
void Init();
GameBase();
PRes SRO_Res;
PNotice SRO_Notice;
PAIM SRO_Player;
};
新加 BackPack.cpp文件,背包结构
#include "pch.h"
#include "BackPack.h"
int BackPack::PackCount()
{
int allsize = (DWORD)ItemEnd - (DWORD)ItemStart;
if (allsize<0) return 0;
return allsize >> 2;
}
PITEM BackPack::GetItem(int index)
{
if (index < PackCount()) {
PITEM pitem = ItemStart[index];
return pitem;
}
return NULL;
}
新加BackPack.h文件,背包结构
#pragma once
#include "ITEM.h"
typedef class BackPack // 背包
{
protected:
char pad_0000[928]; //0x0000
public:
PITEM* ItemStart; //0x03A0 物品起始地址
PITEM* ItemEnd; //0x03A4 物品结束地址
protected:
char pad_03A8[88]; //0x03A8
public:
int PackCount();
PITEM GetItem(int index);
}*PBackPack; //Size: 0x0400
新加ITEM.cpp文件
#include "pch.h"
#include "ITEM.h"
#include "extern_all.h"
ITEM::PROC ITEM::_GetItemRes{};
LPVOID ITEM::GetItemRes()
{
LPVOID resPtr = (this->*_GetItemRes)();
resPtr = (LPVOID)((DWORD)resPtr + 0x60);
return resPtr;
}
PSROSTRING ITEM::GetName()
{
return _pgamebase->SRO_Res->ReadItemTitle(GetItemRes());
}
ITEM.h文件的修改,新加 GetItemRes函数、GetName函数、PROC函数指针,_GetItemRes函数指针类型变量声明
#pragma once
#include "SRO_String.h"
typedef class ITEM
{
typedef LPVOID(ITEM::* PROC)();
public:
static PROC _GetItemRes;
protected:
char pad_0000[52]; //0x0000
public:
int Type; //0x0034 类型
protected:
char pad_0038[84]; //0x0038
public:
int Elv; //0x008C 装备强化程度
protected:
char pad_0090[8]; //0x0090
public:
int Durabillty; //0x0098 耐久度
int Count; //0x009C 数量
protected:
char pad_00A0[64]; //0x00A0
public:
int MaxPhyAttack; //0x00E0 最大物理攻击力
int MinPhyAttack; //0x00E4 最小物理攻击力
int MaxMagAttack; //0x00E8 最大魔法攻击力
int MinMagAttack; //0x00EC 最小魔法攻击力
protected:
char pad_00F0[48]; //0x00F0
public:
int MaxDurabillty; //0x0120 最大耐久度
protected:
char pad_0124[16]; //0x0124
public:
int mingzhonglv; //0x0134 命中率
protected:
char pad_0138[152]; //0x0138
public:
int Plv; //0x01D0 宠物等级
protected:
char pad_01D4[692]; //0x01D4
public:
LPVOID GetItemRes();
// 获取物品名
PSROSTRING GetName();
}*PITEM; //Size: 0x0488