游戏修改器实际上就是定位并且修改数据(代码也是数据),有通用修改器比如CE和专用修改器两种,这里主要讲通用修改器。
定位的过程包括数值的定位和代码的定位。 其中数值的定位是最简单的,原理就是首先知道想要改的数值,比如血量,扫描整个游戏内存,然后搜索指定值,找到以后得到可能的值,如果数据比较多需要缩小范围,就是等数据发生变化后从之前的结果中搜索出变化后的数值,逐步缩小范围,得到需要值的内存地址。
得到内存地址后就可以修改数值了,不过只能临时修改,如果要制作修改器,一般有两种方法,一种是找到从固定地址到达这个地址的路径,一种是修改访问这个地址的代码。 这两种方法就都需要对汇编处理了,首先要在找到的内存地址上设置访问断点或者是写入断点,找到修改它的代码,如果是第一种就要向前查找游戏是怎么访问这个地址的,比如一个游戏有一个全局资源管理器,里面有一个当前场景的指针,当前场景里有一个指向玩家的指针,玩家里有一个指向当前生命值的数值,你需要一层层往上找,直到找到从全局变量出发到达所需修改数值的路径,全局变量是固定的(不考虑重定向的情况下,一般只有DLL可以重定向,这种情况下要从模块基址+偏移方法寻找)。第二种方法就比较简单了,比如造成伤害就是把数值减去伤害值,只要把这行指令改成空指令就行了,不过要注意可能会有副作用,比如对敌人造成伤害也是这个代码处理的那就会导致你也无法对敌人造成伤害,这时候就可以补充更长的代码来执行,但也需要更多的反汇编基础,对游戏的运行方式和数据组织结构有了解。
修改器原理就是这样,不过在实现上有许多细节问题要考虑,比如搜索需要知道游戏采用的数据类型,还可以跳过不可更改的代码段提升效率之类的。此外,现代的操作系统上不同进程的地址空间是独立的,所以要访问其他进程的数据需要使用系统API,在Windows下分别是ReadProcessMemory和WriteProcessMemory。
而定位代码实现上就比较复杂了,要找出修改指定地址的代码修改器本身需要是一个调试器。在Windows下,调用DebugActiveProcess可以调试指定进程,然后就可以用WaitForDebugEvent等待调试事件了,只要程序产生异常都会自动暂停然后把消息发给调试器处理。 那么就需要主动使得程序产生异常,断点本身就是一种异常,可以通过硬件断点和内存断点来实现。硬件断点则是将DRX寄存器设置成需要的地址,然后修改状态寄存器,SetThreadContext可以实现这个功能。内存断点则是设置内存为不可写状态,然后保存之前的状态,这样游戏访问指定的内存时就会产生内存访问异常。不论哪种情况发生异常后调试器都会得到控制权,可以知道代码的位置,然后还需要反汇编器来处理这区域的代码方便阅读,CE就有这部分功能。如果要修改汇编代码还要有汇编器,这些可以用现成的库实现。
专用修改器就只有写入数据这一项了。不过有一点,如果要补充大量代码的话需要在目标进程申请新内存(用VirtualAllocEX)写入修改后的代码,然后原来地方的代码改成跳转指令,地址也是新内存的地址。这种方法叫Inline Hook,如果修改的地址是系统调用的地址就可以拦截系统API,比如修改时钟就把导入表中时间相关函数如QueryPerformanceCounter的地址替换,插入代码增加或减少返回值就可以修改游戏时间。 现在的修改器生成器基本都可以自动封装之前这些步骤,比如Auto Assembler,最大的工作量还是分析游戏程序本身。
另外CE本身是开源的,不过Delphi是个比较老的语言了,用的人已经不多了。
游戏修改器的实现原理和过程是什么?
0 条评论