前言
关于指针找法,多种多样,其中最为“著名”的就是“跟踪法”。它通过跟踪关键数据,来找到各级指针和偏移,从而得到最终数据。此法虽然基础准确(熟练的话,不管对找CALL还是找关键代码都很有帮助),但其平均效率可能只能归于到O(n^2)的级别了。对于新手来说,一定的成就感是激发学习兴趣的一定催化剂。如果练习的目标层层递进,刚好“合适”,那最好不过。但大多数情况下,新手都只是对自己喜欢的目标感兴趣,而一般情况下使用“跟踪法”的结果大多是失败的。失败次数过多,对于大部分人来说,是劝退的直接原因。若想对新手友好,就必须改变使它的效率和难度都一定比例的下降。这里就不得不说到人造指针,它通过找到关键代码,读取关键地址,而获得关键数据。但就目前大多数相关教程来说,只应用到最基础的层次:改变获取。而对于像普通指针一样,加载即获取的性质是不具备的,这样每第一次更改数据还需人为“修改”一次,使得交互性打了折扣(大家都想“所见即所用”,不是吗?)
本文就人造指针进行进一步拓展,使获取指针方式更加高效
PS:
本文所有技术资料仅供研究,不鼓励任何盗版商用行为
欢迎文明转载,请注明出处 御坂00001号
本文所有红色标记处,为理论核心,也就是其它说再多,最后还是归结于这样的一句话
知识准备
我把人造指针分为两个阶段:基础和提升,下面为示区分,以 人造指针-基础 和 人造指针-提升 命名,而它们的共同之处就以 人造指针 表示
首先,我们来说说人造指针-基础的基础概念和其适用范围
人造指针-基础:找到关键代码,读取关键地址,而获得关键数据
适用范围:一种方式一次调用
暂停一下,这里所谓的“一种方式一次调用”是指啥呢?是这样的,当我们使用CE对数据进行找什么访问或找什么写入时,对于关键代码的 调用次数 是存在不同情况的,下面一一列出它的类型以及说明
1. 一种方式一次调用:即关键代码所在的CALL,只用来访问或写入一类数据,而且一次动作(使某数据变化的行为)只触发一次。比如植物大战僵尸里的阳光增减的关键代码,它只在阳光改变时调用,且只调用一次
2. 一种方式多次调用:即关键代码所在的CALL,只用来访问或写入一类数据,但一次动作触发多次。比如魔兽争霸3冰封王座里的物品栏数量增减的关键代码,它只在某个物品栏数量改变时调用,但它会循环遍历6个物品栏,如果这个时候读取,就只能获取最后一个地址
3. 多种方式一次调用:即关键代码所在的CALL,被用来访问或写入多类数据,而且触发多次。假如生命值/魔法值/力量/敏捷度/智力等的增减代码都共用一个函数,则相关量改变时,它最终会调用多次
4. 多种方式多次调用:即关键代码所在的CALL,被用来访问或写入多类数据,而且触发多次。一般出现在 持续不断 的访问的关键代码中
暂停一下,这里提示一下,CE工具提供的反汇编功能很强大,尤其自动汇编和访问改写为最,但这里访问改写框中代码的计数只表示改数据的访问修改的次数,并不代表它的关键代码只执行那么多次。这里正好与上面的几个类型印证。而我们这次的核心就是利用好访问改写功能,辅助以自动汇编。嗯。。。你想变得更加强大吗?我觉得可以试试深入理解访问改写或自动汇编(包括代码注入\AOB注入\API Hook\代码重定位\Lua函数调用)的原理,看CE源码。。。
如上,我们可以轻易得到一个结论:人造指针-基础 只应用到第一种情况或第二种情况。这对于至少超过一半的游戏是没用的,比如魔兽争霸3冰封王座中的生命值/魔法值,如果只应用 人造指针-基础 的知识,由于其关键代码属于 多次方式多次调用 的类型,它的第一个困难就是无法下断跟踪,因为多种方式,所以正好是你需要的情况的概率为1/N。又因为多次调用,这个概率就变为1/N^2。如果这个时候它持续不断,这个概率就变为1/OO(无穷小,不考虑叠加性,可以认为为0)。因此,这个时候我们需要搬出 人造指针-提升 的基础概念及方法
人造指针-提升:找到关键代码,设置条件断点,获取寄存器状态,分析关键寄存器含义,利用多重特征而获得唯一的情况
适用范围:上述四种情况(欢迎后来者继续补充,对人造指针进行拓展,使其无限接近普通指针所具有的特性:加载即所得)
使用方法:附近分析法
暂停一下,给出附近分析法的一个简单说明:即对访问改写的关键代码,利用其寄存器状态、栈状态、特殊值等,通过自动汇编获得数据的动态基址,从而获得最终数据。具体看实战分析来体会
人造指针的实质还是CE的访问写入功能与自动汇编功能的结合。人造指针-基础只是简单的结合两者,只能用于访问次数少或非持续数据。而人造指针-提升则把寄存器状态和栈的状态甚至其它特殊值加入进来,使得应用范围扩展到任意可被访问或写入的数据(比如当关键代码被持续访问时,可以人造指针-提升来获取即时的指针。也就是说,人造指针-提升的技术力还只能够使持续访问的代码来获得普通指针的特性,但对于非持续的暂时还需要条件触发它。但这里我有个建议:我们可以把非持续的作为被持续加载的一个子程序,从而获得普通指针的特性)
实战分析
逻辑分析
首先,我们来分析快速建造
数据捕捉:对于建筑而言,它的耗费金币\耗费木材\耗费时间等数据应该是在一起或相隔不远的。这里我们假设它的金币和木材是靠近的,对它进行字节数组搜索。可以得到目标数据
动作分析:很简单,就是一般的访问触发
接着,我们来分析快速研发
数据捕捉:对于科技而言,这里是不能像上面直接捕捉到实际数据的。因此我们需要间接联想:这个数据可以被谁访问或修改了谁?这里提示一下:CE数据分析的本质,还是与具体游戏动作有关。因此不论是直接的修改还是间接的访问都需要对应的动作联系 这里,很容易联想到,研发某个科技,我们的金币木材会发生改变,这个时候目标数据必然需要被访问。因此耗费金币\耗费木材可以通过跟踪此关键代码向上跟踪到
动作分析:同快速建造
上述对比,可知当直接搜索数据(一般是4字节,然后浮点,最后字节数组、字符串)不到时,可以联想某动作与数据的关系,是访问还是修改。因为游戏动作不是孤立的,所以数据也不是孤立的。直接不行,就间接或逆向思考或换个角度等
CE分析
分析一:快速建造
首先,我们如图搜索,得到目标数据
接着,我们如图查找什么访问/改写,得到关键代码,并可分析(下断,发现它只在建造时调用)得到它属于 一种方式一次调用 的类型
接着,分析寄存器状态,获取关键寄存器含义
接着,分析栈状态,获取栈中相关值
接着,利用寄存器状态\栈状态等多重特征,编写自动汇编脚本
[Asm] 纯文本查看 复制代码[ENABLE]//code from here to '[DISABLE]' will be used to enable the cheatalloc(newmem,2048)label(returnhere)label(code)label(exit)alloc(BLE,4)registersymbol(BLE)alloc(KSSC,4)registersymbol(KSSC)newmem:cmp [Game.dll+ACBDD8],0 //保证在创建界面,脚本可运行je codecmp ecx,Game.dll+ACB2B4jne codemov [BLE],ebxmov ebx,[Game.dll+ACBDD8]mov ebx,[ebx+3F4]cmp ebx,0 //保证在载入地图界面,脚本可运行je recovermov ebx,[ebx+238]cmp ebx,0je recovermov ebx,[ebx+1F4]cmp edi,ebx //一重特征jne recovercmp [esp],edx //二重特征jne recovercmp [esp+14],edi //三重特征jne recoveralter:mov [KSSC],eax //获取建造时间的动态基址mov eax,1 //使建造时间为1jmp end0recover:mov ebx,[BLE]code:mov eax,[eax+18]end0:pop ecxret exit:jmp returnhere"Game.dll"+29C2DE:jmp newmemreturnhere: [DISABLE]//code from here till the end of the code will be used to disable the cheatdealloc(newmem)dealloc(BLE,4)unregistersymbol(BLE)dealloc(KSSC)unregistersymbol(KSSC)"Game.dll"+29C2DE:mov eax,[eax+18]pop ecxret //Alt: db 8B 40 18 59 C3
最后,效果如下
分析二:快速研发
首先,我们如图搜索,得不到目标数据(搜到的值修改无效果)
接着,我们间接联想,查找金币\木材增减的关键代码
接着,向上跟踪增减量
接着,跟进金币\木材减少的CALL
接着,跟进金币获得CALL
接着,可以发现,在这个CALL执行后,EAX便等于我们所要寻找的值,但可以很容易知道,这个CALL是一个系统函数,查一下atoi函数,可以知道它起把字符串转化为整数的作用,第一个参数为常字符指针
接着,分析CALL前面的Push,跳到EDX处,可以看到字符串形式的耗费金币值。因此我们现在可以知道耗费金币\耗费木材\耗费时间是以字符串形式存储的,所以我们第一步是搜不到的
接着,得到目标数据后,通过查找什么访问,可以获得关键代码。这里可以像分析一一样继续分析。这里下一个条件断点
接着,分析寄存器状态\栈状态,获取栈中相关值
接着,利用寄存器状态\栈状态等多重特征,编写自动汇编脚本
[Asm] 纯文本查看 复制代码[ENABLE]//code from here to '[DISABLE]' will be used to enable the cheatalloc(newmem,2048)label(returnhere)label(code)label(exit)alloc(BLA,4)alloc(BLBA,4)registersymbol(BLBA)alloc(KSYF,4)registersymbol(KSYF)newmem: //this is allocated memory, you have read,write,execute access//place your code herecmp [Game.dll+ACBDD8],0je codemov [BLA],ecxmov ecx,[Game.dll+ACBDD8]mov ecx,[ecx+3F4]cmp ecx,0je recmp ebp,0je remov ecx,[ecx+238]cmp [esp+3C],ecx //一重特征jne realt:mov ecx,[esp-4]mov [KSYF],ecx //获取研发时间的动态基址mov eax,1 //使研发时间为1re:mov ecx,[BLA]code:mov [esi+30],eaxmov eax,ediexit:jmp returnhere"Game.dll"+4CBE9E:jmp newmemreturnhere: [DISABLE]//code from here till the end of the code will be used to disable the cheatdealloc(newmem)dealloc(BLA)dealloc(BLBA)unregistersymbol(BLBA)dealloc(KSYF)unregistersymbol(KSYF)"Game.dll"+4CBE9E:mov [esi+30],eaxmov eax,edi//Alt: db 89 46 30 8B C7
最后,效果如下
最后总结
知识总结
1. 对访问写入功能的情况分为4类:1/1 1/N N/1 N/N
2. 追加种类2类:持续 非持续
上述两类可以自由组合,比如1/1持续、N/N持续等
3. 使用方法:附近分析法
附近分析法的实质:利用访问写入功能获取 关键代码访问目标数据时的状态,来获得唯一的情况。这里需要区分的是:CE的访问写入记录的是关键代码执行后的状态,而下断点记录的是关键代码执行前的状态
4. 下简单条件断点的方法:先找什么访问写入获得动态基址,然后在关键代码处先下断再设置条件。比如EAX==0x0
<font face="Trebuchet MS"><font size="3"><strong><font size="4"><font size="3"><font color="Red"><font color="Black"> 5. 加多重特征是为了获得唯一情况,一般来说加特征数情况:1/1 |