第十八章:逆向 Unreal Engine 游戏
Unreal Engine,简称 UE,在游戏圈的地位不用我多说。从《绝地求生》到《堡垒之夜》,再到各种 3A 大作,UE 几乎无处不在。说实话,我第一次逆向 UE 游戏时,也被它那套复杂的对象系统搞得有点懵。但摸清楚套路后,你会发现——嗯,其实 UE 的结构比很多自研引擎要规整得多。
这一章,我们就来拆解 UE 游戏的核心结构。我会带你看看 GObjects、GNames 这些关键数据,再聊聊怎么用 UE4SS 这类工具快速上手。
UE 游戏的结构:从外到内
一个 UE 游戏跑起来,内存里大概长这样:
- 引擎核心模块:负责渲染、物理、音频这些底层活儿
- 游戏逻辑模块:你的角色、武器、技能,都在这里
- 对象系统:UE 最骚的地方——所有东西都是 UObject
- 反射系统:运行时能拿到类的信息,这给逆向开了扇窗
我个人习惯先把 UE 游戏看作一个巨大的对象池。池子里泡着成千上万个 UObject,每个都有名字、有类型、有属性。你想想看,只要能遍历这个池子,游戏里的一切不就尽在掌握了?
核心要点:UE 的反射机制是逆向的突破口。它把类的信息暴露在运行时,我们只需要找到这些信息的存储位置。
GObjects 与 GNames:UE 的命门
UE 游戏有两个全局变量,是所有逆向工程师的宝贝——GObjects 和 GNames。
GObjects:对象大本营
GObjects 是一个数组,存着游戏中所有 UObject 的指针。说白了,这就是 UE 的对象管理器。每个 UObject 在数组里都有一个索引,通过索引就能拿到对象本身。
我曾在逆向一个 UE 射击游戏时,想找玩家的血量。直接搜内存?太慢了。我直接遍历 GObjects,找到玩家角色的 UObject,然后读它的属性——几秒钟就定位到了血量地址。
GObjects 的结构大概是这样:
// GObjects 本质上是一个 TUObjectArray
class FUObjectArray {
TUObjectArray* ObjObjects; // 对象数组
int32 NumElements; // 当前对象数量
int32 MaxElements; // 最大容量
};
// 每个 UObject 的开头
class UObject {
void* VTable; // 虚函数表
int32 ObjectFlags; // 对象标志
int32 InternalIndex; // 在 GObjects 中的索引
UClass* ClassPrivate; // 对象的类
FName NamePrivate; // 对象的名字
UObject* OuterPrivate; // 外部对象(通常是包)
};
小技巧:找 GObjects 地址,可以搜特征码 "48 8B 05 ? ? ? ? 48 8B 0C C8 48 8B 04 D1"(64位下)。这个模式在 UE 4.x 版本中很稳定。
GNames:名字的字典
GNames 是 UE 的名字系统。每个名字(比如 "PlayerState"、"Health")都有一个唯一的 ID,通过 ID 可以查到名字字符串。GNames 本质上是一个大数组,存着所有用到的名字。
为什么要搞这么复杂?因为 UE 里到处都要比较名字,用整数 ID 比字符串比较快得多。你想想看,每帧都要比较几万个名字,用字符串那还得了?
GNames 的结构:
// GNames 是一个 TNameEntryArray
class FNameEntry {
int32 Index; // 名字的索引
FNameEntry* HashNext; // 哈希链下一个
int32 Len; // 字符串长度
char Name[1024]; // 名字字符串(实际长度由 Len 决定)
};
// 通过 GNames 查名字
FNameEntry* Entry = GNames[Name.Index];
char* NameStr = Entry->Name;
注意:UE 4.0 到 4.25 之间,GNames 的结构变化了好几次。我曾经在逆向一个老版本 UE 游戏时,按新版本的偏移去读,结果读出来的全是乱码。所以,一定要先确认引擎版本。
使用 UE4SS 或类似工具进行逆向
手动找 GObjects、GNames 虽然能锻炼技术,但效率确实不高。好在社区有大佬做了 UE4SS 这样的工具,让我们能快速上手。
UE4SS 是什么?
UE4SS 是一个针对 UE 游戏的逆向辅助工具。它本质上是一个 DLL 注入器,注入后能提供:
- 对象浏览器:可视化查看所有 UObject
- 控制台:执行 Lua 脚本,调用游戏内部函数
- Dump 工具:导出游戏的所有类信息
- Live View:实时查看对象属性变化
我个人觉得 UE4SS 最香的功能是 Lua 脚本。你可以写脚本来自动化很多操作,比如批量修改属性、触发游戏事件、甚至写个简单的作弊菜单。
实战:用 UE4SS 找玩家坐标
假设我们要找一个 UE 游戏中玩家的坐标。用 UE4SS 怎么做?
- 注入 UE4SS 到游戏进程
- 打开对象浏览器,搜索 "Player" 相关的类
- 找到
APlayerController或ACharacter的实例 - 查看它的属性,找到
RootComponent或CharacterMovement - 在
USceneComponent里找到RelativeLocation
用 Lua 脚本实现:
-- 获取玩家控制器
local PlayerController = FindFirstOf("BP_PlayerController_C")
if PlayerController then
-- 获取控制的 Pawn
local Pawn = PlayerController:GetPawn()
if Pawn then
-- 获取位置
local Location = Pawn.K2_GetActorLocation()
print("玩家坐标: " .. Location.X .. ", " .. Location.Y .. ", " .. Location.Z)
end
end
你看,几行代码就拿到了坐标。要是手动逆向,你得先找 GObjects,再遍历对象,再解析属性——至少多花半小时。
核心思路:UE4SS 帮我们封装了 GObjects 和 GNames 的访问逻辑。你不需要关心底层怎么找,只需要关心「我要操作哪个对象」。
UE4SS 的局限性
当然,UE4SS 也不是万能的。我遇到过几个坑:
- 版本兼容:UE4SS 主要支持 UE 4.18 到 4.27,UE5 的支持还在完善中
- 反作弊检测:有些游戏会检测 DLL 注入,UE4SS 可能被 ban
- 性能开销:对象浏览器在对象数量多的时候会卡,我见过一个游戏有 10 万个 UObject,浏览器直接崩了
所以我的建议是:UE4SS 适合快速原型验证,但真要写稳定的工具,还是得自己实现 GObjects 遍历。
知识体系总览
下面这张图,是我梳理的 UE 逆向核心知识结构。你可以把它当作地图,随时回来看看自己走到哪了。
手动实现 GObjects 遍历
如果你不想依赖 UE4SS,或者想更深入地理解底层,那就得自己动手了。这里我给出一个手动遍历 GObjects 的流程:
- 定位 GObjects 地址:用 Cheat Engine 搜索特征码,或者通过分析引擎模块的导出表
- 解析对象数组:读取 GObjects 指向的 TUObjectArray,拿到对象指针数组
- 遍历对象:从索引 0 开始,逐个读取 UObject 指针
- 读取对象信息:通过 UObject 的 ClassPrivate 和 NamePrivate 获取类名和对象名
- 筛选目标:根据类名或对象名,找到我们感兴趣的对象
代码示例(伪代码,实际需要根据引擎版本调整偏移):
// 假设已经找到 GObjects 地址
uintptr_t GObjectsAddr = 0x12345678;
// 读取对象数组
FUObjectArray* ObjArray = *(FUObjectArray**)GObjectsAddr;
int32 NumObjects = ObjArray->NumElements;
// 遍历所有对象
for (int32 i = 0; i < NumObjects; i++) {
UObject* Obj = ObjArray->ObjObjects->GetObjectPtr(i);
if (Obj == nullptr) continue;
// 读取对象名字
FName Name = Obj->NamePrivate;
char* NameStr = GetNameFromGNames(Name.Index);
// 读取对象类名
UClass* Class = Obj->ClassPrivate;
FName ClassName = Class->NamePrivate;
char* ClassNameStr = GetNameFromGNames(ClassName.Index);
// 打印信息
printf("[%d] Class: %s, Name: %s\n", i, ClassNameStr, NameStr);
}
避坑指南:我曾经在遍历 GObjects 时,没检查对象指针是否有效,结果读到了一个已经被销毁的对象,直接崩溃。所以,一定要加空指针检查,最好再验证一下对象的 VTable 是否在合理范围内。
总结
逆向 UE 游戏,说白了就是跟 GObjects 和 GNames 打交道。这两个数据结构是 UE 的命门,掌握了它们,你就能在游戏内存里自由穿梭。
UE4SS 是个好工具,能帮你快速上手。但我建议你也要理解底层原理,这样遇到 UE4SS 搞不定的情况时,你还能自己动手。
嗯,这一章的内容就到这里。记住,实践出真知——找个 UE 游戏练练手,比看十遍教程都有用。
公众号:蓝海资料掘金营,微信deep3321