1y ago · Sep 4, 2024 4:30 PM
Here is a standalone, lightweight C++ implementation to read strings directly from Unreal Engine's FNamePool using only the global FNamePool base address:
Usage Example:
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: