返回顶部

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;
}
 
 
 
 
 
 
 
posted @   一身白_粉条  阅读(2993)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示