初探UE4引擎逆向
字数 934 2025-08-20 18:18:23

UE4引擎逆向分析:FName系统与GName加密算法实现

前言

本文基于UE4.27.2源码,详细分析虚幻引擎中的FName名称管理系统,并实现一个独立的GName加密算法。FName系统是UE4中高效的名称管理机制,用于快速查找和处理名称字符串。

一、FName系统核心结构分析

1.1 FName基本调用流程

// 获取对象名称的基本调用链
FString GetName() const {
    return GetFName().ToString();
}

FName GetFName() const {
    return NamePrivate;
}

1.2 关键数据结构

FName结构

class CORE_API FName {
public:
    FORCEINLINE FNameEntryId GetDisplayIndex() const {
        const FNameEntryId Index = GetDisplayIndexFast();
        checkName(IsWithinBounds(Index));
        return Index;
    }
    
    FORCEINLINE FNameEntryId GetDisplayIndexFast() const {
        #if WITH_CASE_PRESERVING_NAME
        return DisplayIndex;
        #else
        return ComparisonIndex;
        #endif
    }
};

FNameEntryId结构

struct FNameEntryId {
    FNameEntryId() : Value(0) {}
    
    uint32 ToUnstableInt() const {
        return Value;
    }
    
private:
    uint32 Value;
};

FNameEntryHandle结构

struct FNameEntryHandle {
    uint32 Block = 0;
    uint32 Offset = 0;
    
    FNameEntryHandle(uint32 InBlock, uint32 InOffset) 
        : Block(InBlock), Offset(InOffset) {}
        
    FNameEntryHandle(FNameEntryId Id)
        : Block(Id.ToUnstableInt() >> FNameBlockOffsetBits),
          Offset(Id.ToUnstableInt() & (FNameBlockOffsets - 1)) {}
};

1.3 FNamePool系统

static FNamePool& GetNamePool() {
    if (bNamePoolInitialized) {
        return *(FNamePool*)NamePoolData;
    }
    
    FNamePool* Singleton = new (NamePoolData) FNamePool;
    bNamePoolInitialized = true;
    return *Singleton;
}

FNamePool关键方法

class FNamePool {
public:
    FNameEntry& Resolve(FNameEntryHandle Handle) const {
        return Entries.Resolve(Handle);
    }
    
private:
    FNameEntryAllocator Entries;
    // 其他成员...
};

FNameEntryAllocator解析

class FNameEntryAllocator {
public:
    enum { Stride = alignof(FNameEntry) };
    enum { BlockSizeBytes = Stride * FNameBlockOffsets };
    
    FNameEntry& Resolve(FNameEntryHandle Handle) const {
        return *reinterpret_cast<FNameEntry*>(
            Blocks[Handle.Block] + Stride * Handle.Offset);
    }
};

1.4 FNameEntry结构

struct FNameEntry {
private:
    #if WITH_CASE_PRESERVING_NAME
    FNameEntryId ComparisonId;
    #endif
    
    FNameEntryHeader Header;
    union {
        ANSICHAR AnsiName[NAME_SIZE];
        WIDECHAR WideName[NAME_SIZE];
    };
};

二、GName加密算法逆向分析

2.1 关键加密点分析

加密算法核心位于FNameEntryHandle的构造过程中:

FNameEntryHandle(FNameEntryId Id)
    : Block(Id.ToUnstableInt() >> 16),
      Offset(Id.ToUnstableInt() & ((1 << 16) - 1)) {}

2.2 加密算法还原

完整解析流程:

FNameEntry& Resolve(FNameEntryHandle Handle) const {
    return *reinterpret_cast<FNameEntry*>(
        Blocks[ID >> 16] + 2 * (ID & ((1 << 16) - 1)));
}

2.3 定位GName/FNamePool

在IDA中定位FNamePool的步骤:

  1. 搜索字符串"ByteProperty"
  2. 定位到FNamePool::FNamePool()构造函数
  3. 查找交叉引用找到GetNamePool()函数
  4. 计算偏移量:程序偏移 = 地址 - 基地址(0x140000000)

三、反调试绕过方法

游戏常见的反调试检测:

FindWindow("WinDbgFrameClass", NULL);
FindWindow("OLLYDBG", NULL);

绕过方法:

  1. 在IDA中找到相关函数
  2. 将函数体替换为直接返回(ret)
  3. 应用修改

四、GName加密算法实现

4.1 核心数据结构实现

FString实现

class FString : public std::string {
public:
    using std::string::string;
    
    int32_t Len() const {
        return static_cast<int32_t>(this->length());
    }
};

FNameEntry实现

class FNameEntry {
public:
    static FString EncryptName(const FString& InName);
    static FString DecryptName(const FString& InName);
};

4.2 加密/解密算法实现

FString FNameEntry::EncryptName(const FString& InName) {
    FString EncryptedName = InName;
    for (int32_t i = 0; i < InName.Len(); ++i) {
        EncryptedName[i] = InName[i] + 1;
    }
    return EncryptedName;
}

FString FNameEntry::DecryptName(const FString& InName) {
    FString DecryptedName = InName;
    for (int32_t i = 0; i < InName.Len(); ++i) {
        DecryptedName[i] = InName[i] - 1;
    }
    return DecryptedName;
}

4.3 完整示例代码

#include <iostream>
#include "FName.h"

int main() {
    FString OriginalName = "ExampleName";
    FName Name(OriginalName);
    
    FString EncryptedName = FNameEntry::EncryptName(Name.ToString());
    FString DecryptedName = FNameEntry::DecryptName(EncryptedName);
    
    std::cout << "Original Name: " << OriginalName << std::endl;
    std::cout << "Encrypted Name: " << EncryptedName << std::endl;
    std::cout << "Decrypted Name: " << DecryptedName << std::endl;
    
    return 0;
}

五、关键点总结

  1. FName系统结构:理解FName、FNameEntry、FNamePool之间的关系
  2. 加密算法核心:掌握FNameEntryHandle的构造和解析过程
  3. 内存布局:了解UE4对象的内存布局和偏移计算
  4. 反调试绕过:识别常见反调试技术并实现绕过
  5. 算法实现:能够独立实现名称加密/解密功能

六、扩展应用

  1. Dump SDK:基于此技术可以实现完整的SDK导出工具
  2. 游戏安全:应用于反作弊系统和游戏数据保护
  3. 引擎扩展:作为理解UE4引擎内部机制的切入点

通过本教程,开发者可以深入理解UE4的名称管理系统,并掌握相关的逆向分析和加密算法实现技术。

UE4引擎逆向分析:FName系统与GName加密算法实现 前言 本文基于UE4.27.2源码,详细分析虚幻引擎中的FName名称管理系统,并实现一个独立的GName加密算法。FName系统是UE4中高效的名称管理机制,用于快速查找和处理名称字符串。 一、FName系统核心结构分析 1.1 FName基本调用流程 1.2 关键数据结构 FName结构 FNameEntryId结构 FNameEntryHandle结构 1.3 FNamePool系统 FNamePool关键方法 FNameEntryAllocator解析 1.4 FNameEntry结构 二、GName加密算法逆向分析 2.1 关键加密点分析 加密算法核心位于FNameEntryHandle的构造过程中: 2.2 加密算法还原 完整解析流程: 2.3 定位GName/FNamePool 在IDA中定位FNamePool的步骤: 搜索字符串"ByteProperty" 定位到FNamePool::FNamePool()构造函数 查找交叉引用找到GetNamePool()函数 计算偏移量:程序偏移 = 地址 - 基地址(0x140000000) 三、反调试绕过方法 游戏常见的反调试检测: 绕过方法: 在IDA中找到相关函数 将函数体替换为直接返回(ret) 应用修改 四、GName加密算法实现 4.1 核心数据结构实现 FString实现 FNameEntry实现 4.2 加密/解密算法实现 4.3 完整示例代码 五、关键点总结 FName系统结构 :理解FName、FNameEntry、FNamePool之间的关系 加密算法核心 :掌握FNameEntryHandle的构造和解析过程 内存布局 :了解UE4对象的内存布局和偏移计算 反调试绕过 :识别常见反调试技术并实现绕过 算法实现 :能够独立实现名称加密/解密功能 六、扩展应用 Dump SDK :基于此技术可以实现完整的SDK导出工具 游戏安全 :应用于反作弊系统和游戏数据保护 引擎扩展 :作为理解UE4引擎内部机制的切入点 通过本教程,开发者可以深入理解UE4的名称管理系统,并掌握相关的逆向分析和加密算法实现技术。