先说结论:Cheat Engine 7.2 和 7.5 的编译流程,核心是搞定 Lazarus 和 FPC 的版本匹配,其它都是小问题。但“其它都是小问题”这句话背后,是我从 Lazarus 2.0.x 一路试到 2.2.6,踩了十几个编译错误、重装了三遍环境之后才得出的。这篇东西就是把我这两天的完整过程、每个报错的定位思路和最后能稳定编译的配置全部摊开写出来,给后面要自己动手编 CE 的人省点时间。
Cheat Engine 本身是开源项目,源码在 GitHub 上可以直接拿到,但很多人在第一步就被“用 Delphi 还是 Lazarus”“要不要装 VS”“为什么 7.5 用老版本 Lazarus 编不过去”这些问题拦住。我这次把 7.2 和 7.5 各编了一遍,Windows 和 Linux 两个平台也都跑通了。下面按我的实际操作顺序来讲,不是抄官方 Wiki,是我自己验证过、能落地的流程。
1. 为什么折腾源码编译:官方安装包给不了的东西
很多人会先问我一句:官方论坛不是直接有安装包吗?下载解压就能用,何必从头编译?这个问题的答案其实分三层。
第一层是信任问题。CE 是个调试器,也是内存扫描工具,这类工具你要往系统里加载,最好自己知道里面每一行代码在干什么。官方发布的二进制虽然经过签名,但毕竟不是所有用户都有能力逆向验证。自己编译,相当于把整个构建过程暴露在阳光下,哪怕你不逐行读源码,至少可以确认这个 exe 是从我刚拉下来的源码编出来的,不是被塞了私货的版本。
第二层是定制需求。CE 7.x 之后加入了 Lua 脚本环境,大量功能可以通过脚本实现,但有些行为是写在 Pascal 源码里的。比如我需要在内存 View 里加一个自定义的解析器,或者改掉默认的字体渲染方式,这些不改源码做不到。官方安装包是一锤子买卖,想改就得编译。
第三层是学习价值。CE 的代码质量在开源逆向工具里算很高的,它内部集成了 Windows 调试 API、Veh 调试器、DBK 内核驱动、Lua 脚本引擎、符号处理、Mono/Net 数据采集器,这些东西单拆出来每一个都是能写一本书的主题。编译它,就是把这些模块之间怎么组织、怎么协作的过程完整走了一遍。说实话,把一个 CE 源码结构看懂,比看十篇讲“内存断点原理”的文章都管用。
所以别嫌折腾,编译 CE 这件事本身就是在学逆向工程的工程化组织方式。后面我会把源码目录结构也梳理一遍,你看完就知道 CE 不是一个“一个 exe 打天下”的玩具项目,它是一整套工具链。
2. 环境选型:7.2 和 7.5 对工具链的要求完全不一样
先说最影响成败的一点:Cheat Engine 不是用 Visual Studio 写的。核心部分是 Free Pascal + Lazarus,虽然有 DBK 驱动是 C/C++ 工程,但默认用户态编译根本不需要打开 VS。很多第一次编译的人第一反应去装 VS2010、VS2019,结果毫无用处,还跑出一个 msb6006 的报错,白白浪费半天。
2.1 7.2 的推荐搭配
CE 7.2 是 2020 年底发布的版本,对应的 Lazarus 版本比较老。我实际测试下来,用以下组合最稳:
- Lazarus 2.0.10 + FPC 3.2.0
- 编译平台:Windows x64 或 x86
- 不需要额外装任何 SDK
这个组合下,7.2 基本是“拉下来直接就能编过”。如果你用更高的 Lazarus 2.2.x 去编 7.2,有概率会碰到一些 LCL 类型定义不一致的问题,比如TList泛型化相关的方法签名变了,虽然也能改,但没必要给自己找麻烦。
2.2 7.5 的推荐搭配
7.5 的源码更新,对工具链的要求也水涨船高。我测试时用的组合是:
- Lazarus 2.2.6 + FPC 3.2.2
- 编译平台:Windows x64
- 建议装完 Lazarus 后确认 FPC 版本号能对上
7.5 的代码里用到了不少新版 FPC 才提供的特性。我之前用 Lazarus 2.0.10 编 7.5,报了一堆unit not found,比如找不到lazutils.StrUtils之类。这不是源码缺文件,而是旧版 Lazarus 自带的 FPC 库没有这些新单元。所以 7.5 如果编不过,十有八九先检查环境版本而不是去改代码。
2.3 版本对应关系背后的原理
为什么 CE 对 Lazarus/FPC 版本这么敏感?因为 CE 的界面层大量依赖 Lazarus 的 LCL 组件库,而 LCL 在不同版本之间 API 并不完全兼容。FPC 的 RTL 和 FCL 库也在持续演进,新增单元、改函数签名是常态。CE 官方不可能为一个版本维护多套代码,所以它只保证在某个范围内的编译器版本下能通过。
打个比方,这就像你拿新版 GCC 去编译一个依赖旧版头文件的 C 项目,大概率会遇到implicit declaration警告甚至直接报错。不是你代码不行,是工具链版本错配。CE 编译最大的坑也就在这,版本不对,后面的所有努力都是白费。
3. 操作流程:拉源码、开工程、出 exe
环境装好之后,编译本身其实不复杂。我把完整流程拆成几个步骤,每一步的注意事项写清楚。
3.1 获取源码与目录结构
CE 的源码托管在 GitHub,仓库名就是 cheat-engine/cheat-engine。你可以用 git 拉,也可以直接下对应版本的 zip 包:
git clone https://github.com/cheat-engine/cheat-engine.git拉下来之后,你会看到根目录下有一堆文件夹。其中最核心的是Cheat Engine这个子目录,里面放着主程序的 Lazarus 工程。其它目录也用得上:
| 目录 | 作用 |
|---|---|
| Cheat Engine | 主程序源码,含 CheatEngine.lpi 工程文件 |
| CEClient | CE 客户端,用于连接 CE 服务和共享内存 |
| DBK | 内核驱动源码,C/C++ 工程,默认不参与编译 |
| Tutorial | 官方培训教程程序的源码 |
| Cheat Component | 一些可复用的组件库和第三方工具 |
我第一次编译时犯了个错误:直接打开根目录下的某个.lpi乱找,结果工程加载报错。后来才搞清楚,7.2 和 7.5 的主工程文件都在Cheat Engine/CheatEngine.lpi。你只要在 Lazarus 里 File -> Open 打开这个文件就行。
3.2 在 Lazarus 里设置好目标和平台
打开工程后,先不要急着按 F9 编译,先确认两个关键配置。
第一是 FPC 源目录。位置在 Lazarus 菜单:Tools -> Options -> Files -> FPC Source Directory。这里要填你安装的 FPC 源码路径。Windows 下一般长这样:
C:\lazarus\fpc\3.2.2\source如果这个路径没填对,或者填成了编译器的 bin 目录,后面会报一堆找不到系统单元的错误。这是小白最容易忽略的点。
第二是编译目标 CPU 架构。CE 编译时可以选 x86_64 或 i386,位置在:Project -> Project Options -> Compiler Options -> Config and Target -> Target CPU family。
这里需要说明一下:如果你想编 64 位 CE,就直接用 64 位 Lazarus,选x86_64;如果你要编 32 位 CE,需要用 32 位版本 Lazarus,选i386。不建议用交叉编译方式在 64 位 Lazarus 里编 32 位程序,因为 CE 用了一些平台相关的汇编代码,交叉编译环境不好调,直接用对应位数的 IDE 最省心。
3.3 编译并定位输出文件
配置好之后,按 Shift+F9 编译(不带运行),或者直接按 F9 编译并运行。第一次编译会花几分钟,因为 FPC 要重新编译大量 RTL 单元。之后增量编译就很快了。
编译成功后,可执行文件默认会生成在源码目录下的output文件夹里,也可能是Cheat Engine\output,具体看工程配置。Windows 下生成的文件名一般是cheatengine-x86_64.exe(64 位)或cheatengine-i386.exe(32 位)。你可以右键 exe -> 属性 -> 详细信息,确认版本号是 7.5 还是 7.2。
如果你不想跑起来,只想要一个 Portable 版本,这一步就够用了。编译出的 exe 不依赖安装包,拷贝到其它机器上能直接跑。
4. Linux 下编译 CE:依赖比 Windows 更多,但没那么可怕
CE 从 7.x 开始官方支持 Linux,很多人在 Windows 上编完后想试试 Linux 版,结果卡在依赖安装上。我在 Ubuntu 22.04 下编译 7.5 的过程如下。
4.1 安装 Lazarus、FPC 和依赖包
先装基础环境:
sudo apt update sudo apt install lazarus fp-compiler fp-units-rtl这里有个要注意的地方:Ubuntu 仓库里的 Lazarus 版本可能比较老,比如 22.04 自带的是 2.2.6 左右,编译 7.5 勉强够。如果你发现版本太老,建议从 Lazarus 官网下载新版 deb 包,不要硬编。
CE 的界面依赖 GTK2,再加上它还要读取libcurl、libsqlite3之类的库,所以还需要这些开发包:
sudo apt install libgtk2.0-dev libcurl4-openssl-dev libsqlite3-dev4.2 Linux 编译和 Windows 的差异
打开工程后,Lazarus 会根据当前系统自动选择 Linux 目标,通常不需要手动改 OS。但有几个点要留意:
- CE 在 Linux 下默认用的是
ptrace调试机制,编译时不需要额外的驱动,DBK 目录完全不用管。 - 如果你用的发行版不是 Ubuntu/Debian 系,包管理器安装的命令可能不一样,但依赖库的名字差别不大。
- Linux 下编译速度通常比 Windows 快一些,因为 FPC 全量编译时磁盘占用更小。
我第一次在 Ubuntu 上编 CE 时漏装了 libgtk2.0-dev,结果编译到 GUI 部分直接报cannot find -lgtk-x11-2.0。这个问题只看源码根本查不出来,必须确认开发库装了。很多从 Window 转到 Linux 编译的人都会栽在这,建议编译前先把依赖库一次装齐。
4.3 Linux 下运行自测
Linux 版编译成功后,直接在终端执行:
./cheatengine-x86_64如果界面能正常弹出来,就说明编译成功。需要注意的是,Linux 版 CE 在 Wayland 会话下可能显示异常,建议用 Xorg/X11 会话跑,这是 CE 本身在 Linux 下的兼容问题,不是编译导致的。
5. 编译期高频报错排查实录
这一节是我最想写的,因为网上关于 CE 编译报错的讨论很零散,而实际编译时踩的坑就那么几个。我把它们按出现频率从高到低列出来,每个都给出定位思路而不是只给答案。
5.1 msb6006 cmd.exe 已退出,代码为 3 —— 几乎都是环境问题
首先这一点必须说明:如果你只是编译用户态 CE(Lazarus 主工程),根本不会碰到 msb6006。这个报错几乎都出现在用 Visual Studio 编译 DBK 驱动工程时,或者某些人试图在 VS 里打开 CE 的 C/C++ 项目时。
“cmd.exe 已退出,代码为 3”这个提示很误导,它只是说某个命令执行失败了,真正的错误信息往往在上面几百行的日志里。我的排查套路是:
- 不要盯着 msb6006 本身,往上看日志,找到真正失败的步骤。
- 最常见的原因是 WDK(Windows Driver Kit)没装,或者装的版本和 DBK 工程不匹配。DBK 是内核驱动,编它需要 WDK 对应版本的库文件。
- 其次是路径问题。工程里的中间目录用了带空格的路径,或者源码放在中文目录下,cmd.exe 解析时出错。
- 最后可能是杀毒软件拦截了 cmd.exe 调用。CE 的驱动代码行为太像恶意程序,某些安全软件会直接阻止编译工具链创建子进程。
如果你只是想要一个能用的 CE,DBK 驱动其实不是必需的。CE 7.x 默认使用 VEH 调试器,不装 DBK 也能完成绝大多数内存调试操作。所以遇到 msb6006 别慌,跳过驱动部分,把 Lazarus 工程编出来,功能完全够用。
5.2 unit not found:版本错配的重灾区
这类报错的表现形式很多,什么Fatal: Cannot find unit xxx、unit not found: lazutils.TimerSupport、cannot find unit interfaces。我见过有人因为这个重装了三次系统,实际上就是环境版本不对。
比如你用 Lazarus 2.0.10 编 CE 7.5,自带的 FPC 3.2.0 缺少 7.5 源码引用的新单元,于是报unit not found。这种错误用搜索引擎很难查到,因为不同 CE 版本需要的单元不一样,但根因非常一致:Lazarus/FPC 版本低于项目要求。
修复方式是先把 Lazarus 版本升到官方推荐的版本(7.5 建议 2.2.6 + FPC 3.2.2),然后重新编译。别指望手动拷贝几个缺失的.ppu文件能解决,因为版本不匹配会导致编译出的单元二进制格式不一致,拷过来也是白搭。
5.3 资源文件与 LFM 界面描述编译失败
CE 的界面全部用 Lazarus 的 .lfm 文件描述,编译时 LRS(Lazarus Resource)工具会把 .lfm 转成二进制资源。如果 .lfm 文件里有新版 Lazarus 不认识的属性,就会在编译资源阶段报错,比如:
CheatEngine.lfm(123,4) Error: Unknown property TForm1.Padding这类问题的原因基本是:源码里的 .lfm 是用新版 Lazarus 写的,但你的 IDE 版本太旧,不认识新增的属性。解决方法和上面一样,升级 Lazarus。反过来,如果你用新版 Lazarus 编老版本 CE 的源码,也可能因为某些旧属性被移除而报错。所以版本匹配这个事,真的是第一优先级。
5.4 32 位与 64 位工程混乱
CE 源码里的两套目标经常让人绕晕。你把源码拉下来后,默认工程可能是 32 位也可能是 64 位,取决于当时作者提交时的状态。如果编译出来运行提示“不是有效的 Win32 应用程序”,说明你目标平台选错了。
解决办法是在 Project Options 里显式指定 Target CPU family 和 Target OS。Windows 上如果直接下载的是 64 位版本,编译时选 x86_64 就行;如果你需要 32 位并且 IDE 是 64 位,最好老老实实再装一个 32 位 Lazarus,两个 IDE 可以共存,不用卸载。
5.5 编译通过但启动报缺少 DLL
这类问题出现在编译成功之后,运行 exe 时提示缺少某个 DLL,比如libcurl.dll或lua54.dll。CE 源码里部分第三方库是动态加载的,编译时不会自动把 DLL 复制到输出目录。
解决办法是去 CE 的源码目录里找对应的 DLL 文件。CE 官方源码会带上运行所需的动态库,通常在Cheat Engine\或者resources目录下。你把这几个 DLL 复制到 exe 同一目录即可:
lua54.dll libcurl.dll sqlite3.dllWindows 下我用的是 CE 源码自带的 dll,Linux 则是直接用系统的 .so 库。总的来说,编译成功只是第一步,运行环境缺库是另一个坑,别以为 exe 编出来就万事大吉。
6. 编译完成后的验证、使用与二次开发入口
编译完成不代表真的能干活,我一般会按这个顺序测试。
6.1 自测流程
- 打开 CE,看 About 里的版本号是否和源码版本一致。
- 附加到一个普通进程(比如记事本),看能不能正常读取内存和扫描数值。
- 切到 Memory View,随便跳到某个模块地址,看反汇编窗口是否正常工作。
- 跑一遍 Lua 脚本,比如执行
print(getAddress("kernel32.dll")),确认脚本引擎没被静态编译漏掉。
如果这些都没问题,说明主要模块编译完整。CE 的 Lua 引擎是内置在二进制里的,编译后不会有单独脚本文件,所以能执行 Lua 语句就说明集成成功。
6.2 便携版整理
自己编译完 CE 后,如果想做成便携版,可以按这个方式整理目录:
CE-Portable/ cheatengine-x86_64.exe lua54.dll libcurl.dll sqlite3.dll dbk64.sys # 如果编译了驱动的用户态部分值得注意的是,官方安装包会额外创建一些目录和配置文件,但便携模式下 CE 会自动在当前目录生成配置。把编译出的 exe 和依赖 dll 放在同一个文件夹里,运行一次就会自动生成Cheat Engine的配置目录,不需要安装程序。
6.3 源码结构和二次开发入口
如果你编译 CE 不仅仅是为了用,还想改点东西,我建议按这个顺序看源码结构:
Cheat Engine/主程序目录,里面最大的是MainUnit.pas,对应主界面。Cheat Engine/MemoryViewUnit.pas,对应内存查看窗口,很多逆向功能都在这里。Cheat Engine/ProcessListUnit.pas,进程列表窗口。Cheat Engine/lua相关目录,是 Lua 引擎的封装层,CE 环境和脚本指令的绑定都在这里。
想加一个自定义脚本函数,入口一般在LuaHandler.pas或者luaengine.pas里面,找到lua_register就能看到所有注册给脚本的函数列表。照着现有函数写一个注册调用,重新编译,你的自定义 Lua API 就生效了。这是我目前玩 CE 源码感觉最有意思的点。
7. 给新人的几条实用建议
最后说几条我在实际操作中的体会,不一定都写在官方文档里,但很实用。
第一,版本的坑不要自己死磕。CE 源码的 README 或者 GitHub Wiki 一般会写推荐的 Lazarus 版本,直接按推荐来。用比我推荐更新的版本不一定有好处,反而可能踩到 CE 还没适配的新 API。稳定编译比追新重要。
第二,装完 Lazarus 后先编一个空项目,确认 FPC 源目录配置正确,再打开 CE 工程。如果你连一个空窗口程序都编不出来,那问题不在 CE 而在环境。这一步能帮你把时间花在真正的问题上。
第三,编译时把杀毒软件关了或者加白名单。CE 的代码特征太明显,不少安全软件会在编译中途直接删除生成的 exe 或者拦截进程创建。我第一次编的时候,Windows Defender 把编译产物给删了,我还以为自己代码有问题,排查了半小时。
第四,遇到报错,往下刨,不要只搜报错信息。很多编译错误都有“真实错误”和“表象错误”两层。比如 msb6006 是表象,真实错误可能是 WDK 没装。养成先看完整日志、再搜索最小错误关键字的习惯,会让你少走很多弯路。
第五,如果只是日常用,没必要每版都自己编译。想省事直接用官方安装包,自己编译更多是为了定制和学习。我后面整理的二次开发入口和源码结构,目的就是让你把这个工具变成“自己的”。编译这块折腾一次就够了,剩下的时间应该花在研究 CE 强大的调试和内存分析能力上。
所有流程和报错基本上就这些。CE 7.2 和 7.5 编译,说难不难,说简单也真不简单。最核心的还是把工具链版本搞定,后面就是点几个按钮的事。希望这篇踩坑记录能把你从环境地狱里捞出来。