Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
CE入门笔记_八种最好的记笔记方法,希望能够帮助你!!!。
CE是一款游戏作弊引擎,全称为Cheat Engine,简称为CE。是逆向工程师常用的几大神器之一,也是游戏汉化、激活成功教程以及外挂编写中常用的工具。
以上内容摘抄自CE教程:基础篇
从CE官网下载地址可以下载CE安装包以及汉化语言包。目前最新版本为7.3。
将汉化包解压到安装路径的languages
目录中,打开CE,从配置窗口中选择Languages
目录,从中选择ch_cn
,重启,完成汉化。可能下载的汉化包对应6.7的缘故,整体汉化之后显示内容为6.7的汉化效果。
CE自身提供一个入门教学软件,在帮助中打开Cheat Engine教程即可,包括32位与64位。我们就从32位入手开始CE的基本入门。
第一步是十分简单的,它教给你如何使用CE附加到一个进程上。
打开进程列表,然后选择对应的进程就达到目的了。
在开始第二步之前,此时让我们简单对CE主窗口及主要的搜索功能进行一下简单介绍,图来自CE教程:基础篇
在主窗口中,除去上层的标题栏、菜单栏以及工具栏之后,左面的窗口是一个搜索结果列表。它的右侧是各种搜索的设置,根据CE本身的介绍我们可以看到,它的基础功能就是通过对内存中各种各样的值进行搜索来逐步达到对游戏修改的目的(自己理解)。它能够记录每次搜索结果的变化,并于当前游戏中特定位置的结果进行对应,从而达到找到与该变量相关代码的目的。
基本的设置有两个,一个是扫描类型,一个是数值类型。
扫描类型包含了5种:
数值类型包含的更多:
通过这些方式,我们可以指定对应的扫描方法,并根据目标游戏中变量可能的类型,来达到对特定内存的搜索目的。
这一步表示要将目前的健康值修改为1000。当前值为100。
根据说明,CE可以记录每次搜索的地址的内容,并根据当前程序的表现来查找目标地址。首先,使用4字节类型通过精确数值方式搜索100。
点击打我,使当前健康值变成97,然后使用97再进行搜索。
双击该地址,将其添加到下方的cheat table中。
此时,我们双击表中的97,并将其修改为1000。
此时通向第三关的按钮打开了。
这一步是将健康值修改为5000,但是不知道初始值与之后的具体值,仅知道每次减少的值以及初始值的范围为0-500
根据教程,它提供了一种利用未知的初始值结合减少的数值来进行查找的方式。
首先使用未知的初始值进行搜索,但是此时是没有显示结果的,只有所有结果的记录。
点击“打我”,发现数值减少了8,扫描类型使用"数值减少了…"进行搜索,如果有多个结果,利用这个方式多进行几次。
因为我们知道初始值在0-500之内,所有只要发现满足这一条件的唯一地址,就是我们要找的地址。并将其添加到cheat table中,并修改健康值,完成。
由于我们知道值的范围,初始的搜索可以使用介于0-500之间将内容限制住
这一步是需要将两个值修改为5000以上,不过一个是单浮点一个是双浮点
其实这一步与第一步基本一致,不过就是搜索的数值类型变为单浮点与双浮点
这一步介绍的是代码查找功能,主要是通过修改代码,从而使某个非固定地址数不发生变化
开始一样,通过100和之后的变化来查找到目标地址。
我们需要查找哪段代码对该地址中的内容进行了修改,所有右击目标地址,选择“找出是什么改写了这个地址”
其实这块儿翻译感觉有些不对味,我们将其修改成原版再看看
原文是“Find out what writes to this address”, 可以理解为查找是哪段代码在对该地址中的内容进行了修改。。。
此时弹出一个新的窗口,窗口名称为“The following opcodes write to ‘some address’",其中"some address"表示的就是目标地址
此时再次点击一下修改值按钮,上方的列表中就会显示出对该地址进行修改的opcode。
按照要求,只要将此处代码修改为无效代码就达到目的,最简单就是修改为nop
。右击该行,弹框中选择“使用空指令进行替换(Replace with code that does nothing(NOP))”。即达成目的。
这一步就是理解一下程序中指针的含义并利用CE中指针这样的一个机制来对某些可变的地址内容进行修改
指针是C语言中的精髓,也是整个底层中的难点。我认为就是一个变量保存了另外一个变量的地址,这个指针指向某个地方表示这个变量中的内容是目标量所在的地址。按照题目说明,应该是我们初始找到的这个地址不是固定的,而是每次都会变化的,猜测可能是每次malloc
导致其发生变化。但是既然是一个变化的地址,那么就会有一个变量保存着这个地址的内容。通过向上查找我们可以找到保存这个地址的变量,即指向目标地址的指针。按照这个逻辑一层一层的向上回溯,找到最终的一个基地址,我理解就是在data段中的一个全局地址或者说静态地址,这个地址对于程序基地址的偏移是固定的。然后反过来一层层的确定后面的可变地址偏移,最终找到其地址。
// 一个示例,可能不是很恰当 struct struct_1 *g_start; // global void some_func() {
g_start = malloc(sizeof(struct_1)); g_start->p_struct_2 = malloc(sizeof(struct_2)); g_start->p_struct_2->key = key; ... }
我们通过CE找到key
这个变量所在的地址,然后由于p_struct_2
地址每次是变化的,我们通过key
所在的地址推出分配出的p_struct_2
的基地址,然后通过这个基地址就能反推出g_start
中保存这个地址的指针变量的地址,从而推出g_start
所在的地址,从而找到该地址与程序基地址的偏移。这样以来我们可以通过指针偏移的方式,从g_start
地址开始,逐步推出key所在的地址,从而达到对该值控制的目的。
其实只要了解了具体的原理,具体操作只是让我们对CE这个工具更深入理解的一个步骤罢了。
按照之前的步骤,找到地址以及修改这个地址的代码。与上一步不同的是双击或者点击“More information”来显示更多信息。
此时我们看到位置的代码为mov [edx], eax
,表示此时地址保存在edx中,所以我们拿edx的内容到进程中进行修改。此时CE提供了一个比较快捷的方法:在对话框中它根据上下文猜测你想要的拿到某个地址,通常在指针使用时可以相信这个结果。
此时发现最左边的地址字体变成了绿色,这就表示这个是地址是基地址,也就是说到了进程的data段,idata段这些地方。将该地址添加到cheat table中或者右击复制该地址,打开手动添加地址按钮。在弹出的窗口中选中“pointer”选项,在地址栏中粘贴目标地址,由于offset为0, 所以offset中保持为零。此时CE就已经将该地址处保存的地址显示到最上面的地址栏中,而这个地址保存的数据显示到地址栏后面,与当前值一致。
完成添加后我们可以看到添加的内容,将后面的值修改为5000,点击最前面使之变成“×”。点击“change pointer”完成这一步。
介绍了代码注入,使每次点击时减1变成加2
老方法,查找到修改的地址以及修改值的代码。此次打开的窗口变成“Show disassembler”。
这个窗口分为上下两部分,上面是汇编代码,下面则是内存视图。
选择“auto assemble”。然后在这个窗口中选择“Template”菜单,并点击“Code injection”。
在该窗口中,将sub dword ptr [ebx+000004A4],01
修改为add dword ptr [ebx+000004A4],02
,点击“Execute”即完成。
上面第一张图显示的是注入的代码,第二张图显示的是注入后原地址的代码。通过这里我猜测CE在完成注入前保存了当前修改的地址信息以及下一个指令的地址信息,然后从堆中分配一块可读可写可执行的区域,将注入代码以及jmp nextOpAddr
的opcode写到该处。将原地址改为jmp injectOpAddr
,后面的地方设为NOP
。可能的代码逻辑如下:
LPVOID curOpAddr; LPVOID nextOpAddr; LPVOID lpBuffer; // inject code store(curOpAddr, nextOpAddr); // store current and next op address LPVOID injectOpAddr = VirtualAlloc(hModule, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hModule, injectOpAddress, lpBuffer, nSize, &lpNumberOfBytesWritten); change_cur_cotent(curOpAddr, injectOpAddr); // change currrent address's opcode
这种手法好像称为“inline hook”。
这一部分讲的是多重指针
其实这一部分的原理在第六部分的时候讲过了,不过由于指针本身就比较绕,在实际过程中需要仔细考虑,不要把自己绕进去了。
初始的查找就不说了。
开始查找第一层
此时发现opcode为mov [esi+18], eax
,具体指针内容放到esi中,偏移量为0x18。将发现的地址放回重新搜索,发现多个地址。这一步我没有好的方法,只能一个个的试,但是此时需要注意的是,在查找时不再选择修改内容,而是访问内容,因为每次未重启前这个地址是固定的。
在多个中我们找到和这个按钮操作有关的地址,然后在两个中选择mov
操作的,因为cmp
操作与整个指针的地址传输没有任何关系。
不过我们发现,这次地址给出的建议与第一次查找时给出的建议一致。这个是因为CE默认采用硬件断点,所以断点只能停在指令执行之后,而这条指令正好是把 esi 原来指向的地址中的值再赋值给 esi,所以执行之后 esi 的值已经是被覆盖掉的值了,而我们想知道的恰恰是执行这条指令之前的 esi 值,那么怎么办呢。
第一,打开内存视图,在该指令的前一个指令处下断点。
这样得到了ESI的值
第二,我们考虑一下,我们之前进行第一次查找时查找的就是这个指针保存的地址,查找到的那个地址不就是这个指针保存的地址,此次偏移为0
两者都是0x14d700。
仍然不是基址,此次为mov esi, [esi+14]
,偏移为0x14
还不是基址,此次为mov esi, [esi+0c]
,偏移为0xc
终于,找到了基址,利用第6部分的方法,手动添加指针
其实前8关基本上把CE的基础内容讲完了,这一关感觉上就是一个综合能力训练,下次再写吧。
说实话我没怎么理解整个课程中关于指针这儿的一些要求,貌似6和8两边都是通过一个地址向上不断查找到初始在数据段中的一个全局或者静态变量,这个变量是一个结构或者指针。好似它们确定会有这样一个全局性的位置放着它们。也许这个和我想的ASLR导致的地址随机化不是一回事儿,这点自己有些没怎么搞明白,也许是malloc。
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章