如何结合Cheat Engine和逆向工程找到CS2内存中的人物地址
或许我们的公众号会有更多你感兴趣的内容
这篇文章发布的时候,关于更多CS2-cheats的代码已经在Github仓库中发布,你可以在下面的链接找到更多CS2的外挂功能
https://github.com/Joe1sn/ExtCheats
游戏环境
Steam上启动的CS2国际服,在设置中加上-insecure
参数
在游戏中启用控制台,然后 ` 就可以输入命令了
CS2可以使用CFG
文件进行快速的加载,这里我用了一段cfg脚本来进行编写
1 | sv_cheats 1 |
你可以在steam\steamapps\common\Counter-Strike Global Offensive\game\csgo\cfg
中防止该文件,然后再游戏中使用exec <不含后缀的文件名>
为了方便调试,可以把屏幕大小改为1280x600
PlayerPawn
简单的CE使用
首先使用准确值找到HP值
在游戏中可以使用hurtme xx
来对自身角色造成伤害
这样就找到了几个类似的值,这里有几个要点
- 由于在真实游戏中我们能控制的只有客户端,没有服务端程序,CS的客户端位于
client.dll
中,所以我们需要对其进行分析,而且地址最好和该dll相关 - cs2使用了
Valve
研发的source2
引擎,所以我们可以利用相关开源信息进行查找,比如有人做了cs2偏移的仓库:https://github.com/a2x/cs2-dumper 。
接着找出有哪些地址访问了这些地址,这里有一个取巧的方法,利用上面的偏移,比如HP的全称是Health Point
,那么变量的命名就可能和heal
相关,在上面推荐的仓库就可以找到
那么对上面的内存找访问
添加该RCX
的值,在 浏览相关内存->工具->解析结构体中
我们发现了一个为C_CSPlayerPawn
的结构体,接着我们看访问的代码,有两段
那我们就打开client.dll
,分析下这段代码
文件位于steam\steamapps\common\Counter-Strike Global Offensive\game\csgo\bin\win64
第一段可能为虚函数
第二段位于另外一个函数中,我们主要看rsi
怎么取到的值,结果发现是这个函数的参数
多看看交叉引用发现引用太复杂,随后放弃
PlayerController
从全局变量找到Controller
继续按照上一面的找搜索到的HP的一堆地址的访问地址,发现
同样的方法我们找到这段代码,然后在IDA中分析
IDA中的基地址从0x180000000
开始,加上偏移521BB0
就找到了这段代码,然后对该函数的引用分析
发现普遍存在这几个函数
我们先分析下他是这么找到v12
的,首先在sub_180697FA0
传入了一个v10
先分析sub_180697FA0
1 | __int64 __fastcall sub_180697FA0(int a1) |
存在全局变量qword_18191C5B8
,在CE中分析一下
分析其中的sub_18060A050
1 | __int64 __fastcall sub_18060A050(__int64 a1, int a2) |
其中a1
为全局变量
a2
暂时未知,不过我们可以根据fastcall
的传参顺序( rcx,rdx,r8,r9)或者汇编来看a2
传递的是什么参数
编写python算法模拟一下,但是条件中内存有指针,那没有两种思路
- 利用调试器取值
- 直接都程序内存
这里用第一种,先不管最后一个条件,计算得到v2 = 0000019CA3550808
然后算出v3 = 0x7ffab466e718
1 | def sub_18060A050(): |
用CE看一下*v3
这个指针的值
那么返回的就是00007FFAB4652500
,用CE发现是一个叫做CCSPlayerController
的数据结构
看下github上的偏移表
发现有几处关键信息:
这样就可以通过client.dll + 191C5B8
加上下标,通过刚才的函数,找到了CCSPlayerController开始的地址
Controller到Pawn
我们继续逆向,根据Controller+0x7E4
为m_hPlayerPawn
,就用CE看看这个地址有无读写,在观察下汇编发现
由于CE捕获到的两段代码十分相近,那么给rax赋值的话rax引用就可能出现,搜索对[rax]
访问找到
1 | v11 = *a4; // ////////////// |
其中v11
就是我捕获到的mPawn
值,这里再次出现了全局变量client.dll+1819538
同之前编写脚本计算地址,然后再对照,这里就不再赘述过程了。
得到从CCSPlayerController.mPawn
找到对应CSPlayerPawn
的方法,这段代码在项目的Cheats
的Player
类中
1 | void Player::GetPawn() { |
Controller的数组
到这里算是总结了吧。之前从全局变量找到Controller,有许多没用的比较和逻辑运算,这些是为了对其和限制大小
找到Controller的就可变为,改代码位于项目的Cheats.cpp
中,在Cheats
的构造函数中
1 | DWORD64 ListOffsetA = GetProcessMem(this->hProcess, this->ClientDLLBase + ClientDLL::C_CSPlayerController, 1, 0); |