前言
终于来到这个系列最后一期,之前的评论里很多兄弟们也提出了问题,也有些兄弟提出了自己的建议。非常感谢大家的支持,也希望大家能够保持这种钻研精神。
本期我将为大家介绍如何使用易语言调用AA引擎来实现自己的修改器的方法。
其实大家也不用太纠结语言,只要能调用dll的语言,都一样,因为毕竟是通过引擎嘛。
另外有些兄弟可能担心,教程会不会助长外挂开发。其实任何东西都是双面的,当然,学习如何去修改汇编,在某种程度上可以开发一些坏的东西。但是你能了解得更多,你就能研究更多对抗他的东西,医学院研究病毒不也是这个意思。你知道他去破解的方式,是不是可以更好的检测和防护呢,研究和学习就是为了更好的防护。
欢迎文明转载,请注明出处 丸子de爸爸
本文所有技术资料仅供研究,不鼓励任何盗版商用行为
请大家支持正版,支持正版!支持正版!!!
上集传送门
工具
CheatEngine6.7
易语言5.11
AA引擎1.21(这其实就是个dll,也写进来吧)
本次基础概念
内存,一切皆内存,我们操作的全部都是内存。
所有地址相关的概念,都可以理解为坐标,用来给我们做标记的而已。
如果实在搞不明白,你想想指南针为啥指向北边,为啥叫南北,只是定义,只是公认
PS:上面这一段是重复了,但是我觉得还是有必要多重复一下,看多了,大家就印象深刻一点。
什么是AA引擎?
AA引擎由CE 5.61的Delphi源码中, 摘除并移植AA脚本直译器,外加OD的汇编编译器(disasm)源码作为心脏
由axdx兄弟进行移植整合手术, 所有技术源自CE与OD。
AA引擎运行环境(引擎自带描述)
- 需要 VS2008SP1运行库 (仅4MB)
- 部分功能需要Vista或XP SP1以上运行环境
- 使用UPX 3.08压缩加壳, 无毒。如有任何误报, 可自行脱壳, 方法为 upx.exe -d aa_engine.dll
脱壳后, 原大小約为 160k
DLL引用是啥意思?
DLL是动态链接库,你可以简单理解为原本的程序是一本指导书,上面有很多种可以直接引用的方法,引用方法就是你告诉我,多少页,我自己就可以去找到,计算机也一样。
dll引用就相当于,我自己新买了一本指导书,我得告诉计算机,啊,我这里有新买的书,下次你找东西的时候,这里也可以找,这里的多少页我也是需要你帮我查的。
具体特别专业的解释,可以自己去查询查询,我只是先帮助大家理解。
实现步骤
易语言引用AA引擎
打开易语言,先新建一个“windows空白程序”,选择“Windows窗口程序”
在新打开的程序中,按照下图选择到dll命令界面,添加新DLL命令。
这一步的作用就是建立dll引用。
AA引擎函数说明图
下图就是AA引擎自带的函数说明
新建DLL命令详解
分析比较长,所以我把图先帖在前面
dll命令名
你在易语言中调用时使用的名称,可以自己随便取。
返回值类型
函数返回值的类型。按照AA脚本提供的来写。
库文件名
你需要引用的dll的名称,包含路径。我这里是和当前的文件在同一目录,所以可以直接写名称。
例:E:\aa_engine.dll,你放哪就写哪,如果是和exe同一目录,直接写名字就可以。
在库中对应命令名
dll中函数的名称。也需要按照AA脚本提供的来写。
参数名
dll中函数的参数,名称是可以随便写的,但是类型需要符合。
参照着之前AA引擎的函数说明图,补全三个方法。
觉得不会写也没事,重要是弄懂思路,我最后会附上e文件和单独的dll文本文件。
其他必要dll方法
可以看到,不管是自动汇编函数,还是获取地址的函数。都是需要用到“进程ID”。
那我们怎么获取“进程ID”呢?百度“易语言助手”,云词库中,可以查询你需要的用到的dll方法。
我这里就列出来一些需要用到的:
- WriteProcessMemory:写内存
- ReadProcessMemory:读内存
- GetWindowThreadProcessId:获取进程ID
- OpenProcess:获取进程句柄
- CloseHandle:回收进程句柄
心跳线程创建
所谓的心跳线程,就是用来监测游戏是否已经启动的一个循环。
同时也正是因为很多功能需要进程ID,我们也可以在这个心跳里,获取进程ID。
在右边的组件框中,选择“标签”,然后在左侧的红框处点击一下。给程序添加一个标签控件。
PS:如果运行说出现死循环,工具-->系统配置-->编译-->把编译时是否检查死循环代码的勾去掉。
选择控件的可以设置对他进行属性设置。
名称对应是在易语言中使用的引用,可以理解为编程时候的引用。这里改为"Attach标签"。
标题对应的是显示,就是你看到的内容。这里可以改为“目前未连接上游戏”。
接下来我们要做的,就是理一下我们心跳线程的逻辑了。
整体的流程其实也不复杂,就是一个持续循环的过程。
选中启动窗口,就是在中间刚才添加标签的那个窗口空白处点一下,看左上角变成启动窗口。
然后左下角选择,“创建完毕”,进入编程界面。(直接双击窗口也可以)
其实易语言很多就是这样,通过和控件的事件交互,来进行编程。
这里选择的意思是,当窗口被创建完成的时候,进入我们选择创建完毕的逻辑,执行我们的逻辑。
PS:真心想学编程的话,可以去了解下“回调”。不多讲了。
自动跳转到编码界面,选中第一栏的备注,按回车,会出现一栏变量名。
按下图填写,这一步是建立一个全局变量。
进程ID用来待会存放植物大战僵尸的进程ID;心跳线程句柄用来待会关闭线程使用。(属于优化,你不关也没事)
PS:啥叫全局变量,这又涉及到作用域的概念。简单理解,就是知名度。B站出名呀,还是全球出名呀。就决定了别人在什么地方认不认识你,全局变量,等于就是全世界,到处都知道你是干嘛的。同理,计算机在任何位置,都知道这个进程ID就是用来存放一个整数的。有兴趣的去了解下变量作用域,也是编程必学。
由于我们需要使用线程,所以需要添加一下支持库。选择工具,支持库配置。
在弹出的框里,输入“多线程”,即可在下面列表中找到支持库。勾选之后选择确认。
为啥使用线程呢,因为我们需要做一个死循环,来循环判断当前是否有植物大战僵尸的游戏在运行。
程序呢,本身有一个主线程在运行。我们可以理解为,一个主干道,你的车不可能一直占用,那别的车就不能走了。
于是,你只能在旁边,开一条小路,我在旁边停着,要走的时候,我再回到主干道,直接走。
有兴趣的也可以去了解下,线程。
右键编程处,选择新子程序,创建一个新的子程序。并改名为心跳线程。(名字随便你取)
此时我们先不用给心跳线程里面加入代码,先把他的启动和关闭完成。
在启动窗口中,输入如图代码。
代码分析,首先执行启动线程方法,调用心跳线程,如果成功,将句柄赋值给全局变量;如果没有成功,则直接将标签标题改为“连接异常”。
按照前面的方法,在“启动窗口”的属性中,选择“将被销毁”事件,并在代码中完成销毁窗口时,关闭线程的动作。
如此,我们便完成了,线程的启动和回收。
估计有兄弟要晕了,不是,我们什么代码都还没写啊。 是没写,但是我希望传达的思想就是编程逻辑中的模块化。
不用着急去写逻辑的内部实现,先实现整体的框架。我们刚才做了啥,就是窗口运行,在线程中启动这个方法;窗口关闭,就停止这个方法。具体这个方法内部是怎么实现的,我不用那么清楚。简单理解就是,我只知道刮胡刀是能刮胡子的,怎么刮胡子,我用不用理解马达为啥这么能转。当我们确定了线程启动这一块逻辑是正确的时候,我们再去实现方法,就完事了。
这种方式的好处是可以让思维更加线性,思维不用来回跳转。而且在某种程度上也更方便结队编程,你想你先写完了框架,方法如果没实现好,这时候有别人帮你的话,他不需要重新了解逻辑,直接帮助你实现方法就行了。但是如果你框架没写好,只是实现完了方法,人家想帮你都不好帮。这也是为啥好的架构师贵呀...
接下来就开始实现方法,具体方法的实现思路,就在上面的流程图里。
按下图写好,蓝色的变量是局部变量,快捷键Ctrl+L添加。或者在“插入”菜单栏中选择局部变量。
运行程序之后,打开游戏,是不是看左下角,瞬间就拿到了进程ID,同时我们的程序中的标签页显示了“已连接”。
PS:你着时候关掉游戏,标签又会变成未连接的(不过会慢一点,毕竟成功后周期变成5秒了),不过我代码好像忘记清空进程ID了。
AA引擎的使用
要使用AA引擎,我们选择选择框作为触发控件,因为AA引擎也是一个开,一个关。
按之前介绍的方法,添加一个选择框,修改名称和标题如图。(你也可以按自己喜好)
接下来给他添加事件。双击选择框,或者左下角选择“被单击”,进入编码界面。
还是按照上面的思路,我们可以给他封装成三个方法。(封装你就简单理解成格式化吧,就是把代码整理)
在选择框被单击的时候,判断当前是选中还是未选中,分别将是执行还是关闭传入,0和1是dll本身需要的。
第一个参数传的是你的AA脚本的路径。(脚本自己写哈,没有提供的,哈~~)
然后事件就完成了,是不是很好理解也不混乱,因为选择框就只要做选择的事,其他事情不归他管了。
然后我们开始完成执行脚本内容的方法。
也比较简单,就是将AA脚本内存读到变量中,然后调用我们引用的DLL中的自动汇编,传递对应的参数,搞定。
这里之所以要进行一个替换脚本动态地址是因为,AA脚本中有些模块地址偏移操作
jmp ?PlantsVsZombies.exe+294AF?这种,但是在我的电脑上,如果你直接这么读入脚本,是不生效的。
所以我换了种方式,我查找到AA脚本中的模块偏移地址内存中的动态地址,然后替换回脚本,就OK了。
PS:我当时怀疑就是和这两个问号有关,但是也没去深究为啥,直接替换了,有兴趣的兄弟可以试试看,有时候不替换也是OK的。
替换动态地址的逻辑也很简单,就是通过“正则表达式”,对内容进行查找,然后用AA引擎自带的获取地址函数,获取模块偏移地址对应的动态地址,然后替换回去。
上面正则创建的“替换正则”是一个常量,常量意思就是不会改变的固定值。这里用常量是因为,一是代码更加规范便于阅读,二是正则中有一些引号啥的,再用引号包裹时会出现各种转义字符的问题,就理解成不是太兼容吧,要兼容比较麻烦,干脆直接引用常量。
至于正则表达式为啥要这么写,我只能说,感兴趣的去查查吧,这个我是真的不熟练,每次要写正则都要查好久,谁说汇编不好懂,正则表达式才是反人类的存在好伐!!!
结尾
完成了上面所有的步骤之后,运行游戏。再勾选上你选择的脚本,马上就可以使用那些功能了,再也不用开CE了,美滋滋。
更新了这么久,终于把这个系列做完了。中间肯定有一些说得不是很完美的地方,希望大家多多包涵。
下个系列暂时是考虑做个CS1.6修改器的相关讲解,战旗游戏玩了一段时间了,也玩玩FPS游戏吧。
大家可以多动手自己试试,有啥不懂或者遇到的问题,尽管提出来大家一起学习进步。当然,请先表达清楚哈,要不然我也不知道该怎么解决了。再次感谢大家的关注和观看,谢谢。
PS:附上自己封装好的易语言调用框架和AA引擎。但是AA脚本你们得自己写,哈哈。