12.UE-游戏逆向-DumpUE对象
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
本次游戏没法给
内容参考于:微尘网络安全
上一个内容:11.UE-游戏逆向-内存中的FUObjectArray(深入理解内存数据)
本次来保存游戏中的ue对象,主要需要的东西是下图红框UObjectBase里面的变量
UObjectBase里面有虚函数
主要用到的变量是下图红框的3个
代码说明
/** 用于跟踪和记录对象各种状态的标志(枚举类型)* 说明:* - EObjectFlags是一个枚举,里面定义了很多"状态位"(比如"对象是否已加载"、"是否需要被垃圾回收"、"是否是临时对象"等)* - 这些标志就像对象的"状态标签",系统通过检查这些标签快速判断对象的当前状态* - 特别处理:在32位系统上需要8字节对齐(内存对齐),避免内存浪费*/
EObjectFlags ObjectFlags;/** 全局对象数组(GObjectArray)中的索引,非常私密的内部标识* 说明:* - GObjectArray是UE管理所有对象的"总名单",每个对象在这个名单里都有一个唯一位置* - InternalIndex就是这个位置的编号(类似"学号"),系统通过这个编号能直接找到对象在数组中的位置,速度极快* - "非常私有"表示这个值只在引擎内部使用,开发者一般不需要手动修改*/
int32 InternalIndex;/** 对象所属的类(类的元数据指针)* 说明:* - UClass是UE中"类"的描述类型(比如"玩家类"、"武器类"的元信息都存在UClass里)* - ClassPrivate指向当前对象的"模板类",比如一个玩家对象的ClassPrivate就指向"玩家类"的UClass* - 作用:通过它可以知道"这个对象是什么类型的",以及这个类型有哪些功能(函数、属性等)*/
UClass* ClassPrivate;/** 这个对象的名字* 说明:* - FName是UE的高效名字类型(由GName系统管理,全局唯一,不重复存储)* - NamePrivate存储对象的名称,比如"Player_01"、"Sword_03",方便开发者识别对象* - 和普通字符串不同,FName通过索引管理,比较和查找速度极快*/
FName NamePrivate;/** 这个对象所在的"外部对象"(所有者或容器)* 说明:* - OuterPrivate表示当前对象的"上级容器"或"所有者",形成对象间的层级关系* - 举例:一个武器组件(UObject)的OuterPrivate可能指向它所属的角色对象(另一个UObject)* - 作用:管理对象的生命周期(当所有者被销毁时,它包含的对象也可能被销毁),以及组织对象的层级结构*/
UObject* OuterPrivate;
这里有个东西,FName它有里面有一个字符串的索引(id),这里可以使用CE找到UObjectBase类型的值,然后查看NamePrivate的值,然后使用之前实现的GName算法来看看它的FName是什么,首先使用0x4A92740偏移来到FUObjectArray
然后单击下图红框,然后按空格进入TUObjectArray结构,注意下图红框是FUObjectArray+0x10位置
然后进入TUObjectArray里的FUObjectItem**,也就是单击下图红框,然后按空格
按完空格后就进入了FUObjectItem**结构的数据
下图红框都是一个UObjectBase结构的内存地址
然后使用鼠标进行选中,按一下CTRL+C进行复制
然后如下图选择工具里的分析数据/遍历
然后把复制的东西粘贴到下图红框位置
然后选择定义新的结构
下图红框随便写,然后点击确定
然后就可以看到下图绿框是一个id,这个id就可以进行搜索
这个数字可能是十六进制显示的,如下图选择4字节就会以十进制显示,id是十进制的
然后使用我们的GName解密,如下图可以看到1097好像是一个路径
到这应该会很蒙,又是FUObjectItem又是UObjectBase这都什么玩意,刚开始蒙就对了,现在应该有一点了解UObjectBase这个结构,但感觉差点事,现在应该是这种感觉,下面来整理一下
这一切都是从第10节,查找UObject开始,最开始说UObject是UE中所有 “可被引擎管理的对象” 的基类资源对象,就是武器、人物、材质、组件这些对象(对象就是对某个结构的数据在内存中的称呼),然后找UObject是通过vs2022搜索GUObjectArray这个关键字,就找到了FUObjectArray结构,这个FUObjectArray结构是用来记录UObject的,然后就开始分析FUObjectArray,它偏移0x10位置有个TUObjectArray类型,较早之前是使用FUObjectArray来实现UObject的记录和管理,但是FUObjectArray它不是很好,所以就有了TUObjectArray类型来代替FUObjectArray,TUObjectArray里面就有FUObjectItem,FUObjectItem对应一个UObject(UObjectBase),FUObjectItem里面记录的是UObject的地址,UObject是UObjectBase的升级版,它里面有,如下的白话解释
UObjectBase
里的信息不多,但每一条都是 “必须项”,少了它,小区(引擎)就不认这个住户(UObject
):
「身份标签」(
ObjectFlags
)类似身份证上的 “状态标记”,比如 “是否有效”“是否临时住户”“是否需要注销”。引擎通过这些标签快速判断这个对象的基础状态(比如 “这户是不是已经搬走了?”)。
「全局编号」(
InternalIndex
)小区给每户分配的唯一编号(比如 “XQ2023001”),和
TUObjectArray
登记本里的编号对应。引擎查这个号,能立刻在登记本里找到这户的详细记录(FUObjectItem
)。「所属类型」(
ClassPrivate
)记录这户是 “什么类型的住户”,比如 “居民户”“商户”“物业办公室”。对应到游戏里,就是记录这个
UObject
属于哪个类(比如 “角色类”“道具类”),让引擎知道它能做什么(有哪些功能)。「住户姓名」(
NamePrivate
)这户的名字(比如 “张三家”“便民超市”),用
FName
类型存储(全局唯一,不会重名)。方便开发者在编辑器里识别对象(比如在蓝图里看到 “Player_01” 就知道是哪个角色)。「所属上级」(
OuterPrivate
)记录这户 “归谁管”,比如 “3 单元 201 室归 3 单元楼长管”。游戏里就是对象的 “上级容器”(比如 “武器组件” 归 “角色” 管),确保对象的层级关系清晰,方便批量管理(比如角色删除了,它的武器也跟着删)。
这个东西就是很乱,想不乱只能多写多看,有一个dump代码是用来把游戏中的对象、函数、名字、内存中的地址保存到硬盘上的,上方的不理解也没事都是些理论,实际上用起来并没有那么多事
需要改的位置,代码的原理就是先获取GName,然后通过上方的公式
FUObjectArray+0x10位置读取TUObjectArray
然后再从TUObjectArray+0x14位置获取当前元素的数量
然后从TUObjectArray+0x18位置获取当前块的数量
然后从TUObjectArray=0x0位置获取FUObjectItem
FUObjectItem里有0x14大小,在内存里有内存对齐,它会变成0x18
然后从FUObjectItem里得到UObjectBase
然后从UObjectBase+0x10位置获取Class
然后从UObjectBase+0x18位置获取FName也就是名字
然后从0x20位置获取UObject也就是对象
文件保存在下图红框的目录里
效果图:保存所有的对象的地址