需求:
在自动化助手的UI界面中,能够实时的显示玩家背包中的数据,以及重要的属性信息,比如数量,名称等
1、分析物品数据属性,还原C++类
2、分析物品基址或者基址获取方法
物品数据的初步分析:
搜索背包的物品数据 初步猜测是数组 相邻的差值都一样
发现改变背包的物品位置,数据也被copy了,直接搜字符串
发现这个地址离太远了,不可能和别的构成数组 ,说明物品是没名字的,而是有物品种类
再由这个数据有一个算法来指向名字
鼠标放上去显示名字 肯定是先有id 然后通过算法 那个算法参数是id 来指向这个名字的位置
所以直接下断,鼠标移向背包装备 触发断点
发现是有eax读出来的
一直往上走 发现ebx像 物品指针
直接加上偏移 发现是物品数量
这就是物品指针了。
物品指针-》995800 得到新的指针 +60
关键点:
获取背包结构:
比较指针
EBX没变就去找ECX
一直往上发现ECX一直没变
说明这个体系比较复杂
EAX是46 应该是从这儿来的
下断发现不是从这来的..
再往前就追到一个和界面有关的地方,鼠标移动就断下。。
追到这就不追了 涉及到UI 就很底层了 这么底层的地方找太难了。
我们得找个和UI没关系的地方
因为物品是独立的 ,写入的操作就也比较独立,访问的话又会涉及到UI的问题,写入就可能可以把UI这块避过去
跟进去往前跳
这个看起来还好,一上来就看见一个数组结构
ebx是物品指针 通过edi控制这个指针 edi可能是序号或者大小
item[x] item*[x] 只有这两种可能 点第一个edi是0 第二个edi是1 ...
那么就可以确定这是一个指针数组 那么edi代表物品在背包里的序号,访问估计也就是一个循环0---95了
超过就异常 包裹大小也就是 /4 得到
也清晰的记录了背包有多少格
背包基址的分析:
esi来自于上级菜单,往上找~
来自于EBX
这个函数估计就是更新属性的东西
来自esp+20
指针从这得来的
再试试金币是不是在包裹里:
很明显在同一个结构体里 :钱也在背包里
物品类的C++还原:
#pragma once
#include"SRO_String.h"
//物品
typedef class ITEM
{
typedef LPVOID(ITEM::* PROC)();
public:
static PROC _GetItemRes;
protected:
int unknowB1[13];
public:
int Type;//类型
protected:
int unknowB4[21];//
public:
int elv;//装备强化程度
protected:
int unknowB28[2];
public:
int MaxDurability;//最大耐久度
int Count;// 数量
protected:
int unknowB7[16];
public:
int MaxPhyAttack;//最大物理攻击力
int MinPhyAtack;//最小物理攻击力
int MaxMagAttack;//最大魔法攻击力
int MinMagAttack;//最小魔法攻击力
protected:
int unknownnB25[12];
public:
int Durability;//耐久度
protected:
int unknownB13[43];
public:
int plv;//宠物等级
protected:
int unknownB31[129];
public:
LPVOID GetItemRes();
PSROSTRING GetName();
}*PITEM;
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());
}
背包类的C++还原:
#pragma once
#include"ITEM.h"
typedef class BackPack
{
int unknowmB1[232];
public:
PITEM* ItemStart;//物品起始地址
PITEM* ItemEnd;//物品结束地址
protected:
int unknownB7[22];
public:
int PackCount();
PITEM GetItem(int index);
}*PBackPack
#include "pch.h"
#include "BackPack.h"
int BackPack::PackCount()
{
int allsize = (DWORD)ItemEnd - (DWORD)ItemStart;
if (allsize < 0)return 0;
allsize = allsize / 4;
return allsize;
}
PITEM BackPack::GetItem(int index)
{
int max = PackCount();
if (index < max)
{
PITEM pitem = ItemStart[index];
return pitem;
}
return NULL;
}
追加 初始化操作:
GameBase* _pgamebase;
void GameBase::Init()
{
//主要负责游戏对接类的初始化
unsigned* addrRead = (unsigned*)0x1256E3C;
SRO_Res = (PRes)0x1036518;
SRO_Control = (PControl)addrRead[0];
addrRead = (unsigned*)0x1037D3C;
SRO_Player = (PAIM)addrRead[0];
InitClassProc(&Res::_ReadTitle, 0x9A46C0);
InitClassProc(&Res::_ReadItemTitle, 0x9A4640);
InitClassProc(&Control::_NormalNotice, 0x848580);
InitClassProc(&Control::_NetNotice, 0x844E40);
InitClassProc(&Control::_ChatNotice, 0x844E80);
InitClassProc(&Control::_GetPPack, 0x866140);
InitClassProc(&ITEM::_GetItemRes, 0x995800);
InitClassProc(&Pack::_GetPackPack, 0x7722C0);
}
void GameBase::InitClassProc(LPVOID proc_addr, unsigned value)
{
unsigned* Writer = (unsigned*)proc_addr;
Writer[0] = value;
}
GameBase::GameBase()
{
_pgamebase = this;
//Init();//初始化基址 完成系统对接
}
装备栏数据结构的分析:
直接搜物品数量找
直接看改写
发现edx是装备编号. 那么1E0就是装备大小了 这是个数组
edx是序号 22d0是固定的 看看esi
发现是要找1C301D94的由来
进入函数
得到基址
装备栏数据与算法C++还原
#pragma once
#include"ITEM.h"
//装备栏
enum class EquipType
{
har = 0,
Jacket = 1,
Shoulder=2,
Hand = 3,
Trousers=4,
Shoe=5,
Weapon=6,
WeaponEx=7,
Ol=8,
Earring=9,
NeckLace=10,
RingLeft=11,
RingRight=12
};
typedef class EquipPack
{
public:
PITEM Getitem(EquipType index);
}*PEquipPack;
测试:
void CUIWnd_1::OnBnClickedButton1()
{
auto _PackBack = _pgamebase->SRO_Control->GetPPack()->GetPackBack();
lstPack.ResetContent();
CString tmp;
for (int i = 0; i < _PackBack->PackCount(); i++)
{
auto item = _PackBack->GetItem(i);
if (item != NULL&&item->Type)
{
tmp.Format(L"[%s][数量:%d][耐久:%d/%d]", item->GetNameByWCHAR(), item->Count,
item->Durability,item->MaxDurability);
lstPack.AddString(tmp);
}
}
}
void CUIWnd_1::OnBnClickedButton2()
{
auto _PackBack = _pgamebase->SRO_Control->GetPPack()->GetEquipPack();
lstPack.ResetContent();
CString tmp;
for (int i = 0; i < 13; i++)
{
auto item = _PackBack->Getitem((EquipType)i);
if (item != NULL && item->Type>0)
{
tmp.Format(L"[%s][数量:%d][耐久:%d/%d]", item->GetNameByWCHAR(), item->Count,
item->Durability, item->MaxDurability);
lstPack.AddString(tmp);
}
}
}