封包辅助“不得不说的秘密"(2)

2020-11-13 11:20:11 李良人 9

第二章数据逆向之周围目标对象链表

 

最近我广览无数番剧,总结出来一个结论——不管怎么样,反正名字一定要长!~一定要很繁琐!~诶!就很棒!!!

 

原理扯淡:

 

好了骚话不多讲,接下来直奔主题!

 

上几篇笔记我们讨论了封包辅zhu的原理和实例,成功的实现了封包吃药的功能,相比调用游戏功能Call实现功能,绕开了本地代码也绕开了本地检测。

 

但是有一个非常重要的事情没能解决,发送吃药封包有一个很重要的参数——药品在背包中的位置下标。也是呢,不知道药品的位置咋嗑药啊,总不可能我们打开背包去数吧....

万一数错,发了个把盔甲当药嗑的封包,可能当场就没得玩了...

 

好在我们可以通过逆向手段,找出这些我们需要的数据,直接读取它就绝对不会出错了。

 

首先,这些数据肯定保存在游戏中的某个位置;当然,肯定不是胡乱存放的,不然东存一个西存一个,它自己都找不到了。如何工整且高效率高利用率的在内存中存放数据是一门学问——数据结构,游戏里面有那么多的数据一定不是杂乱无章的,肯定都是严格的遵循某种数据结构科学的存放和管理。那么我们通过了解一些数据结构的规律规则,就能容易的通过一些蛛丝马迹找出我们想要的数据!

 

在编程中有各种各样的数据结构,打开百度马上就能搜索到不少,好在通过时间的考验实用性高的结构也就那么几个——字符串、数组、链表、二叉树....基本上能被碰见的就这么几个,只要掌握了它们的结构和特征,在数据逆向中才能无往不利!

 

本期先不讲背包的数据结构,用来当例子的那个私服其背包结构比较复杂,不适合用来初次见面,所以下面让我们来了解了解链表,通常游戏角色周围的怪物与其他玩家的对象就存放在一个链表里面,找到它我们就可以获取到周围目标的对象 在对象下面肯定有它们的坐标属性等待,这样是不是就可以把它们的坐标传入上篇讲到的寻路Call里面,让游戏角色走过去K它们了~

 

PS:最好对C/C++指针、结构体有一些了解哦~

 

链表 链表,这个链字确实非常形象,但是表就非也非也了,这里说的表可不是你正在想象的四四方方的样子,与其说是表不如说是一串佛珠,每一颗珠子都是一个结构体,通常在其固定的位置通过一个指针 指向下一颗佛珠。

 

如图所示,链表在内存中的结构。

飞郁网络培训有限公司 

 

其本身每个结构体在内存中的位置通常都是杂乱无章的,每个结构体通过一个指针指向下一个结构体,就好像一条链子一样。

 

但是这样有一个问题,什么时候没有下一个结构体了呢?通常有两种种情况:

1. 无头链表,每个结构体内部都有一个标志位成员,通常它为1时表示任有下一个,为0时表示没有下一个了。

2. 有头链表,第一个结构体仅仅作为头部标识无其他数据,当指针指向的下一个结构体为头部标识时——即表示没有下一个了。

 

干巴巴的理论看多了也没有意思,还是叫上我们的老伙计——私服版幻想神域2实际操作一下!

 

猥琐实战:

 

要想找到周围目标链表,通过一些其内部的数据入手是最好的。比如,周围有一群怪物,那么周围目标链表里肯定会有它们的实例对象,而对象下面会有它们的属性,其中比较好了解的就是怪物的血量了,但是这个游戏并不会直接显示怪物的血量数值,只会在头上显示一个血条,没有具体数值的话我们在CE中不好搜索它,但是我发现....

飞郁网络培训有限公司

选中一个怪物界面上方会显示其名字与血条,我估计这些信息是从周围目标链表里面取出的,当然这不是很重要 重要的是....

飞郁网络培训有限公司

我们点击一下自己头像,也会选中自己——显示自己的名称与血量,唉 怎么是我们自己就显示具体血量数值了...草(一种植物),先不管它 我估计这个名称和血量 和我们上面说得一样,是从周围目标链表里取出的,周围目标链表里面通常都有自己和附近玩家或NPC。上方的选中显示框是实时更新的,它应该在不断从周围目标链表里取出我们的角色对象访问血量。

 

这样的话,只需要在我们自己的血量上下一个访问断点,这样的话应该可以使游戏断在周围目标链表遍历的代码段,当然最好是先选中其他怪物,然后在自己血量上下断点,点击自己头像选中自己,从而呼出显示框,显示框一呼出一定会立即访问角色血量 游戏会在我们点击自己头像的瞬间断下,这样就可以肯定使游戏断在了我们想要的代码段了。毕竟访问角色血量的代码应该挺多的,如果不是断在周围目标链表遍历的代码 对我们是没有意义的,也是在浪费时间。

 

人物血量我们是可以看见具体数值的,这种一般使用CE搜几次就出来了,所以过程不在过多赘述,得到人物血量地址后 如上述操作...

飞郁网络培训有限公司

断在了这里,Eax+8里面就是我们的血量。追寄存器作为逆向基本功,这里就不再多说了,要值得注意的是 我们追的是一个结构,而非单纯的想回溯出一个基地址;所以我们要时刻注意所追的寄存器里面的内容是否开始变化——下断断下几次的内容都不一样。

 

基本内容不在赘述,我们直接来到所追寄存器内部数值开始变化的地方。

飞郁网络培训有限公司

往上翻几个偏移就是这里了,按照回溯出来的表达式[[esi+0xC]+0xC]+8 下断在Command命令行中DD它,应该是可以跳转到我们的血量地址的,但是事实是不一定 有时候还会跳转到一些数值相同但是地址却不同的地方,这时候我们查看esi这个要继续回溯的寄存器 发现它几次下断,数值都不一样。

 

这很正常,因为我们追得是一个链表,链表里面肯定有许多对象,我想我们应该追到链表的遍历里面了,每次断到的应该就是周围不同怪物的对象,之前我们的表达式会跳转到一些数值相同但是地址却不同的地方,应该就是周围一些怪物的血量,我们的表达式是追人物血量所回溯出来的,但是一般来说怪物、NPC、玩家的对象是结构相似的,可能都是继承于同一个父类,甚至就是同一个类型。所以,人物血量表达式能够通用在怪物对象上面也不奇怪了,所以那些相同的数值 应该是角色身边许多同样怪物的血量。

 

既然知道变化是正常的了,我们继续回溯...

飞郁网络培训有限公司

mov指令,esi来自于[eax]。这时候在上图那条代码下断,却发现不论几次断下,eax都不怎么变化了,基本可以认为不变化了。

 

但是esi的值相当是来源eax的,既然eax不变化为什么esi变化不断?只能说明这一段代码并不是顺序执行的(从上至下),结合我们追的是一个链表 这里应该是一个遍历,2条标注出的代码之间 必有循环!

 

如何找到循环?很简单只有向上的跳转才能产生循环,只要我们选中JCC跳转指令OD会贴心的为我们标注出跳转线,如图:

飞郁网络培训有限公司

一个一个JCC指令的往下面找,产生循环的那条JCC指令应该就在附近!~

 

飞郁网络培训有限公司

 

果然,既然有一个循环,那么说明esi不止来源于上面的eax,它还应该来源于下面到Jmp指令之间的某一条代码!

飞郁网络培训有限公司

也就这一条了,每次执行过这里,都会产生新的esi ; 来源于esi为首地址的结构体的第一个成员指针指向的下一个结构体。

 

现在我们已经知道了如何循环遍历这个链表,但是还需要判断循环遍历什么时候结束,毕竟下一个对象是有限的,我们得知道什么时候遍历到链表的尽头了。

 

产生循环的jmp指令是必定跳转的,所以要想打破这个循环,只能在循环里面寻找能够跳转出循环的JCC指令,循环里面总共就没有几条指令 随便点几下就,如图所示:

飞郁网络培训有限公司

Je指令啊,那说明上面一条cmp esiebx代码,esi等于ebx时循环就会结束,我相信这会你应该可以预料到什么了。

 

再看这里,ebx往上面追几条代码,发现它来自于[ecx+0x8],同时我们也看到,esi的来源之一eax 也是产生自[ecx+0x8],如下图:

飞郁网络培训有限公司

已经非常明了了,周围目标链表是一个有头链表,eax就是那个无用的链表头,新遍历出来的对象也就是esi一但等于它,就代表链表没有下一个对象了。

 

那么接下来只要回溯出链表头eax的基地址,我们就搞清楚这个链表的所有情况了!简单的基本功这里就不再赘述,直接放出分析结果:

 

[[0xF84B74]+0x410+0x8] 链表头

+0x0 第一个成员 指向下一个成员 如果指向链表头则代表没有下一个成员了

 

[[[链表头]+0xC]+0xC]

+0x8 目标对象的血量

 

这样通过遍历我们可以得到周围目标的对象,而对象下面一定包含它们的属性,简单翻一翻就能找到比血量更有价值的东西,比如坐标、对象ID等 都是实现自动功能不可或缺的数据呢!~


电话咨询
QQ客服