查找数据主要包括:背包数据遍历、NPC数据遍历、怪物数据遍历、地面物品数据遍历、技能列表遍历、周围玩家数据遍历、地图数据的查找、人物信息的查找等等。
本次只讨论需要遍历的数据
为什么要遍历数据?
一般来讲是给我们找到的call当参数使用的,比如我们找到打怪call,但是这个call需要一个参数是怪物的指针,我们上哪去弄这个指针?我们只能去遍历怪物数据,这些数据包括怪物指针,怪物的坐标,怪物的血量,名字等等信息,把有用的信息提取出来,用编程语言写个数据结构把它存起来供我们使用时候用。
需要遍历哪些数据?
不同数据需要不同的信息,如果是提供给call使用的话,我们主要看call需要什么类型的数据,是怪物的指针啊,还是怪物的ID,当然我们也可以遍历一些用处比较少的属性,比如怪物名字
找到的遍历结果一般是什么样子的?
本次不讨论链表结构和二叉树结构,只讨论数组结构,比如我们找到的背包物品个数的数组的形式可能是:
个数=[[[[[基地址]+a]+b]+格子编号*0x40]+c
这个时候我们就发现[[[[基地址]+a]+b]+格子编号*0x40是某个格子的指针,从而推导出其他属性,比如我们可能推导出
名字=[[[[[基地址]+a]+b]+格子编号*0x40]+d
最大叠放=[[[[[基地址]+a]+b]+格子编号*0x40]+e
使用等级=[[[[[基地址]+a]+b]+格子编号*0x40]+f
物品ID=[[[[[基地址]+a]+b]+格子编号*0x40]+h
………
所谓推到办法,就是看看背包数据,再看看内存数据比较下,猜测出偏移,再验证下,验证方法:修改内存,看看物品有没有相应的更改。
如何遍历背包物品数据
好了,不废话,说说如何查找这个数组,首先我们必须有个切入点,背包物品最好从背包中某项物品的个数入手,因为很多情况这个数目不止一个,并且可以改变,比如血瓶,右击一下就减少一瓶。
我们直接有CE搜索995,使用一瓶搜索994,搜索出来两个结果,
再改变数量发现还是这个两个地址,这两个地址都是正确的,但是他们表达的含义不一样,我们将血瓶移动到第二个格子看看,发现一个值变为0,这就说明这个地址指向的是背包第一个格子中物品的数量,而不是血瓶数量
我们查看访问这个地址的代码,然后把血瓶移回第一个格子,看到代码
打开OD,找到代码,找到代表物品数量的表达式[eax+14],下面的工作就是找基地址,找这个eax的基地址。
第一个格子中物品的数量=[[[[[[[[15AC044]+10+4]+4]]]+0C+4]+30+4]+ 0*0x28 +0x14]
如何确定这是个数组呢,以及第二个格子和第一个格子的差别应该差在哪里?这个一般在寻找基地址时候就会发现,
比如,举个例子,我们首先得到 第一个格子中物品的数量=[eax+14],我们挪动血瓶发现eax的值每个格子都不一样,并且是个等差数列,这不就明显了吗?哈哈
研究游戏名字为《龙武》实战检测,他的背包数据很奇葩,有两个基地址,前32个格子统一基地址,剩余格子(不足32个)另一个基地址。最终确定格子中物品数量表达式为:
前32个格子:[[[[[[[15AC044]+10+4]+4]]]+0C+4]+30+4]+ 格数*0x28 +0x14 格数范围0-1f
剩余格子: [[[[[[15AC044]+10+4]+4]+8]+0C+4]+30+4] + 格数*0x28 + 0x14
寻找数据的思路:
上面就是按照数量的找法,也有看过相关教程按照每个格子的指针找的,即,每个(些)都应该有个指针,格子会盛放这些指针,互相改变格子中的物品,这些指针也应该随之改变,并且空格子的指针应该为0,按照这个思路用CE找,也可以找到一个数组,一个指针的数组。但是这些指针是否有用的,如果有call直接使用这些指针的话,这些指针就是游泳的,如果没有的话,还有需要研究这些指针指向的地址盛放的东西的话,这个研究方式就不太好了,最好是直接下手,需要数量数组就从数量下手,需要ID数组就从ID下手,需要名字就从名字下手。
追寻基地址的一些实战感悟:
感悟1:
毫无疑问如果可以用CE就能找到基地址的话,那实在是太方便了,快速而高效,但是有些时候我们只用CE找不到基地址,这个时候我们只能用OD了,最好是OD和CE结合着用,没找到一个地址就先用CE试一下。有时纯CE找不到基地址原因如下:
1.用CE搜索一个中间地址,搜索搜索结果为空。(中间地址:非基地址,如:物品个数=[[435C9660+0C+4]+30+4] + 格数*0x28 + 0x14,这其中的不是基地址,我们把它简称为中间地址)
2.搜索到了地址,右键查看访问代码,结果没有代码出现
3.出现了访问代码,最后也找到了一个绿色的地址,突然发现这个绿色地址盛放值是可以变动的,突然为0了等等。
感悟2:
有时候用OD跟踪找基地址,会发现越来越深,这个时候最好做个中间记录,省的一次追不完,下次又得重头开始追查,比如我们追背包中物品数量的基地址,可以先做个记录
物品数量= [[435C9660+0C+4]+30+4]+ 格数*0x28 + 0x14
并且记录下追到的代码地址,下次接着从这块代码入手,
00E07BD1 8B4D EC MOV ECX,DWORD PTRSS:[EBP-14]
00E07BD4 83C1 10 ADD ECX,10 ; ecx=11014270
00E07BD7 E8 A4140000 CALLLWClient.00E09080 ; 关键call,在堆栈中写入435C9660
00E07BDC 8D55 F0 LEA EDX,DWORD PTRSS:[EBP-10]
00E07BDF 52 PUSH EDX
这个结果最好验证下(验证方法,dd [[435C9660+0C+4]+30+4] + 格数*0x28 + 0x14,如果435C9660是个堆栈地址需要在代码处下断点再执行命令)
感悟3:
基地址嵌套很深,最后追到基础地址却忘了一路是怎么过来的,不得不模拟走好几遍才能把最后的表达式写出来,这时有个方法,很有效,方法如下:
比如我们先追到了一段,记录下
品数量= [[435C9660+0C+4]+30+4]+ 格数*0x28 + 0x14
接着我们追这个435C9660的地址是怎么来的,没遇见一次赋值记录下来,没有偏移并且没有指针就不记录了,比如move eax,ecx就不用记录了,追的地址没变,记录下每次地址改变值,直接记录值就可以了,记寄存器名字反倒不方便,记录如下:
435C9660=[435C9740]
435C9740=[435C9420]
435C9420=[1B757924]
1B757924=1B757920+4
1B757920=[11014280+4]
11014280=11014270+10
11014270=[15AC044]
把这些地址迭代进去就可以得到最终的基地+偏移表达式了
物品数量= [[[[[[[15AC044]+10+4]+4]]]+0C+4]+30+4]+ 格数*0x28 +0x14