首页
社区
课程
招聘
ue4dumper 使用以及ue4外挂制作
发表于: 2022-10-21 20:05 21237

ue4dumper 使用以及ue4外挂制作

2022-10-21 20:05
21237

前段时间一直在试图了解ue4引擎的一些东西,在完成之后将一些“坑”显露出来,以防后来者再次踩坑。

之前因为一些众所周知的原因删掉了这篇文章并且将github仓库也删掉隐藏,最近跳槽后没有这个顾及,因此将文章和仓库重见天日...

ue4dumper 使用以及ue4外挂制作

Owner: Francis Frank
Tags: unreal engine

Toolkits

ue4dumper ue4dumper的起源仓库。

ue4dumper 作者对4.26引擎版本的改进。

UE4Dumper4.26.2 作者在wsl的环境下用cmake的工具链对4.26引擎版本的改进。

Manuscript

1. 如何确定想要破解游戏使用的unreal engine引擎版本

不同引擎之间GName的定义以及偏移,GWorld的偏移可能不同,因此必须先确定游戏使用的引擎版本,才能通过github上的ue4引擎源码来比对。

拿到游戏的apk,unzip包拿到apk的AndroidManifest.xml, 例如某游戏的ue4版本在该文件中如下:

图片描述

2. 如何找到GName和GWorld

不同的引擎可能不一样,作者也仅仅只看过如下三个版本引擎源码中和GName,GWorld相关的逻辑。
源码地址:source

2.1 unreal engine 4.18

GName

在一些文章中,说GName的找法如下:

图片描述

我在4.18版本中试了一下,ue4dumper失败,不知道这篇文章的作者是怎么理解的,我认为一般意义上的GName其实是TNameEntryArray而不是这篇文章作者认为的GNameEntryPoolAllocator + 0x14。虽然这两个之间存在联系,但是我认为通过GNameEntryPoolAllocator + 0x14的方法是不恰当的。

真实的GName的地址就是TNameEntryArray,其定义在Engine\\Source\\Runtime\\Core\\Private\\UObject\\UnrealNames.cpp文件中,是一个静态变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TNameEntryArray& FName::GetNames()
{
    // NOTE: The reason we initialize to NULL here is due to an issue with static initialization of variables with
    // constructors/destructors across DLL boundaries, where a function called from a statically constructed object
    // calls a function in another module (such as this function) that creates a static variable.  A crash can occur
    // because the static initialization of this DLL has not yet happened, and the CRT's list of static destructors
    // cannot be written to because it has not yet been initialized fully.  (@todo UE4 DLL)
    static TNameEntryArray* Names = NULL;
    if( Names == NULL )
    {
        check(IsInGameThread());
        Names = new TNameEntryArray();
    }
    return *Names;
}

因此通过在IDA中通过解析libUE4.so,要找的步骤如下:

  1. 在导出表中找到GetNames的函数:

图片描述

  1. 进入GetNames函数获得GName

图片描述

因此GName的地址就是0x5AF6818

GWorld

在源码中GWorldEngine\\Source\\Runtime\\Engine\\Classes\\Engine\\World.h中定义,其具体定义如下:

1
2
/** Global UWorld pointer. Use of this pointer should be avoided whenever possible. */
extern ENGINE_API class UWorldProxy GWorld;

可以看出GWorld是导出的,因此其必然存在于导出表中,通过IDA或者objdump -T 就可以看到:

图片描述

因此GWorld的地址就是0x5B31B50

2.2 unreal engine 4.26 & 4.23

GName

不知道是不是从4.23开始,至少作者看到的4.23以及4.26版本中GName的定义实际上已经是FNamePool,其定义在Engine\\Source\\Runtime\\Core\\Private\\UObject\\UnrealNames.cpp,如下:

1
2
static bool bNamePoolInitialized;
alignas(FNamePool) static uint8 NamePoolData[sizeof(FNamePool)];

上面的NamePoolData其实就是作为单例对象FNamePool实际存储的地址,因此其实找GName就是找NamePoolData这一块地址。

通过源码可以看到,NamePoolData在函数GetNamePool以及FNamePool的相关成员函数中都有体现。
GetNamePool,但该函数被static修饰,因此不能通过该函数来找NamePoolData

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Only call this once per public FName function called
//
// Not using magic statics to run as little code as possible
static FNamePool& GetNamePool()
{
    if (bNamePoolInitialized)
    {
        return *(FNamePool*)NamePoolData;
    }
 
    FNamePool* Singleton = new (NamePoolData) FNamePool;
    bNamePoolInitialized = true;
    return *Singleton;
}
  1. FamePool的成员以及构造/析构函数的this指针
1
2
3
4
5
6
7
8
9
10
11
12
class FNamePool
{
public:
    FNamePool();
 
    void            Reserve(uint32 NumBlocks, uint32 NumEntries);
    FNameEntryId    Store(FNameStringView View);
    FNameEntryId    Find(FNameStringView View) const;
    FNameEntryId    Find(EName Ename) const;
    const EName*    FindEName(FNameEntryId Id) const;
        ....
}

通过IDA在到导出表中查FNamePool可以看到:

图片描述

进入FNamePool::FNamePool(void)函数中,该函数是FNamePool的构造函数,其第一个值为FNamePoolthis指针

图片描述

通过找该函数的调用,就可以找出this指针的地址:

图片描述

通过对arm指令集的了解,函数的第一个参数一般都存在X0寄存器中,因此我们清楚此处的ADRL X0, unk_A537200就是我们要找的东西,所以unk_A537200就是NamePoolData

GName的地址为0xA537200

GWorld

与4.18的方法一致,直接在导出表中查找:

图片描述

GWorld的地址为0xA6BBE18

GUObject

目前作者只看过4.26版本的GUObject,其查找方法也非常简单:

图片描述

在导出表搜索GUObjectArray即可,GUObject在此处为0x13A98780

3. dump的SDK.txt部分效果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Class: World.Object
    Level* PersistentLevel;//[Offset: 0x30, Size: 0x0]
    NetDriver* NetDriver;//[Offset: 0x38, Size: 0x0]
    LineBatchComponent* LineBatcher;//[Offset: 0x40, Size: 0x0]
    LineBatchComponent* PersistentLineBatcher;//[Offset: 0x48, Size: 0x0]
    LineBatchComponent* ForegroundLineBatcher;//[Offset: 0x50, Size: 0x0]
    GameNetworkManager* NetworkManager;//[Offset: 0x58, Size: 0x0]
    PhysicsCollisionHandler* PhysicsCollisionHandler;//[Offset: 0x60, Size: 0x0]
    Object*[] ExtraReferencedObjects;//[Offset: 0x68, Size: 0x0]
    Object*[] PerModuleDataObjects;//[Offset: 0x78, Size: 0x0]
    LevelStreaming*[] StreamingLevels;//[Offset: 0x88, Size: 0x0]
    StreamingLevelsToConsider StreamingLevelsToConsider;//[Offset: 0x98, Size: 0x0]
    FString StreamingLevelsPrefix;//[Offset: 0xc0, Size: 0x0]
    Level* CurrentLevelPendingVisibility;//[Offset: 0xd0, Size: 0x0]
    Level* CurrentLevelPendingInvisibility;//[Offset: 0xd8, Size: 0x0]
    DemoNetDriver* DemoNetDriver;//[Offset: 0xe0, Size: 0x0]
    ParticleEventManager* MyParticleEventManager;//[Offset: 0xe8, Size: 0x0]
    PhysicsVolume* DefaultPhysicsVolume;//[Offset: 0xf0, Size: 0x0]
    bool bAreConstraintsDirty;//(ByteOffset: 0, ByteMask: 0, FieldMask: 0)[Offset: 0x10e, Size: 0x0]
    NavigationSystemBase* NavigationSystem;//[Offset: 0x110, Size: 0x0]
    GameModeBase* AuthorityGameMode;//[Offset: 0x118, Size: 0x0]
    GameStateBase* GameState;//[Offset: 0x120, Size: 0x0]
    AISystemBase* AISystem;//[Offset: 0x128, Size: 0x0]
    AvoidanceManager* AvoidanceManager;//[Offset: 0x130, Size: 0x0]
    Level*[] Levels;//[Offset: 0x138, Size: 0x0]
    LevelCollection[] LevelCollections;//[Offset: 0x148, Size: 0x0]
    GameInstance* OwningGameInstance;//[Offset: 0x180, Size: 0x0]
    MaterialParameterCollectionInstance*[] ParameterCollectionInstances;//[Offset: 0x188, Size: 0x0]
    Canvas* CanvasForRenderingToTarget;//[Offset: 0x198, Size: 0x0]
    Canvas* CanvasForDrawMaterialToRenderTarget;//[Offset: 0x1a0, Size: 0x0]
    <ActorComponent*> ComponentsThatNeedPreEndOfFrameSync;//[Offset: 0x1f8, Size: 0x0]
    ActorComponent*[] ComponentsThatNeedEndOfFrameUpdate;//[Offset: 0x248, Size: 0x0]
    ActorComponent*[] ComponentsThatNeedEndOfFrameUpdate_OnGameThread;//[Offset: 0x258, Size: 0x0]
    WorldComposition* WorldComposition;//[Offset: 0x5d8, Size: 0x0]
    WorldPSCPool PSCPool;//[Offset: 0x668, Size: 0x0]
    WorldSettings* K2_GetWorldSettings();// 0x8f172d8
    void HandleTimelineScrubbed();// 0x8f1730c
 
--------------------------------
Class: Object
    void ExecuteUbergraph(int EntryPoint);// 0x67b5908
 
--------------------------------
Class: Level.Object
    World* OwningWorld;//[Offset: 0xb8, Size: 0x8800]
    Model* Model;//[Offset: 0xc0, Size: 0xff0088]
    ModelComponent*[] ModelComponents;//[Offset: 0xc8, Size: 0x0]
    LevelActorContainer* ActorCluster;//[Offset: 0xd8, Size: 0x8800]
    int NumTextureStreamingUnbuiltComponents;//[Offset: 0xe0, Size: 0x88ff]
    int NumTextureStreamingDirtyResources;//[Offset: 0xe4, Size: 0x8800]
    LevelScriptActor* LevelScriptActor;//[Offset: 0xe8, Size: 0x88]
    NavigationObjectBase* NavListStart;//[Offset: 0xf0, Size: 0xff0088]
    NavigationObjectBase* NavListEnd;//[Offset: 0xf8, Size: 0x88]
    NavigationDataChunk*[] NavDataChunks;//[Offset: 0x100, Size: 0x0]
    float LightmapTotalSize;//[Offset: 0x110, Size: 0x88ff]
    float ShadowmapTotalSize;//[Offset: 0x114, Size: 0x88]
    Vector[] StaticNavigableGeometry;//[Offset: 0x118, Size: 0x0]
    Guid[] StreamingTextureGuids;//[Offset: 0x128, Size: 0x0]
    Guid LevelBuildDataId;//[Offset: 0x1d0, Size: 0xff0088]
    MapBuildDataRegistry* MapBuildData;//[Offset: 0x1e0, Size: 0xff88]
    IntVector LightBuildLevelOffset;//[Offset: 0x1e8, Size: 0xff88]
    bool bIsLightingScenario;//(ByteOffset: 0, ByteMask: 0, FieldMask: 0)[Offset: 0x1f4, Size: 0x8800ff]
    bool bTextureStreamingRotationChanged;//(ByteOffset: 0, ByteMask: 0, FieldMask: 0)[Offset: 0x1f4, Size: 0x880000]
    bool bStaticComponentsRegisteredInStreamingManager;//(ByteOffset: 0, ByteMask: 0, FieldMask: 0)[Offset: 0x1f4, Size: 0x8800ff]
    bool bIsVisible;//(ByteOffset: 0, ByteMask: 0, FieldMask: 0)[Offset: 0x1f4, Size: 0xff0088]
    WorldSettings* WorldSettings;//[Offset: 0x258, Size: 0xff88ff]
    AssetUserData*[] AssetUserData;//[Offset: 0x268, Size: 0x0]
    ReplicatedStaticActorDestructionInfo[] DestroyedReplicatedStaticActors;//[Offset: 0x288, Size: 0x0]
 
--------------------------------
Class: Model.Object
 
--------------------------------
Class: ModelComponent.PrimitiveComponent.SceneComponent.ActorComponent.Object
    BodySetup* ModelBodySetup;//[Offset: 0x450, Size: 0x0]
 
...

4. dump的Objects.txt部分效果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
[0x0]:
Name: /Script/CoreUObject
Class: Package
ObjectPtr: 0x715fc731c0
ClassPtr: 0x71c61c8080
 
[0x2]:
Name: /Script/CoreUObject
Class: None
ObjectPtr: 0xcdcdcdcd000003ea
ClassPtr: 0xcdcdcdcd00000402
 
[0x3]:
Name: /Script/CoreUObject
Class: None
ObjectPtr: 0x40000000
ClassPtr: 0x40000018
 
[0x4]:
Name: NetDriver
Class: Class
ObjectPtr: 0x719e6c5b00
ClassPtr: 0x71c61c8800
 
[0x7]:
Name: NetDriver
Class: None
ObjectPtr: 0x42000000
ClassPtr: 0x42000018
 
[0x8]:
Name: /Script/OnlineSubsystemSeasun
Class: Package
ObjectPtr: 0x715fc73080
ClassPtr: 0x71c61c8080
 
[0xb]:
Name: /Script/OnlineSubsystemSeasun
Class: None
ObjectPtr: 0x40000000
ClassPtr: 0x40000018
 
...

reference

  1. 某火热区块链游戏(mir4)的一次通信协议分析
  2. UE4引擎学习与寻找GName和GWorld

Attention: 本文仅供参考和练习,不包含任何商业信息。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-5-27 17:46 被descosmos编辑 ,原因: 更新
收藏
免费 5
支持
分享
最新回复 (9)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
  int NumTextureStreamingUnbuiltComponents;//[Offset: 0xe0, Size: 0x88ff]
    int NumTextureStreamingDirtyResources;//[Offset: 0xe4, Size: 0x8800]
    LevelScriptActor* LevelScriptActor;//[Offset: 0xe8, Size: 0x88]
哈哈 你这明显读Size的偏移有问题吧
2023-2-14 13:38
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
2023-2-16 11:04
0
雪    币: 235
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
万里星河 [em_38]
??
2023-3-6 19:07
0
雪    币: 235
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
sanqiu int NumTextureStreamingUnbuiltComponents;//[Offset: 0xe0, Size: 0x88ff] int NumTextureStreami ...
没有关注Size,这个计算逻辑是在fork的原始库那儿,代码逻辑都没有变,具体参考原始库。  我只是做了一些字段的修正,让这个工具能在我的这个上下文工作。 如果你有需要这个Size字段,也可以去修正一下。
2023-3-6 19:13
0
雪    币: 36
活跃值: (1061)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
mark
2023-4-6 10:08
0
雪    币: 1223
活跃值: (4707)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
所以你找的东西都不在导出表里的时候呢?
2023-4-11 01:24
0
雪    币: 235
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
R0g 所以你找的东西都不在导出表里的时候呢?
那就得通过二进制特征来找了。
2023-4-13 12:36
0
雪    币: 107
活跃值: (134)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
来个联系方式
2023-5-20 02:59
0
雪    币: 235
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
mb_xmmjvkmd 来个联系方式
最后于 2023-7-25 16:20 被descosmos编辑 ,原因:
2023-5-31 18:57
0
游客
登录 | 注册 方可回帖
返回
//