现在CS2外挂层出不穷,基本大部分的外挂功能都已被实现,其中在我研究过程中比较有意思的就是外部静默自瞄。当然静默自瞄在注入游戏后是很容易实现的,只需要Hook CreateMove这个函数进行拦截CMD这个结构数据,然后进行视角的修改即可,但外部比较难实现这种方法,但也可以从此函数入手来研究,所以就有接下来的分析过程。注:此文章仅分享逆向过程以供学习参考,并无传播、提供外挂等非法程序。
由于游戏是3D世界,所以方向大部分是用欧拉角来表达,即Pitch(俯仰角)、Yaw(偏航角)、Roll(翻滚角)三个数据,静默就是修改开枪旋转角,在本地相机旋转角不变的情况下修改开枪旋转角,就可以实现不瞄准目标但又可以射击到目标的功能。而在CS2中CreateMove函数参与移动相关的所有操作,例如:相机旋转角改变、人物移动、人物动作等等,函数原型如下:
其中"CCSGOInput"类包含了所有相关数据,具体实现功能就是拦截并修改此指针数据,所以我的入手点就在这个函数。
首先使用IDA分析"client.dll"此文件,在String窗口中直接搜索"CreateMove",可以在String窗口看到这些文本。选中第二个,查看交叉调用可以发现有且仅有一个函数这个函数就是CreateMove
静默最主要的数据就是相机的旋转角数据,因为开枪的旋转角与相机旋转角数据一致,注:Rotation{Pitch,Yaw,Roll},所以先去Github上的cs2-dumper项目中找到ViewAngle的地址,添加到CE以便对照寄存器数据进行调试定位。然后在Memory Viewer里面跳转到CreateMove函数,直接下断F8单步走一遍,过程中打开着FPU窗口观察XMM寄存器数据,因为旋转角数据是浮点数,所以在调试代码过程中观察是否能看到旋转角相关数据,就可以快速定位相关代码段,发现在这行汇编代码后的一片地址都没有执行过 所以我们直接略过下面一片代码,直接跟着跳转过去继续单步执行下去。当执行完这个Call后,XMM1寄存器出现了一个熟悉的数据可以和旋转角数据对照,发现是相机的Yaw数据。这个Call有点嫌疑,直接NOP后,在游戏中开枪,发现射出的子弹方向和实际相机方向不一致。 基本可以确定开枪角度的写入是在这个Call内部,所以打标签记录一下这个函数,直接跳转到函数内部进行继续分析。(这个函数后面发现是之前IDA String列表的第一个文本交叉调用中的函数。注:图三)开着寄存器窗口继续F8单步走跟代码,跟到这一行代码发现XMM0首次出现了Pitch数据,与我们ViewAngle的数据一致 继续执行后可以看到XMM0、XMM1分别就是旋转角Pitch和Yaw。 所以就可以确定是上面这两个关键代码获取到旋转角数据,并分别赋值给[rcx+18]和[rcx+1C],可以猜测下一个的XMM0赋值代码便是Roll数据,但是Roll数据一般是0,所以这里不讨论下面部分的代码。所以就可以在这附近进行拦截修改rcx相关寄存器地址的值,达到修改开枪角度的效果,下面进行验证。
我们在0x87C37C偏移处进行简单的Hook来验证,看看修改[rcx+18]以及[rcx+1C]后是否能成功修改开枪视角。这里先直接使用CE的自动汇编来快速的写一个Hook脚本,将[rcx+18]以及[rcx+1C]拦截修改为[newmem+50]和[newmem+54]两个地址的浮点值。执行脚本后射击发现子弹射击角度和相机角度不一致,修改[newmem+50]以及[newmem+54]后发现可以正确的修改子弹射击角度,那就可以确定这是我们所需要的效果。
我和好友在人机房间进行测试,让好友看我观战视角,然后我这边启动Hook脚本,发现在线观战是有效果的,并且在其他玩家的第三人称视角也是有效果的,在其他视角我的人物开枪方向和实际子弹射出方向不一致,由此可得出结论此功能效果是在线有效,而并非仅本地有效。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
逆向爱好者 跳起来不咋准整
Liv_T 需要配合RCS系统来调整,这个仅供修改开枪视角。
逆向爱好者 他子弹碰撞运算逻辑是服务器运算的还是本地运算
mb_snqzioxv 这支枪弹道偏左,这是谁的枪
Liv_T 仅子弹出射角度是本地,子弹坐标、碰撞之类是服务器运算
逆向爱好者 看来游戏为了遏制变态挂专门整了个服务器运算
veryluckko 可以看一下netchan相关结构,有一个bSendPacket,当你写入0的时候,你这个usercmd会被choke住不发送,这时候你可以修改该usercmd的pitch和yaw,然后取消choke, ...
木志本柯 这个从cs起源开始就是这样设计,服务器会继续模拟客户端的子弹在走一遍相同的逻辑。最终执行的结果以服务端的结果为准。