列表类数据定位:从背包、仓库到周围 NPC

1. 背包数据分析

1.1 通过 CE 进行数据查询

通过不断改变背包中某个物品的数量来查找我们需要的数据

我这里是通过背包的血量道具直接搜索初始值,使用之后再次搜索新的值直接就能找到了

cmp dword ptr ds:[edi+70],1               |edi==31F32748

1.2 x32数据堆栈回溯

继续向上寻找 edi 的来源,发现 edi 来自 [esp+84],我们去堆栈区看一下,发现是一个 call 的第一个参数,那我们继续向上找

返到上一层我们发现上面的第一个 push 竟然是 push 0,这肯定不对,这个时候我们注意一下旁边的跳转线,估计一下应该就是从上面 jmp 下来的,应该是 push eax 才对,那我们继续去找 eax

注意:大家如果不确定可以通过下条件断点的方式来判断自己的分析正不正确,这里只需要好再 push eax 的位置下个条件断就能判断出来

往上走没多远就发现了一个 call

这里下端也能发现确实 eax 是来自这个 call,那在该 call 出下断步进查看一下

跟进这个 call 我们也能发现最终数据来自 ecx,我们退出去看一下

其实这个时候就能发现 ecx 已经不变化了,而且上方也显示 ecx 来自 [esp+2c],而且我们发现它并不是某个 call 的参数或者什么,那就是一个全局变量嘛,我们先看看有没有直接对 [esp+2c] 的赋值

大家可以自己看一下,上下部分确实没有相关赋值,这里也给大家说一下相关方法

关于堆栈数据无法找到对应赋值的解决思路:

  • 思路一:对我们找到的最后的数据下访问断点,比如这里,我们最后找到 ecx,那么我们可以通过对 ecx 地址下访问断看能不能找到具体来源,如果找到就可以从这个思路去继续找,不过这里确实断不下来
  • 思路二:我们可以在 CE 中搜索一下这个地址,看能不能找到来源
  • 思路三:我们直接去这个 call 的头部下断,一步一步步过执行看一下有没有跟我们要找的数据相等的数据或者相近的数据,这个思路也是最为经常用的一种思路,我们这里也是通过这个方法找到的

通过下图我们也能看到 edi+8 就是我们的数据,那我们就继续跟 edi 找 edi 的来源,这里我们其实也能看到 edi 来自 [eax+14],eax 来自 [eax+8],eax 来自上面的 call,我们进 call 看一下

进去可以发现确实是我们要的数据

1.3 堆栈+偏移总结

那么背包的基址加偏移我们就能总结出来了:

但是这里我们要注意一点,我们找的 edi 的数据 +8 才是我们之前找的数据,一定要记得加上

[15282D8]+24]+90]+8]+14]+2c]+eax*4]

物品数量:+70

我们通过 CE 验证一下

这里我们就以第一个格子举例:

确实没问题

那么这里我们找这个背包物品就成功了

2. 仓库数据遍历

2.1 CE数据查找

我们接着按照这个思路趁热找一下仓库数据遍历

这里我也是通过不断向仓库中放入同一个物品找到了对应的地址

2.2 x32数据堆栈回溯

这里我们发现也来自和背包相同的位置,我们继续向上看一下

发现也是来自 [esp+84],继续去堆栈中向上找

发现这次直接来到了这里,那对应的数据肯定就是 eax 了,我们进上面的 call 看一下

这里还是一样的结构,那我们继续出去找 ecx

发现来自于 [esp+24] 的位置,且堆栈数据还是全局变量,这里去上下找还是找不到还是去头部开始单步步过找相关数据

这里找到 eax+8 就是我们对应的数据,那么继续去找 edi

发现来自 [eax+8],进 call 去看一下

2.3 仓库数据总结

这里仓库的基址 + 偏移我们就得到了

[15282D8]+24]+90]+8]+38]+2c

3. 周围怪物 NPC 数据分析

3.1 CE数据查找

我们再分析一个有关周围怪物的数据,突破口我这里是通过选中 NPC,修改 NPC 名字的方式来找的

3.2 x32数据堆栈回溯

找到突破口我们去 x32 中看一下,我们对该位置下个访问断,根据断点位置,我们去找对应的 eax

发现 eax 来自 ebp,ebp 来自 [esp+C] 我们下断可以看到来自于 call 的第一个参数

返上去我们发现来自于一个 call eax,我们下断进去看一下

进去发现来自 [ecx+898],继续去找 ecx

退出去发现 ecx 来自 esi,esi 来自 [eax+edi*4],eax 来自 [ebx+AC],我们继续去找 ebx

这里也给大家看一下,我们可以看到 ebx 来自 [esp+24],但是这里我们可以看一下堆栈

这里我们返过去其实能够看到啥也没有,这里我们还是老样子去看有没有赋值或者其他的相关数据,这里我们也能看到最终来自 eax,我们进上面的 call 看看

进去之后我们就能看到基址了

3.3 关于怪物 NPC 的数据总结

到这里,我们关于怪物 NPC 的数据的基址加偏移就能确定了

怪物名字:

[15282D8]+24]+c]+74]+AC]+edi*4]+898

4. 总结

这一篇找的三类数据——背包物品、仓库、周围怪物 NPC——目标各不相同,但走的是同一条路。

第一步,先用 CE 把数值锁成一个地址。

背包靠反复改变某个物品的数量,仓库靠不断放入同一个物品,怪物 NPC 靠选中后改名。思路是一样的:找一个你能主动改变、且变化结果能立刻在游戏里看到的量,然后「改值 → 再搜」,一轮轮筛到只剩少数候选。突破口选得好,后面能省一半力气。

第二步,下访问断点,看是哪条指令在读这块内存。

断下来之后,从这条指令往上找「持有该值的寄存器是从哪来的」。数据来自 [esp+xx] 就去堆栈区看它是哪个 call 的第几个参数,再返回上一层去找那个参数。返回之前务必先核对数据是对的。

第三步,也是这篇真正想讲的:回溯断在半路时怎么办。

背包这里就卡住了——追到最后发现数据来自 [esp+2c],而它既不是某个 call 的参数,上下也找不到任何赋值,是个全局变量。这种「堆栈数据找不到对应赋值」的情况,本文给了三条思路:

  1. 对最后找到的数据下访问断点,看能不能断出具体来源
  2. 在 CE 中搜索这个地址,反查谁持有它
  3. 去 call 的头部下断,单步步过执行,盯有没有和要找的数据相等或相近的值

前两条在这里都没走通,最后是第三条找到的:一路步过发现 edi+8 正是目标数据,再顺着 edi 的来源逐层往上回溯,整条链就串起来了。后面仓库和怪物 NPC 两节,遇到同样的卡点,用的也是这个办法。

这里我们可以总结一下:

  • 突破口优先选「你能主动改、游戏里立刻能看到变化」的量——数量、名字、血量都行
  • 回溯时每一步都先确认数据正确再往上走,方向错了只会越追越远
  • 追不动了别硬追,多想想原因
  • 三类数据的结构其实很像,背包和仓库连中间几层都重合——找到一类之后,其余的可以顺着同一套结构去套