ue4游戏逆向之GName内存解析(4.23版本以下)

ue4游戏中的所有对象名称都保存在GName中,4.23版本以下的GName解析与高版本的不同。

解析GName

4.23版本以下可以通过FName::GNames()获取到GName指针,对应的GName指针就是static TNameEntryArray* Names,利用ue4Dumper时输入的GName就是这个静态指针变量。

TNameEntryArray类型是通过类模板TStaticIndirectArrayThreadSafeRead定义的,实际TNameEntryArray就相当于一个[2 * 1024 * 1024]大小的数组,数组的每一个元素又指向一个新的数组FNameEntry* [0x4000]

TNameEntryArray类型进行简化后如下图所示。

其中类模板TStaticIndirectArrayThreadSafeRead中定义了重载运算符[]完成元素的索引

那么名称的索引保存在何处呢,看一下FName::GetComparisonNameEntry()函数,其通过调用GetComparisonIndex()函数获取FName的成员变量ComparisonIndex,这个就是名称的索引。

遍历所有的Actor名称

UE4游戏逆向时可以通过GWorld->GameInstance->LocalPlayer->PlayerController->AcknowledgedPawn获取控制角色的Actor,也可以通过GWorld->Level->Actors获取Actor数组,然后再通过Actor的名称过滤出控制角色和敌人。

32位ue4而言Level的偏移为GWorld + 0x20

Actors的偏移为Level + 0x70

AActor的基类为UObject类,继承关系为AActor->UObject->UObjectBaseUtility->UObjectBase,对应的FName就是UObjectBase类的NamePrivate,对应的偏移为Actor + 0x10,而且FName类的第一个成员就是ComparisonIndex名称索引,所以名称索引的偏移也是Actor + 0x10

frida脚本遍历ue4的actors数组并获取对应的名称。

function hook_ue4(){
    var libUE4_module = Module.findBaseAddress("libUE4.so")
    console.log("libUE4_module is :", libUE4_module)

    var GWorld_Offset = 0x4924570
    var GName_Offset = 0x4877034

    var GWorld = libUE4_module.add(GWorld_Offset).readPointer()
   
    var Level_Offset = 0x20
    var Level = GWorld.add(Level_Offset).readPointer()
    console.log("Level :", Level)

    var Actors_Offset = 0x70
    var Actors = Level.add(Actors_Offset).readPointer()
    console.log("Actors Array :", Actors)

    var Actors_Num = Level.add(Actors_Offset).add(4).readU32()
    console.log("Actors_num :", Actors_Num)

    var Actors_Max = Level.add(Actors_Offset).add(8).readU32()
    console.log("Actors_Max :", Actors_Max)

    for(var index = 0; index < Actors_Num; index++){
        var actor = Actors.add(index * 4).readPointer()
        //console.log("actor", actor)
        //通过角色actor获取其成员变量FName
        var FName_Offset = 0x10
        var FName = actor.add(FName_Offset);
        //console.log("FName", FName)

        //解析TNameEntryArray
        var ComparisonIndex = FName.add(0).readU32()
        var ChunkIndex = parseInt(ComparisonIndex / 0x4000) 
        var WithinChunkIndex = ComparisonIndex % 0x4000

        var TNameEntryArray = libUE4_module.add(GName_Offset).readPointer()
        var Chunks = TNameEntryArray
        var FNameEntry = Chunks.add(ChunkIndex * 4).readPointer().add(WithinChunkIndex * 4).readPointer();
        console.log("actor : ", actor, " ", FNameEntry.add(8).readCString() )
    }
}   

最后的结果如下,可以获取到控制角色actor的名称为FirstPersonCharacter_C

posted @ 2023-08-13 23:08  怎么可以吃突突  阅读(1581)  评论(0编辑  收藏  举报