-
-
UnrealEngine GName 分析
-
发表于: 2024-6-7 18:52 2559
-
UnrealEngine GName 分析
IDA分析GName:
在UnrealNames.cpp
中找到如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | static bool bNamePoolInitialized; alignas(FNamePool) static uint8 NamePoolData[ sizeof (FNamePool)]; // 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; } |
- 在
UnrealEngine5.x
的引擎版本中,GName
以全局变量static uint8 NamePoolData
的形式存在. - 被定义的
NamePoolData
会在环境中通过FNamePool::FNamePool()
初始化
我们跟随引用找到相应的FNamePool::FNamePool()
函数
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 | FNamePool::FNamePool() { for (FNamePoolShardBase& Shard : ComparisonShards) { Shard.Initialize(Entries); } #if WITH_CASE_PRESERVING_NAME for (FNamePoolShardBase& Shard : DisplayShards) { Shard.Initialize(Entries); } #endif // Register all hardcoded names #define REGISTER_NAME(num, name) ENameToEntry[num] = Store(FNameStringView(#name, FCStringAnsi::Strlen(#name))); #include "UObject/UnrealNames.inl" #undef REGISTER_NAME // Make reverse mapping LargestEnameUnstableId = 0; for (uint32 ENameIndex = 0; ENameIndex < (uint32)EName::MaxHardcodedNameIndex; ++ENameIndex) { if (ENameIndex == (uint32)NAME_None || ENameToEntry[ENameIndex]) { EntryToEName.Add(ENameToEntry[ENameIndex], (EName)ENameIndex); LargestEnameUnstableId = FMath::Max(LargestEnameUnstableId, ENameToEntry[ENameIndex].ToUnstableInt()); } } // Verify all ENames are unique if (NumAnsiEntries() != EntryToEName.Num()) { if (FPlatformMisc::IsDebuggerPresent()) { UE_DEBUG_BREAK(); } else { FPlatformMisc::PromptForRemoteDebugging( false ); FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT( "UnrealEd" , "DuplicatedHardcodedName" , "Duplicate hardcoded name" )); FPlatformMisc::RequestExit( false ); } } } |
- 有明显的明文字符串
DuplicatedHardcodedName
于是通过IDA搜索字符串
在IDA中搜索字符串
Name | Address |
---|---|
aDuplicatedhard | 00000001439ADA30 |
继续跟踪反汇编
1 2 3 4 5 6 7 8 9 10 11 12 13 | if ( v336 - v2 != *(_DWORD *)(a1 + 93000) - *(_DWORD *)(a1 + 93092) ) { v338 = sub_140F60170(v685, L "Duplicate hardcoded name" , L "UnrealEd" , L "DuplicatedHardcodedName" ); sub_141022D50(0i64, v338, 0i64); v339 = v686; if ( v686 && _InterlockedExchangeAdd(v686 + 2, 0xFFFFFFFF) == 1 ) { (**( void (__fastcall ***)( volatile signed __int32 *))v339)(v339); if ( _InterlockedExchangeAdd(v339 + 3, 0xFFFFFFFF) == 1 ) (*( void (__fastcall **)( volatile signed __int32 *, __int64 ))(*(_QWORD *)v339 + 8i64))(v339, 1i64); } sub_1410714B0(0i64); } |
- 这里伪代码很明显就是与上述代码相对应的部分
- 可以判断出来这就是构造函数,于是在IDA中改名为
void __fastcall FNamePool_FNamePool(__int64 a1)
使用IDA分析交叉引用
Direction | Type | Address | Text |
---|---|---|---|
Up | p | sub_141055510+D1 | call FNamePool_FNamePool |
Down | p | sub_141059000+50 | call FNamePool_FNamePool |
Down | p | sub_141059110+51 | call FNamePool_FNamePool |
Down | p | sub_141059EA0+42 | call FNamePool_FNamePool |
Down | p | sub_141059F60+42 | call FNamePool_FNamePool |
Down | p | sub_14105A7D0+4E | call FNamePool_FNamePool |
Down | p | sub_14105BBC0+20 | call FNamePool_FNamePool |
Down | p | sub_14105BC60+31 | call FNamePool_FNamePool |
Down | p | sub_14105BCC0+2F | call FNamePool_FNamePool |
Down | p | sub_14105BD50+38 | call FNamePool_FNamePool |
Down | p | sub_14105BDE0+38 | call FNamePool_FNamePool |
Down | p | sub_14105BE50+38 | call FNamePool_FNamePool |
Down | p | sub_14105C1A0+47 | call FNamePool_FNamePool |
Down | p | sub_14105D4F0+82 | call FNamePool_FNamePool |
Down | p | sub_14105F090+A1 | call FNamePool_FNamePool |
Down | p | sub_14105F390+11A | call FNamePool_FNamePool |
Down | p | sub_141062740+47 | call FNamePool_FNamePool |
Down | p | sub_141062740+A8 | call FNamePool_FNamePool |
Down | p | sub_1410628E0+51 | call FNamePool_FNamePool |
Down | p | sub_1410629D0+49 | call FNamePool_FNamePool |
Down | p | sub_141062AA0+47 | call FNamePool_FNamePool |
Down | o | .pdata:0000000144CEE0AC | RUNTIME_FUNCTION <rva FNamePool_FNamePool, rva algn_141058B15, \ |
- 很显然要继续分析的是第一个表项
这个函数就是完成NamePoolData初始化的函数
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 | _QWORD *__fastcall sub_141055510(_QWORD *a1, __int64 a2) { bool v2; // zf __int64 v3; // r8 __int64 v5; // rax unsigned int v6; // eax _QWORD *result; // rax RTL_SRWLOCK *v8; // rax unsigned int v9; // ecx __m128i v10; // [rsp+20h] [rbp-18h] BYREF char v11; // [rsp+40h] [rbp+8h] BYREF v2 = *(_BYTE *)(a2 + 4) == 0; v3 = a2 + 6; v10.m128i_i64[0] = a2 + 6; v5 = -1i64; if ( v2 ) { do ++v5; while ( *(_BYTE *)(v3 + v5) ); v10.m128i_i8[12] = 0; } else { do ++v5; while ( *(_WORD *)(v3 + 2 * v5) ); v10.m128i_i8[12] = 1; } v10.m128i_i32[2] = v5; if ( (unsigned int )_mm_cvtsi128_si32(_mm_srli_si128(v10, 8)) < 0x400 ) { if ( byte_144A3AA64 ) { v8 = &stru_144A56400; } else { FNamePool_FNamePool(( __int64 )&stru_144A56400); byte_144A3AA64 = 1; } v9 = *(_DWORD *)sub_1410624C0(v8, &v11, &v10); result = a1; *a1 = v9; } else { v10.m128i_i32[2] = 24; v10.m128i_i64[0] = ( __int64 ) "ERROR_NAME_SIZE_EXCEEDED" ; v6 = sub_1410552F0( "ERROR_NAME_SIZE_EXCEEDED" , &v10.m128i_u64[1]); sub_14105F340(a1, &v10, 1i64, v6); return a1; } return result; } |
FNamePool_FNamePool((__int64)&stru_144A56400)
完成了对NamePoolData
的初始化计算
0x144A56400-0x140000000=0x4A56400
得到GName
偏移为0x4A56400
,其中0x140000000
是所在模块基地址
CE分析GName
在CE中搜索字符串或特定字节数组
文本:
ByteProperty
字节数组:
1E 01 4E 6F 6E 65 10 03 42 79 74 65 50 72 6F 70 65 72 74 79 C0
跟踪搜到的地址
297DAB20000
得到地址
"DeathlyStillnessGame-Win64-Shipping.exe"+4A56410
计算
0x4A56410-0x10=0x4A56400
得到GName
偏移为0x4A56400
赞赏
他的文章
看原图
赞赏
雪币:
留言: