游戏外挂原理解析与制作 - [内存数值修改类 篇一]

频道:外挂推荐 日期: 浏览:19
  本章旨在讲解外挂实现原理,未深入涉及至代码层面。希望能与对这方面感兴趣的朋友多多交流,毕竟理论是死的,套路是固定的,只有破解经验是花大量时间和心血积累的。 对于单机游戏而言,游戏中绝大部分的参数(比如血、蓝、能量亦或是金币)都存储在计算机的堆栈中,一些类似剧情进度的则加密后写入本地的自定义配置文件中; 对于页游、网游和手游,虽然服务器保存了大量的重要的参数,但由于客户端不可避免的需要进行大量的计算和资源的加载,本地内存种必定存有部分的临时变量,通过判断这些变量的变化规律和函数的破密寻到利于自身的参数,比如伤害值一类,继而寻找该变量的内存地址,根据指针偏移分析获得内存基址,再提升权限利用Windows API把自定义数值写入该内存块,就完成了修改某项数值的操作,一般来说,只要破解了一项数值,利用规律继而破解其他数值就更加容易了。    一般套路就是上述,一些防护性强大的游戏会在上述的每一步中都设置难题,等着我们去破解。    在此之前,我们来了解一些基础知识: 数据类型:游戏中的血量、蓝、生命值,我们将他们称之为变量,变量包含了变量名称和数据类型,那么它的名字就是"血量、生命值"等等,而它的数据类型决定了数值以何种方式存储到计算机的内存中,想要找到自身需要的变量,如果可以确定这个变量的数据类型或者有根据的推测来缩小变量的数据类型范围,那么对于快速定位该变量是具有帮助性的。以下是几种常见的变量类型:    整数型:游戏中比如血量、法力可能用到这种类型。    字节型:根据不同的编辑器,1个整形占用N个字节(N>1),一般很早之前出产的GBA游戏为了节省开销会用到这种类型。    浮点型:带有小数点的数字,如果金币或者伤害值带有小数点,那很可能是这种数据类型保存的。    文本型:比如世界喊话,人物命名,一般采用文本型保存这类数据。    推荐阅读《数据结构》相关书籍更好的熟悉数据结构,有编程经验的就不必多说了。 进程:每一个应用程序/游戏启动,都会产生至少一个进程Process,在任务管理器里可以看到进程名称和进程PID。     句柄:英文HANDLE,一个整数值。数据的地址需要变动,变动以后就需要有人来记录管理变动,就好像户籍管理一样,因此系统用句柄来记载数据地址的变更。肉眼看到的一个个文件夹,窗口,按钮,图标,应用程序能够通过句柄访问相应的对象的信息   推荐阅读《计算机操作系统》相关书籍更多的了解计算机原理。      进入正题,根据目的反向推导下需要得到哪些信息,我们最终才能想要实现修改数值。   修改变量的数值→得先找到存储变量的内存地址→得先找到游戏窗口的句柄→得先找到游戏的进程。   根据什么依据推导出的路线呢?   Windows系统库的kernel32.dll库文件中包含了内存操作的API,其中VirtualQueryEx用于查询地址空间中内存地址的信息。   函数原型:   我们下面逐个分析参数:   hProcess:顾名思义,进程句柄,也就是说想要查询地址存放的信息,首先得获得进程的句柄。   lpAddress:查询的内存地址,输入参数,需要主动提供地址。但我们并不知道我们需要的数值它被存放的地址,我们只能一个页面一个页面的猜测,直到扫描到某个页面的某块内存里面存放的信息正是与我们需要的信息一致或是存在一定的函数关系。其次,对于同一个数值也许出现在多个地方,比如 在某个时间区间人物的攻击数值和防御数值等同都为1200,那么说明至少有两个地址存放了这个数据。我们需要把这些地址全都筛选出来。   lpBuffer:结构体指针,用于存放内存信息。   dwLength:上述结构体的大小。   返回值:函数写入lpBuffer的字节数,如果字节数等于结构体PMEMORY_BASIC_INFORMATION的大小,表示函数执行成功。   但此函数只负责获取内存信息,而查询内存信息中具体存放数值则用到另一函数ReadProcessMemory,来看一下函数原型:   此函数将根据句柄读取该进程的某个内存空间,并将读取到的字节数写入到我们开辟的一块空间中,而此空间存放的正是我们苦苦追寻的“有意义的数值”。此函数的部分参数依赖于上一个函数VirtualQueryEx产生的结果。   根据上面的API,先来看怎么获取第一个参数:窗体句柄,同样的kernel32.dll提供了名为OpenProcess的函数用来打开一个已存在的进程对象,并返回进程的句柄。   函数原型:   dwDesiredAccess :渴望得到的访问权限,这里默认填写PROCESS_ALL_ACCESS | 0x1F0FFF 给予所有可能允许的权限。   bInheritHandle :是否继承句柄,FALSE即可。   dwProcessId :进程标示符PID。   对于进程PID各种编程语言有自己的获取方式,以C#语言为例(针对非多开客户端):   我们获取到进程的PID以后,就可以调用OpenProcess获取窗体的句柄,然后利用函数VirtualQueryEx遍历内存查找地址信息,根据地址利用ReadProcessMemory查找具体存放的值,最后利用WriteProcessMemory把修改后的值写入该地址,这样就完成了一次数据的修改。来看一下API的函数原型: