首页
社区
课程
招聘
[原创]Unreal Engine 4引擎基础及其2024第九届游戏安全竞赛-初赛-安卓客户端安全为例
发表于: 2026-9-12 17:19 13811

[原创]Unreal Engine 4引擎基础及其2024第九届游戏安全竞赛-初赛-安卓客户端安全为例

2026-9-12 17:19
13811

本文以 2024 第九届腾讯游戏安全竞赛安卓初赛题目(com.tencent.ace.match2024)为例,完整记录一次 UE4 手游的逆向过程。内容从 GUObjectArray、GWorld、GName 三大核心结构体的源码分析讲起,便于对 UE 引擎对象系统不熟悉的逆向入门者学习

ps:小白初次写文章,大佬们多多指教

使用工具:IDA 9.4Pro、Frida 17、ue4dumper

环境:Android 64 位,UE4.27

UE中所有东西都继承自UObject,引擎会维护一个全局对象数组GUObjectArray,里面存储了所有UObject对象的指针,通过这个数组可以遍历引擎中的每一个类,可以读取类的属性以及在内存中的偏移

UE引擎中有一个全局变量GWorld,代表当前游戏的世界状态,通过GWorld可以访问到当前游戏中的所有关卡、角色、物品等信息,获取运行时数据实例,并且是一个指针变量,指向Uworld

UE 不会在每个对象中存储字符串,而是将所有的字符串存储在一个全局的字符串池中,并给每个字符串分配一个唯一的索引 id,有了 GName,就可以将在内存中看到一个个整数映射回字符串,是FNamePool类型的全局唯一实例对象

我使用的工具是ue4dumper,这个工具需要Gworld,GUObjectArray,GName的地址

推荐一下这位师傅的文章fd2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3M7X3g2$3k6i4u0U0j5#2)9J5c8Y4m8Q4x3V1j5I4y4K6j5@1x3e0R3#2y4g2)9J5k6h3S2@1L8h3H3`.

网上也多有此类教程,大多写的很好,不再赘述

学习了上述结构体的基础布局之后

我们很容易知道两种思路(附件中均有实现,可以配合注释慢慢学习,分别是GetAddrByName,FindAddrInGWorld)

通过完全遍历 GUObjectArray,依次对比当前 Object 的名字与所需名字,若成立则返回 Object。

范围:全引擎所有 UObject(Actor、UClass、UFunction、UPackage、CDO 等)

优点:通用,什么都能找

缺点:慢;同名对象多(CDO 和实例),可能命中错的

适用:找非 Actor 对象(UClass、UFunction 等),或不确定目标在哪时全局搜索。

获取 GWorld 后,沿 GWorld -> PersistentLevel -> ActorList 这条链,遍历 Actors 数组,依次比对名字,命中则返回地址。

范围:当前关卡的 Actor(几百个)

优点:快,全是实例,不会命中 CDO

缺点:只能找 Actor,找不到 UClass、UFunction 这类非 Actor 对象

适用:找场景里的实际物体(玩家、敌人、墙、道具),操作运行时状态

初步学习完关键结构体,我们取2024第九届游戏安全竞赛-初赛-安卓客户端安全为例子,一步步深入,附件在最后

初步游玩可以发现一碰墙就生命值归零,在dump出的SDK中寻找生命值字样

在此可以找出偏移0x510

这时我们需要根据给定字符串找到运行时实例对象地址

我上述的第一思路是:

遍历GUObjectArray,根据上述结构体知识查出每个Object的名字,再匹配检查

后面能发现不太对,因为找出来的对象不处于Uworld中

故我们需要寻找当前Uworld下的

那么思路是寻找Gworld->PersistentLevel->ActorList->AActor(又已知这个继承于UObject)

实现看附件FindAddrInGWorld.js,具体原理是差不多的

且该脚本验证了Actor偏移问题

获取了之后接上setInterval即可

不与门触碰,所以我们需要说穿墙

首先我们可以看见Class: FirstPersonCharacter_C继承于Character.Pawn.Actor.Object

350K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0p5^5z5e0x3&6y4U0f1H3x3o6M7&6y4K6l9H3y4K6f1@1y4o6R3`.

而CapsuleComponent又继承于PrimitiveComponent,PrimitiveComponent内部的结构体BodyInstance

可以发现这里有我们角色的碰撞处理点,写frida脚本处理掉却发现人物卡死了,原因是地面其他点也被该位置控制

转换思路变成改掉Wall的碰撞处理点即可

553K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2M7$3E0Q4x3X3g2U0M7$3c8F1i4K6u0W2L8X3g2@1i4K6u0r3M7i4g2W2M7%4c8A6L8$3&6K6i4K6u0r3z5o6x3%4x3o6j5^5z5l9`.`.

看这篇文章启发我们可以去hookSetCollisionEnabled


传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

最后于 2026-9-12 17:24 被dayDReam_10编辑 ,原因:
上传的附件:
收藏
点赞 ・12
打赏
分享
最新回复 (5)
雪    币: 777
活跃值: (402)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2 楼
比赛附件太大了无法上传,有想要的请私聊
2026-9-12 19:41
0
雪    币: 4824
活跃值: (8332)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3 楼
感谢分享,文件太大可以试着上传github
2026-9-13 00:35
0
雪    币: 210
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4 楼
师傅好强,看完醍醐灌顶
2026-9-13 14:47
1
雪    币: 447
活跃值: (3751)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5 楼
强强
2026-9-13 18:59
1
雪    币: 110
活跃值: (9651)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6 楼
tql
2026-9-14 08:55
0
游客
登录 | 注册 方可回帖
返回