Home / Forums / Resolving Strings from FNamePool in UE 4.23+ and UE 5 (C++ Implementation)

UnreliableCode Community

Developer Research, Reverse Engineering & Coding Community

Source

Resolving Strings from FNamePool in UE 4.23+ and UE 5 (C++ Implementation)

DarkLogic
Game Logic & SDK Developer
MEMBER
Rep: 180
Join Date: Jun 2024
Posts: 28
Thanks: 41
1y ago · Sep 4, 2024 4:30 PM
#1
Here is a standalone, lightweight C++ implementation to read strings directly from Unreal Engine's FNamePool using only the global FNamePool base address:

CPP
#include <windows.h>
#include <string>
#include <iostream>

struct FNameEntryHeader {
    uint16_t bIsWide : 1;
    uint16_t Len : 15;
};

// Global FNamePool Address (Resolved via pattern scan or RVA)
uintptr_t g_FNamePoolAddress = 0;

std::string GetNameFromFName(uint32_t comparisonIndex) {
    if (!g_FNamePoolAddress) return "";

    // In UE4.23+ / UE5, FName comparisonIndex is split into:
    // BlockIndex (bits 16-31) and Offset (bits 0-15 * 2)
    uint32_t blockIndex = comparisonIndex >> 16;
    uint16_t blockOffset = static_cast<uint16_t>(comparisonIndex & 0xFFFF);

    // Read pointer to block from FNamePool.Blocks[blockIndex]
    uintptr_t blockPtrAddress = g_FNamePoolAddress + 0x10 + (blockIndex * sizeof(uintptr_t));
    uintptr_t blockAddress = *reinterpret_cast<uintptr_t*>(blockPtrAddress);
    if (!blockAddress) return "";

    // Entry location inside 64KB block (stride is 2 bytes or 4 bytes depending on align)
    uintptr_t entryAddress = blockAddress + (blockOffset * 2);
    auto header = *reinterpret_cast<FNameEntryHeader*>(entryAddress);

    if (header.Len == 0 || header.Len > 1024) return "";

    const char* namePtr = reinterpret_cast<const char*>(entryAddress + sizeof(FNameEntryHeader));
    return std::string(namePtr, header.Len);
}


Usage Example:
CPP
// Given any UObject:
uint32_t nameIndex = pObject->NamePrivate.ComparisonIndex;
std::string objectName = GetNameFromFName(nameIndex);
std::cout << "Object Name: " << objectName << std::endl; // e.g. "BP_PlayerCharacter_C_0"
DarkLogic | Virtual method tables & SDKs
The following users thanked DarkLogic for this post:
VectorByte
Graphics & DirectX Dev
VIP
Rep: 420
Join Date: Aug 2022
Posts: 39
Thanks: 115
1y ago · Sep 4, 2024 6:50 PM
#2
CODE
blockOffset * 2
vs
CODE
blockOffset * 4
depends on whether the build is compiled with
CODE
WITH_CASE_PRESERVING_NAME
. For 95% of shipping release games,
CODE
blockOffset * 2
(stride 2) is standard.
VectorByte | DirectX 11/12 Hooking & ImGui Overlays
Quote
Math is the language of game engines.
PEHeader
PE Format & Linker Tech
VIP
Rep: 350
Join Date: Jun 2023
Posts: 35
Thanks: 95
1y ago · Sep 5, 2024 10:20 AM
#3
Clean bit shifting logic! Having this in internal overlays makes displaying actor class names in ESP instantaneous without calling internal engine methods.
PEHeader | IMAGE_NT_HEADERS & Section Parsing