Cheat Engine逆向工程入门:从内存扫描到代码注入实战指南

📅 2026/7/29 12:57:25
Cheat Engine逆向工程入门:从内存扫描到代码注入实战指南
1. 项目概述为什么选择Cheat Engine作为逆向工程的第一站如果你对游戏修改、软件分析或者单纯想窥探程序运行时的内部状态感到好奇那么Cheat Engine简称CE几乎是一个绕不开的名字。它远不止是一个“游戏修改器”而是一个功能强大、界面直观的Windows平台动态分析工具。对于逆向工程新手来说它提供了一个从“黑盒”外部观察逐步深入到“白盒”内部干预的完美学习路径。相比于直接上手IDA Pro或OllyDbg这类更底层的调试器CE的学习曲线要平缓得多。你不需要一开始就理解复杂的汇编指令和调用约定而是可以从最直观的“数值变化”入手通过内存扫描找到目标数据再顺藤摸瓜定位到操作这些数据的代码最终实现代码注入和逻辑修改。这个过程恰恰是逆向工程核心思维——“观察、假设、验证、修改”的生动体现。本指南旨在为你拆解这条完整链路从最基础的扫描一个血条地址到理解并注入一段自定义汇编代码让你不仅能“用”CE更能“懂”其背后的原理为后续更深入的逆向工程学习打下坚实基础。2. 核心思路拆解逆向工程的“侦察兵”与“突击队”我们可以把使用CE进行逆向的过程类比为一场军事行动。你的目标是攻陷一个程序目标软件的某个功能堡垒比如无敌、无限弹药。盲目强攻直接修改硬盘上的程序文件几乎不可能成功因为程序在运行时其逻辑和数据都在内存这个“战场”上动态展开。2.1 第一阶段侦察与定位内存扫描这是“侦察兵”的工作。程序的所有动态数据如角色的生命值、金钱数量、物品数量甚至一些状态标志都存储在内存的特定地址中。我们的首要任务就是找到这些地址。CE的核心功能——内存扫描就是最强大的侦察手段。其基本原理是你知道目标数据当前的值比如生命值100就告诉CE扫描这个值然后你让目标数据发生变化比如受到伤害变成80再让CE在第一次扫描的结果中搜索变化后的值。通过多次“变化-筛选”地址范围会急剧缩小最终锁定唯一或少数几个疑似地址。这个过程的关键在于理解数据在内存中的存储格式如4字节整数、单精度浮点数和变化规律。2.2 第二阶段监视与溯源找出是什么访问/改写了这个地址找到地址只是知道了“物资仓库”的位置。接下来我们需要知道是“谁”哪段程序代码在“什么时候”访问或修改了这个仓库里的物资。CE的“找出是什么访问了这个地址”和“找出是什么改写了这个地址”功能就是安装在这个仓库门口的“监控摄像头”和“震动传感器”。当你激活这些功能后CE会使目标地址变成被监视状态。一旦有任何指令读取或写入该地址程序就会暂停并高亮显示正在执行的那条汇编指令。这相当于直接把“运输队”代码抓了个现行。通过反复执行程序功能如吃药回血、攻击扣血我们就能收集到所有与该数据相关的关键代码位置。2.3 第三阶段分析与干预代码注入这是“突击队”的渗透行动。当我们定位到修改生命值的关键指令比如一条sub [eax04], edx指令表示从[eax04]这个地址存储的值里减去edx寄存器中的值后单纯的“锁定”该地址的值只是一种临时且粗糙的干扰。更高级的做法是“代码注入”。我们可以在目标程序的内存空间中开辟一小块“安全区”写入我们自定义的汇编指令比如把减法指令改为nop空操作或者直接改为mov [eax04], 9999然后修改原程序的代码让它跳转jmp到我们这块安全区执行我们的指令执行完毕后再跳转回去。这样我们就实现了对程序逻辑的精准、持久在本次运行中的修改。这是从“观察者”转变为“控制者”的关键一步。3. 环境准备与工具配置工欲善其事必先利其器。在开始实战前需要做好以下准备。3.1 获取与安装Cheat EngineCheat Engine是完全免费的从其官方网站即可下载最新安装包。安装过程需要注意一点官方安装包可能会捆绑一些额外的软件如合作方的游戏平台在安装时务必仔细阅读每一步取消勾选你不需要的组件。安装完成后首次运行可能会被Windows Defender或其他杀毒软件报毒这是因为CE的内存访问和注入行为与某些恶意软件特征相似属于“灰色工具”的常见情况。你需要将CE的主程序cheatengine-x86_64.exe或cheatengine-i386.exe添加到杀毒软件的信任区白名单中。这是正常使用的前提。3.2 目标程序选择经典“训练场”强烈不建议初学者一开始就对大型网络游戏或带有强反作弊保护如 BattlEye, EasyAntiCheat, VAC的程序进行尝试这极易导致账号被封禁且技术难度极高。理想的“训练场”是经典的单机游戏或小型演示程序。推荐选择1附带的Tutorial程序CE安装后在它的安装目录下有一个Tutorial.exe或Tutorial-x86_64.exe。这是CE作者专门设计的、分步骤的交互式教程完美契合学习路径它会引导你完成从基础扫描到代码注入的全过程是无可替代的入门教材。推荐选择2经典单机游戏例如《植物大战僵尸》、《星际争霸1》、《魔兽争霸3》的离线模式或者一些小型RPG Maker制作的游戏。这些游戏逻辑相对简单数据清晰且没有反作弊干扰。自制测试程序如果你有编程基础可以自己用C/C/C#写一个简单的控制台程序里面声明几个变量如int health 100;然后循环打印并允许修改。用它作为目标你可以100%确定数据的结构和行为非常适合验证你的操作和理解。3.3 核心界面与概念速览打开CE主界面主要分为以下几个区域进程列表左上角的电脑图标点击后可以列出当前运行的所有进程选择你要分析的目标程序。地址列表主窗口区域成功找到的地址会显示在这里包含地址、当前数值、类型、描述等信息。内存扫描窗口点击“首次扫描”按钮弹出用于设置扫描参数。调试器窗口在“调试”菜单下或通过工具栏按钮打开用于单步执行、查看寄存器、内存和汇编代码是进行代码分析的核心面板。内存查看窗口可以查看指定地址附近的内存原始数据十六进制和对应的汇编指令。注意在开始任何操作前请务必关闭目标程序的自动存档功能或者先备份你的存档文件。因为错误的修改可能导致游戏状态异常甚至崩溃。4. 实战第一步精准内存扫描与锁定让我们从一个最简单的目标开始修改一个单机游戏中角色的生命值。4.1 启动与附加进程首先运行你的目标程序比如Tutorial.exe。然后打开CE点击左上角的电脑图标在弹出的进程列表中找到并选中Tutorial.exe点击“打开”。此时CE就成功“附加”到了目标进程上获得了读取和修改其内存的权限。4.2 执行首次扫描假设教程程序第一步要求你找到一个不断变化的数值。你看到屏幕上显示一个数值比如“100”。在CE主界面的“数值”输入框输入“100”。在“扫描类型”中选择“精确数值”。这表示我们要搜索一个恰好等于100的值。在“数值类型”中根据你的判断选择。对于大多数游戏的整数生命值、金钱选择“4字节”。如果不太确定可以先尝试“4字节”或“所有类型”。点击“首次扫描”。扫描结束后左侧的地址列表可能会显示成千上万个结果。这很正常因为内存中值为100的4字节数据太多了。4.3 利用变化进行筛选现在回到目标程序想办法让这个数值发生变化。在教程中你可能需要点击一个按钮。假设数值变成了90。在CE的“数值”输入框将数值改为新的“90”。扫描类型保持“精确数值”。点击“再次扫描”。这次CE会在上一次的扫描结果那些值为100的地址中搜索哪些地址的值现在变成了90。结果列表会大幅减少。重复这个过程让数值再次变化比如变成80然后在CE中输入新值点击“再次扫描”。通常经过2-4次变化筛选结果会减少到个位数甚至一个。4.4 识别与锁定目标地址当结果列表只剩下少数几个地址时你需要进行最终确认。观察地址列表中的“数值”列看哪个地址的值会随着程序显示的值实时同步变化。找到它后双击这个地址它会被添加到下方的地址列表中。锁定功能在地址列表中勾选该地址左侧的“锁定”复选框一个小方框然后在“数值”列双击输入一个你想要的数值比如9999。你会发现无论程序内部如何试图改变这个值它都会被立刻恢复为你锁定的值。这就是最基础的“无敌”效果。手动修改不勾选锁定只是双击“数值”列修改这是一次性的修改。实操心得如果扫描后结果减少得很慢或者始终找不到可以考虑以下情况1)数值类型选错比如生命值可能是“浮点数”Float或“双浮点数”Double尝试切换类型。2)未知初始值扫描如果你不知道初始值是多少只知道它会变化可以使用“未知初始值”扫描类型然后用“增加的数值”、“减少的数值”或“变动的数值”来筛选。3)指针问题找到的地址可能每次启动游戏都会变化这说明它只是一个“临时”地址其背后还有一个“基址偏移”的指针结构。这需要通过“找出是什么改写了这个地址”来进一步分析是进阶内容。5. 进阶侦察指针扫描与多层指针挖掘通过直接扫描找到的地址往往是“动态地址”每次游戏启动都会变化。为了实现“一次查找永久有效”我们需要找到指向这个动态地址的“静态指针”或者至少是多层指针链的基址。5.1 为什么需要指针程序在运行时很多数据是在堆Heap上动态分配的。比如你创建一个游戏角色对象系统会在堆上找一块空闲内存来存放这个对象的所有数据生命值、坐标等。这个对象的地址每次运行都可能不同。但是程序内部会用一个存储在相对固定位置比如在某个模块的.data段的指针来记录这个对象在哪里。这个相对固定的位置其地址在每次程序加载时是固定的相对于程序模块的基址这就是“静态地址”或“基址”。5.2 使用“找出是什么改写了这个地址”这是寻找指针链的起点。首先通过扫描找到你关心的动态地址比如当前生命值地址并将其添加到地址列表。在地址列表中右键点击这个地址选择“找出是什么改写了这个地址”。会弹出一个新的调试器窗口里面是空的。回到游戏执行一次会修改该值的操作比如让角色受到一次伤害。此时CE会自动暂停游戏并在调试器窗口中显示一条汇编指令。这条指令就是正在向你的目标地址写入数据的指令。记录下这条指令的详细信息尤其是它操作数的格式例如mov [esi00005510], eax。这里的[esi00005510]就是目标地址它由esi寄存器的值加上一个固定偏移0x5510计算得来。5.3 分析指令与查找指针现在我们知道目标地址 esi0x5510。那么esi的值从哪里来我们需要找出是什么代码设置了esi的值。在调试器窗口中右键点击那条mov指令选择“找出指令访问的地址”。或者更直接的方法是在CE主界面点击“手动添加地址”在地址栏输入ESICE支持直接输入寄存器名勾选“指针”选项。但这需要你知道ESI当前的值这个值可以在调试器窗口的寄存器面板看到。更系统的方法是使用CE的“指针扫描”功能。在找到动态地址后右键点击它选择“指针扫描”。CE会分析当前内存状态找出所有可能指向该地址的指针链。这会生成一个巨大的指针映射文件.ptr。重启游戏地址会变再次附加进程扫描同一个数值得到新的动态地址。然后通过“指针扫描”功能加载之前生成的.ptr文件并“重新扫描内存”。CE会帮你找出那些在新旧两次运行中依然能正确指向目标地址的指针链。最终你会得到一个类似game.exe002A34FC - 10 - 1C - 550的指针链。这表示从game.exe模块的基址开始加上偏移0x002A34FC取出该地址存储的值作为下一级地址再加上偏移0x10再取出值加0x1C最后加0x550就得到了动态的生命值地址。game.exe002A34FC就是一个静态基址。5.4 使用指针添加地址找到指针链后在CE中“手动添加地址”勾选“指针”然后按照基址-偏移1-偏移2...的顺序填入。这样添加的地址无论游戏重启多少次只要模块基址不变CE都能正确计算出最终的目标地址。注意事项指针扫描非常消耗内存和时间且可能产生数百万个结果。务必先保存你的游戏进度并在一个简单的程序上练习。多层指针的分析是逆向工程中的难点和重点需要耐心和对汇编指令上下文的理解。6. 代码分析与注入从修改到创造锁定数值是“治标”修改代码才是“治本”。代码注入允许我们改变程序的执行逻辑。6.1 定位关键代码区域继续使用“找出是什么改写了这个地址”功能。这次我们不仅要找到一条指令更要观察围绕这条指令的一小段代码函数。在调试器窗口点击“显示反汇编程序”你会看到以目标指令为中心的一段汇编代码。仔细阅读这段代码理解其逻辑。例如你可能看到... (一些前置代码) cmp eax, 0 ; 比较 eax 是否等于 0 (可能判断是否死亡) je short f ; 如果等于0就跳转到某个标签处可能是死亡处理 mov edx, [ebp-10] ; 将伤害值放入 edx sub [esi5510], edx ; 从生命值中减去伤害值 - 这是我们找到的关键指令 ...这段代码的逻辑是先检查某个条件是否死亡如果不死亡则执行扣血操作。6.2 编写自定义汇编代码我们的目标是不让生命值减少。有几种思路空操作NOP最简单的办法是把sub [esi5510], edx这条指令替换为等长的nop指令机器码0x90。这样扣血操作就什么都不做。但这条指令是5字节sub指令的编码而nop是1字节所以需要5个nop。跳转JMP将这条指令替换为无条件跳转指令jmp直接跳过扣血代码段。这需要计算跳转偏移。逆向操作把减法改为加法甚至改为赋值。例如把sub [esi5510], edx改为add [esi5510], edx加血或者改为mov [esi5510], 9999锁定满血。6.3 使用“自动汇编”进行注入CE提供了强大的“自动汇编”脚本功能可以方便地编写和注入代码。在地址列表中右键点击你的目标地址选择“找出是什么改写了这个地址”定位到关键指令。在反汇编窗口中右键点击那条关键指令如sub [esi5510], edx选择“自动汇编” - “模板” - “代码注入”。CE会自动生成一个注入模板它主要包含以下部分alloc在你的目标进程中分配一小块内存用于存放我们的新代码。这块内存是“可执行”的。label定义标签用于跳转。原指令的复制模板会自动包含原始的那条sub指令。注入点在originalcode:标签后newcode:标签前是执行我们自定义逻辑的地方。jmp最后跳转回原程序继续执行。生成的模板类似这样[ENABLE] // 分配内存 alloc(newmem, 2048) label(returnhere) label(originalcode) label(newcode) // 新分配内存的地址 newmem: // 这是我们的新代码区可以在这里写自定义逻辑 // 例如什么都不做直接跳回原代码 jmp newcode originalcode: // 这里是原始指令的副本 sub [esi00005510],edx newcode: // 执行完我们的逻辑或原始指令后跳回原程序 jmp returnhere // 这里是原程序中我们要修改的地方 // 用一条跳转指令跳到我们新分配的内存块开始执行 目标模块.dllABCDE: jmp newmem nop nop // 可能用nop填充原指令剩余字节 returnhere: [DISABLE] // 禁用时的代码用于恢复原状 dealloc(newmem) 目标模块.dllABCDE: sub [esi00005510],edx // 恢复原始指令修改模板在newmem:标签下originalcode:标签前写入我们的逻辑。如果我们想实现无敌不扣血可以直接注释掉或删除originalcode:标签下的sub指令或者更清晰一点在newmem:处直接跳转到newcode:完全绕过原始扣血指令。newmem: jmp newcode // 直接跳过原始扣血指令执行脚本点击“执行”按钮。如果脚本语法正确CE会进行内存分配、写入新代码、修改原程序跳转。此时游戏中的扣血逻辑应该就失效了。你可以通过“手动添加地址”将分配的内存地址newmem添加进来查看其内容。6.4 理解注入原理这个过程本质上是“钩子”Hook。目标模块.dllABCDE:处的原始指令被替换为jmp newmem。当程序执行流到达这里时不再是执行sub扣血而是跳转到我们分配的newmem内存块。在这里我们执行自定义逻辑或者什么都不做然后执行原始的sub指令如果我们保留了它最后通过jmp returnhere跳回原程序jmp指令之后的位置继续执行。[DISABLE]部分则用于清理释放分配的内存并恢复原始指令让游戏恢复正常。实操心得代码注入是强大的也是危险的。错误的注入如跳转地址计算错误、没有保存寄存器状态会导致游戏立即崩溃。务必在注入前保存游戏。从简单的“空操作”开始练习。在自动汇编脚本中originalcode:部分最好保留原始指令的副本除非你完全确定要替换它。另外注意指令对齐和长度jmp指令是5字节如果原指令小于5字节需要用nop填充否则会破坏后续指令。7. 高级技巧与实战问题排查掌握了基本流程后一些高级技巧和常见问题能让你事半功倍。7.1 处理浮点数与双精度数很多游戏使用浮点数Float, 4字节或双精度数Double, 8字节来表示百分比、坐标、时间等。在扫描时数值类型必须选对。对于浮点数在CE中输入值时可能需要带上小数位或者使用“浮点数”扫描类型下的“介于两者之间”来应对精度微小的变化。修改时在地址列表双击数值可以直接输入小数。7.2 扫描字符串与字节数组除了数值还可以扫描文本字符串如角色名、物品名。选择“字符串”扫描类型并指定字符串长度。对于更模糊的匹配如不知道具体数值只知道字节模式比如一段特定的机器码可以使用“字节数组”扫描类型输入用空格分隔的十六进制字节未知的字节用?代替例如89 45 FC ? ? 8B 4D。7.3 使用“内存查看器”进行深度分析内存查看器快捷键 CtrlM是强大的手动分析工具。你可以输入一个地址查看其周围大范围的内存数据。结合对程序数据结构的理解例如一个游戏角色对象可能在内存中连续存放着生命值、魔法值、坐标X、坐标Y等你可以通过修改一个已知地址如生命值然后在内存查看器中上下浏览寻找附近同步变化的、格式相似的数据从而发现其他属性的地址。7.4 常见问题与排查清单扫描不到/结果太多检查数值类型尝试4字节、浮点数、双精度、所有类型。检查扫描范围默认是全部内存可以尝试缩小到特定模块如游戏的.exe或主要.dll。使用“未知初始值”对于不知道具体数值但知道变化规律的数据。找到的地址重启后失效这是动态地址。必须使用“指针扫描”或手动分析汇编指令找出是什么访问/改写了它来寻找基址指针。代码注入导致游戏崩溃寄存器保护在你的注入代码开头使用pushad指令保存所有通用寄存器状态在跳回前使用popad恢复。模板通常会自动生成。堆栈平衡确保你的注入代码没有破坏堆栈指针ESP。不要随意进行push而不对应pop。跳转地址错误jmp指令的跳转目标是相对偏移或绝对地址确保计算正确。使用CE的标签label功能可以让它自动计算。指令长度确保覆盖原指令的jmp指令5字节加上可能的nop填充总长度不小于原指令长度。反作弊/保护机制单机游戏一般没有。一些游戏会使用简单的“完整性检查”比如关键代码段 checksum 验证或者对关键数据存储多份副本进行比对。这需要更复杂的逆向分析来绕过已超出入门范围。7.5 结构体的探索与利用在内存查看器中如果你发现一组数据比如生命、魔法、体力总是以固定的间隔出现在同一个地址附近这很可能是一个“结构体”。CE的“结构体分析”功能在“工具”菜单下可以帮你自动分析这些数据的偏移量。你可以定义一个结构体例如Player包含Health (offset 0)Mana (offset 4)Stamina (offset 8)。然后当你找到一个角色的生命值地址时CE可以自动帮你计算出魔法值和体力值的地址极大提升效率。8. 安全、伦理与学习路径延伸8.1 法律与道德边界Cheat Engine是一个中性工具其用途取决于使用者。务必遵守以下原则仅用于单机与学习绝对不要在任何多人游戏、网络游戏或带有在线服务的游戏中使用这违反用户协议会导致账号永久封禁也可能涉及法律问题。尊重知识产权你的分析学习应限于个人技术研究范畴。勿作恶不要利用此类技术开发、传播破坏性程序或进行非法活动。8.2 从CE出发的深入学习路径CE是逆向工程世界的“前厅”。当你熟练掌握了内存扫描、指针查找和基础代码注入后可以朝着更专业的方向迈进静态分析学习使用IDA Pro或Ghidra进行程序的静态反汇编分析整个函数的逻辑和控制流。动态调试深入使用x64dbg或OllyDbg它们提供比CE更强大的调试功能如硬件断点、条件断点、更细致的线程和模块管理。汇编语言深入学习x86/x64汇编语言这是理解所有逆向工程行为的基石。Windows API与PE结构了解程序如何被操作系统加载理解导入表、导出表、节区等概念。反反调试技术了解常见的反调试手段如IsDebuggerPresent,NtGlobalFlag及其绕过方法这是分析有保护程序的必经之路。逆向工程是一条漫长而有趣的道路Cheat Engine以其独特的低门槛和直观的反馈为你打开了第一扇门。记住核心不是记住某个游戏的修改方法而是掌握“观察-定位-分析-修改”这一套方法论。多动手从简单的程序开始耐心分析每一条指令思考每一个数据变化的原因你的能力会在解决一个又一个具体问题的过程中稳步提升。最后保持好奇保持敬畏享受解构与重建的乐趣。