UE4 Gname Dump
对UE4 引擎进行分析
看到网上很少UE4资料(其实外网已经很多了),查阅了一些资料都是卖课程,看见好几套教程都在教逆向 BattleRoyaleTrainer 这个单机游戏,手法也都是一样的用CE
一直扫一直筛选,这虽然这是最简单暴力的方法, 个人认为也是最笨的~ 如果想彻底研究透 UE4 的SDK Dump 需要付出很多时间去研究。这种无脑用CE扫只会让你原地踏步
而且复杂点的游戏你也不一定能扫出来
既然这么多教程用BattleRoyaleTrainer来示范,我也用BattleRoyaleTrainer来测试,这次教大家如何dump Gname和Object
一、UE4是开源的 GitHub有项目,必须要学会结合项目来进行分析而且很多代码都需要使用到
二、知道两个重要的结构
UE4中有两个重要结构:Gname 和 Object 简单来说
Gname :是保存着UE4整个世界对象的名字
Object :是保存着世界的对象地址
#!!! 怎么查阅UE4代码 自己去官网看教程
GnameDump 需要参考的代码
ObjectDump 需要参考的代码
三、开始 Dump Gname
1、首先查看看看Gname 返回的是TNameEntryArray 这个类型 去看看UE4是怎么定义的

一个 TStaticIndirectArrayThreadSafeRead 类模板 它中间使用到了 一个FNameEntry的结构

2、接下来去看FNameEntry 源代码 NameTypes.h 中有一个结构 FNameEntry 这个结构存储这全局名称 想Dump 就得先了解这个结构
把这个结构写到自己代码中


2、看源代码中 TStaticIndirectArrayThreadSafeRead 这个类看看UE4 是怎么处理Gname的我们代码中就怎么处理
其中关键的是 GetItemPtr 这个函数,可以看到它返回类型是ElementType 在源代码在查看一下这个是什么

可以看到它是个类模板 还有看到这个类 TStaticIndirectArrayThreadSafeRead 它有定义了三个变量 Chunks NumElements NumChunks 也需要写到源代码中

还是一样 把观察到的结构写到代码中

注入

程序目录下生成了GnameDump


代码
struct FNameEntry
{
private:
int Index;
public:
FNameEntry* HashNext;
char AnsiName[1024];
char WideName[1024];
};
//模板
template<typename ElementType, int32_t MaxTotalElements, int32_t ElementsPerChunk>
class TStaticIndirectArrayThreadSafeRead
{
public:
ElementType const* const& GetById(int32_t index) const
{
return *GetItemPtr(index);
}
ElementType const* const* GetItemPtr(int32_t Index) const
{
int32_t ChunkIndex = Index / ElementsPerChunk;
int32_t WithinChunkIndex = Index % ElementsPerChunk;
ElementType** Chunk = Chunks[ChunkIndex];
return Chunk + WithinChunkIndex;
}
enum
{
ChunkTableSize = (MaxTotalElements + ElementsPerChunk - 1) / ElementsPerChunk
};
ElementType** Chunks[ChunkTableSize];
__int32 NumElements;
__int32 NumChunks;
};
using TNameEntryArray = TStaticIndirectArrayThreadSafeRead<FNameEntry, 2 * 1024 * 1024, 16384>;
TNameEntryArray* Names = NULL;
void NameDump()
{
FILE* Log = NULL;
fopen_s(&Log, "NameDump.txt", "w+");
for (DWORD64 i = 0x0; i < Names->NumElements; i++)
{
if (!Names->GetById(i)) { continue; }
fprintf(Log, "Name[%06i] %s\n", i, Names->GetById(i)->AnsiName);
}
fclose(Log);
}
void Init()
{
DWORD_PTR BaseAddress = (DWORD_PTR)GetModuleHandle(NULL);
Names = *reinterpret_cast<TNameEntryArray**>(BaseAddress + 0x294C290);
std::cout << "Names: " << Names << std::endl;
NameDump();
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Init, hModule, 0, NULL);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架