揭秘封包辅助外G:处理游戏多线程发送封包(三)

时间:2024-03-25 14:01:31

又是一个风和日丽的早晨,又对一款游戏产生了念想,又是熟悉的传统手艺——断点发包函数定位功能Call。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
奇怪的是无论怎么Ctrl+F9 都返回不到功能call, 点击OD快捷栏 K 按钮 查看堆栈调用关系,才惊讶的发现 无论做什么动作断下,调用关系都是一样的,也就是说游戏中任何动作都是走的一样的函数一样的代码?

揭秘封包辅助外G:处理游戏多线程发送封包(三)
揭秘封包辅助外G:处理游戏多线程发送封包(三)
当然不可能的,不同的动作不同的功能,怎么会是同样的代码产生的呢!在断点发包函数的时候,遇到这种现象 只能说明厂商对发送封包进行了特殊的处理。就像小说里面的鬼打墙,让我们一直在同样的代码里面打转转。

不过这种手段远没有鬼打墙那么邪乎,它只不过是把发送封包的责任交给了一个子线程——俗称线程发包。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
原理如图:
揭秘封包辅助外G:处理游戏多线程发送封包(三)
上图就是线程发包最简单明了的情况了,厂商把游戏的功能代码和发包代码放在了不同的线程里面。通过一个一个不变的地址或者结构互相联系。

子线程发包,这个线程里面恐怕是一个死循环,一直在查看全局变量里面是否有游戏主线程写入的封包内容,如果有那就发送出去。

现在的情景就一目了然了,既然是死循环 那么循环里面每次运行的代码必然是一样的,所调用的函数也必然是一样的,那么每次的堆栈也是一样的。这就解释了为什么我们会看到一模一样的堆栈调用关系了。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
哪怎么才能正常的断点发包,找功能call呢?很简单,以前游戏主线程会直接告诉服务器,游戏角色干了什么事情,现在只不过是把角色干的事情写入到全局变量里面。 只需要在写入的地方下断点,我们照样能够找到游戏的功能函数。

要在写入处下断,首先就得找到它的位置,它在哪? 也不困难,在全局变量上下一个内存写入断点,自然就会断在写入处。

好的,哪全局变量它又在哪?

解决一个问题总是会引出另一个问题,好在无论什么问题都有解决之道等待着我们去发现、去摸索。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
现在我们知道,全局变量存储的是封包内容,而且子线程会调用发包函数把 封包内容发送出去,而我们已经知晓了发包函数,无非就是WSASend send sendTo,而封包内容会作为参数传入函数中,只要我们在OD中对这个参数溯其来源,自然可以找到那个不变的地址或者结构。

真是欣慰终于没有套娃了,现在我们终于跳出了这个该死的循环,可以继续快乐了。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
实例:

光说不练假把式,利用自己搭建的私服游戏幻想神域2 做个实战练习。

这个游戏使用WSASend发包,直接在头部下断点,Ctrl+F9返回上一层。

然后我们在调用WSASend的call指令上下断点,以此在OD堆栈窗口查看它的参数。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
其实都没必要我们自己下断点分析了,由于是常用的系统函数,所以OD直接帮我们分析并标注出来了。WSASend 第二个参数pBuffers 是一个结构体地址,这个结构体第一个成员是包长,第二个成员就是包内容的地址。

在往上面回溯之前,我们还有一些准备工作。再次在WSASend 下断点,依次Ctrl+F9 把线程发包里面调用的函数全部标记一下,如图。

揭秘封包辅助外G:处理游戏多线程发送封包(三)
很简单,就这样依次 1. 2. 3. 4. 5… 这样标注下去。

接下来开始回溯包地址的来源,没什么太多好说的 逆向的基本功 唯一要注意的是 pBuffers来源于一个局部变量,在汇编中常常以[esp+XX]的形式出现,但是esp 栈顶指针是受到很多指令影响而变化的,所以 这里要追的是 [esp+0x28] 但是往上面一些 这个局部变量可不是 [esp+0x28]了,所以要细心的注意影响栈顶指针esp 的指令,从而推算出我们要追的局部变量是[esp+什么]。

一段无趣的回溯过程之后…
揭秘封包辅助外G:处理游戏多线程发送封包(三)
来到了这里,发现如果是角色动作引起的发包,edi 是一个固定值 那么 edi+2888 也是不变的,还记得上面说了什么吗?不变的地址!

来激动的心颤抖的手,在edi+2888 这个内存上下一个写入断点。断在了…这。
揭秘封包辅助外G:处理游戏多线程发送封包(三)
哦!~老天,我们从鬼打墙墙里面出来了么?

别高兴得太早,我们在上面下断点 Ctrl+F9 试试…
揭秘封包辅助外G:处理游戏多线程发送封包(三)
来到了这?还记得之前说的准备工作吗? 这不是我们的标记吗? 也就是说这是线程发包调用的函数,我们还在镜子的世界里!!憎らしい!!

其实也很正常,我自己也常常这样。先把某个全局变量 或者 函数返回值,先复制一份放在函数里面的局部变量里,方便操作。

好嘛!失败是成功之母,至少这次也算是前进了一步,继续接着回溯。

就在写入断点断到的位置不远,又发现不变化的地址了…嘿嘿嘿…这个应该…
揭秘封包辅助外G:处理游戏多线程发送封包(三)
激动的心颤抖的手,在edx 这个内存上下一个写入断,断下如图.
揭秘封包辅助外G:处理游戏多线程发送封包(三)
下断Ctrl+F9。
揭秘封包辅助外G:处理游戏多线程发送封包(三)
(请忽略我之前的注释)
是陌生的代码!没有我们的标记!我们一起成功的走出了鬼打墙!!!

不愧是我
揭秘封包辅助外G:处理游戏多线程发送封包(三)