背包属性遍历
从物品数量入手,搜索2字节
筛选出唯一的值
下两字节的访问断点,鼠标移动到物品上面,断点断下
物品数量=r14+0x10
这里就能得到一个+0x10的偏移。然后记录下每层的返回地址
r14来源于r9
r9来源于rsi
rsi来源于r9
r9来源于r14
r14来源于rax
rax来源于rbx,rbx来源于上面的call
继续进call里面追,里面有个循环就是二叉树
追rax的来源
物品数量=[rax+0x20]+0x10
物品数量=[[rax]+0x20]+0x10
物品数量=[rdx+0x20]+0x10
rdx来源于rax,然后这个位置是一个二叉树
rax来源于rdx+8
rdx来源于一个数组
[[r9+rcx*8+0x9FC]+0x8]
r9来源于rcx
rcx来源于一个基地址
[[0x00007FF637D57050+rcx*8+0x9FC]+0x8]
继续追rcx
rcx来源于rax+rax*4
[[0x00007FF637D57050+rax+rax*4*8+0x9FC]+0x8]
rax来源于dx
dx来源于[rbp+0x30],这个地址往上追会追到一个常量。这个数值1代表背包,0代表装备栏
物品名字库遍历
接着我们需要去找到物品名称,一般物品名称是通过一个call来查找的,这个call会传入物品ID,返回物品的名称。我们从物品的名称入手来找到这个call
直接搜索物品名称
下断,让断点断下
返回发现是一个系统函数,我们要追r10的来源。
r10来源于rdx,返回上层
rdx来源于rsi
rsi来源于r8
返回上层,r8来源于[rdi]
rdi来源于rcx
再返回上层,rcx来源于r10
r10来源于rdx
rdx来源于[rcx+0xBC]
[[rcx+0xBC]+0]
rcx来源于rax,rax来源于rdx
再返回,rdx来源于r12
r12来源于r8
r8来源于r13
r13来源于rax。接着来分析这个call
这个call有两个参数,rcx是一个基地址,edx传入的是物品ID。那么我们就可以通过这个call,来拿到返回值
[[rax+0xBC]+0]
然后再通过偏移表达式,拿到物品名称。
继续追下rax
rax来源于[rax+0x20],来源于[rax]
来源于rsp+0x8
来源于r8
[[[r8+0x20]+0xBC]+0]
r8来源于rax,然后就到了一个二叉树,rax来源于[r8+0x8],r8来源于[rcx+0x1A14]
然后来源于一个基地址
名称二叉树:[[0x00007FF66C047050+0x1A14]+0x8]
+0 左子树
+0x10 右子树
+0x29 结束标志
+0x18 物品ID
+0x20 物品对象
名称偏移:[[[root+0x20]+0xBC]+0]
物品的名字可以通过调用call来获取,也可以通过遍历拿到整个名字库
数据整理
mov edx,r15d |
lea rcx,qword ptr ds:[0x7FF66C047050] | 名字库二叉树基地址
call 0x7FF66A16DDA0 | 通过物品ID取物品名称-----------------------------背包物品的二叉树----------------------------
二叉树根节点:[[0x00007FF637D57050+rax*5*8+0x9FC]+0x8]
二叉树基地址偏移:0x2F67050
rax是背包序号
0 装备栏
1 主背包
2 资源包1
3 资源包2
4 资源包3
+0 左子树
+0x10 右子树
+0x29 结束标志
+0x18 物品的下标
物品数量=[root+0x20]+0x10
+0x20 对象
对象+0x10 物品数量 DWORD
对象+0x14 最大数量 DWORD
对象+0xE 物品位置 BYTE
对象+8 物品ID DWORD
通过二叉树拿对象 通过对象拿属性
-----------------------------物品名称的二叉树----------------------------
名称二叉树:[[0x00007FF66C047050+0x1A14]+0x8]
偏移:0x2F67050
+0 左子树
+0x10 右子树
+0x29 结束标志
+0x18 物品ID
+0x20 物品对象
名称偏移:[[[root+0x20]+0xBC]+0]
通过二叉树拿ID 通过ID拿名称
----------------------------通过物品ID获取物品名称----------------------------
mov edx,r15d |
lea rcx,qword ptr ds:[0x7FF66C047050] | 名字库二叉树基地址
call 0x7FF66A16DDA0 | 通过物品ID取物品名称
名字库二叉树基地址偏移:0x2F67050
通过物品ID取物品名称call偏移:0x108DDA0
名称:[[rax+0xBC]+0]
代码编写
背包遍历的代码和周围遍历很相似,这里直接给出相关代码
GameData.h
//背包遍历
_stuObjs GetBagDatas();
//进入背包遍历
void EnterBagDataTree(DWORD dwRoot, _stuObjs& alllist);
//获取每个节点的背包数据
void GetBagDataObjInfo(DWORD dwNode, _stuObjs& alllist);
GameData.cpp
//背包遍历
_stuObjs GetBagDatas()
{
_stuObjs baglist;
//获取二叉树根节点(这里只遍历主背包 1代表主背包)
QWORD dwRootAddr = g_GameAddr + AroundAndBagDataTree + 1 * 5 * 8 + 0x9FC;
DWORD dwBagTreeToot = ReadDword(dwRootAddr);
dwBagTreeToot = ReadDword(dwBagTreeToot + 0x8);
//进入背包遍历
EnterBagDataTree(dwBagTreeToot, baglist);
return baglist;
}
//进入背包遍历
void EnterBagDataTree(DWORD dwRoot, _stuObjs& alllist)
{
//左子树
DWORD dwLeftNode = ReadDword(dwRoot + 0);
//右子树
DWORD dwRightNode = ReadDword(dwRoot + 0x10);
//标志位
BYTE bFlag = ReadBYTE(dwRoot + 0x29);
//标志位为0开始遍历
if (bFlag == 0)
{
//获取对象里面的数据
GetBagDataObjInfo(dwRoot, alllist);
//递归遍历左子树
EnterBagDataTree(dwLeftNode, alllist);
//递归遍历右子树
EnterBagDataTree(dwRightNode, alllist);
}
}
//获取每个节点的背包数据
void GetBagDataObjInfo(DWORD dwNode, _stuObjs& alllist)
{
_stuObj stuBagData;
//设置类型
stuBagData.m_StuType = Em_Item;
//对象
stuBagData.m_Obj = ReadDword(dwNode + 0x20);
//下标
stuBagData.m_Item_Index = ReadDword(dwNode + 0x18);
//物品ID
stuBagData.m_ID = ReadDword(stuBagData.m_Obj + 0x8);
//物品数量
stuBagData.m_Item_Nownum = ReadDword(stuBagData.m_Obj + 0x10);
//物品名字
stuBagData.m_Name = Fn_GetGoodsNameByID(stuBagData.m_ID);
//保存到容器
alllist.m_data.push_back(stuBagData);
}
GameFunction.h
//通过物品ID获取物品名称
wstring Fn_GetGoodsNameByID(DWORD ID);
GameFunction.cpp
//通过物品ID获取物品名称
std::wstring Fn_GetGoodsNameByID(DWORD ID)
{
//1.1 先拿到二叉树的地址 也就是ECX的地址
QWORD GoodsTreeAddr = g_GameAddr + AroundAndBagDataTree;
//1.2 再拿到call地址
QWORD GetGoodsNameCall = g_GameAddr + GetBagNameCall;
//调用call
QWORD qGoodObj = GameCall2(GoodsTreeAddr, ID, GetGoodsNameCall);
//第一层偏移
qGoodObj = ReadDword(qGoodObj + 0xBC);
try
{
//1.5 读取名字
if (qGoodObj)
{
return ReadWChar(qGoodObj);
}
}
catch (...)
{
OutputDebugStringA("读取名字出错了");
}
return L"NULL";
}
实际效果如图:
到这里自动吃药所需要的数据都已经找齐了,下一节我们来完成自动吃药的功能。
Github:https://github.com/TonyChen56/GameReverseNote
完整代码:https://download.csdn.net/download/qq_38474570/79498815