- 0.前言
- 1.准备
- 1.1 下载游戏《死寂(DeathlyStillness)》
- 1.2 下载UE源码
- 2.寻找GWorld
- 3.寻找GName
- 4.寻找GUObjectArray
- 5.开始Dump
- 5.结尾
0.前言
笔记(一)中我们了解了GWorld,GName和GUObjectArray是什么,也知道了想要使用UEDumper要获取到它们的偏移。
这次我们就以游戏《死寂(DeathlyStillness)》为例,利用源码中的特征字符串来寻找GWorld,GName和GUObjectArray,并使用UEDumper来Dump这个游戏的SDK。
1.准备
1.1 下载游戏《死寂(DeathlyStillness)》
从Steam下载完成后查看如下目录中的 xxx-Shipping.exe
右键属性查看UE版本为UE4.27
1.2 下载UE源码
下载UE源码需要先获取授权,具体流程可参考文章。
获取授权后就可以进入UE的代码仓库下载了。
原则上是应该下载对应版本的源码进行逆向,这里由于我没有找到4.27,所以我用最新版本5.4.4(4.23版本以上即可)分析,对于今天使用特征字符串的方法无影响。
2.寻找GWorld
GWorld定义在\UE_5.1\Engine\Source\Runtime\Engine\Private\World.cpp文件中。
我在UE源码工程中搜索"GWorld = nullptr",定位到函数FSeamlessTravelHandler::Tick中,查看如下位置代码:
其中字符串"SeamlessTravel FlushLevelStreaming"可作为特征
使用ida打开1.1中查看过的 xxx-Shipping.exe,搜索字符串"SeamlessTravel FlushLevelStreaming"
经过十几分钟的搜索,得到两个结果,直接查看上面这个代码里的。
F5查看伪代码,这里就是之前看过的UE源码
而GWorld是全局变量,源码中有两次源码赋值,使用这个特征在伪代码中可以找到:
那这个qword_144C1D800就是GWorld了,减去ida加载基址,偏移为0x144C1D800 - 0x140000000 = 0x4C1D800
3.寻找GName
GName也是用内存池保存,内存池FNamePool的构造函数会初始化一些Name,例如None,ByteProperty,IntProperty等,在内存中的结构是这样的:
同样的方法,在ida中搜索"ByteProperty",选择下面这个:
可以看到FNamePool的初始化代码:
再点击函数名称按X,跳转到此函数的任一引用处:
函数调用时传入的this指针就是GName了
GName偏移为0x144A99140 - 0x140000000 = 0x4A99140
4.寻找GUObjectArray
GUObjectArray在\UE_5.1\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectHash.cpp中定义。
同样找到GUObjectArray引用的地方,这里找的是int32 FEngineLoop::PreInitPostStartupScreen(const TCHAR* CmdLine)函数
特征字符串"CloseDisregardForGC"的下面就是GUObjectArray
在ida中搜索"CloseDisregardForGC",定位到源码相同代码处,this指针dword_144AD5480即为GUObjectArray
GUObjectArray偏移为0x144AD5480 - 0x140000000 = 0x4AD5480
5.开始Dump
打开UEDumper工程,在offsets.h中填入刚刚获取到的几个偏移。
再搜索UE_VERSION,转到定义,修改UE版本。
F5开始编译运行
填入项目名称,和xxx-Shipping.exe的PID。
依次点击Create,Find,Dump,dump成功后按需保存项目,不知道为何我这里只获取到了BasicType
然后在工程目录文件夹下可看到刚刚保存的内容。
5.结尾
今天通过最简单的方式去找了GWorld,GName和GUObjectArray,如果游戏隐藏了符号信息,那这个方法就不好使了。
dump虽然没有报错,但总感觉内容太少了,不知是哪里的问题,下次再换个游戏试试。
参考文章:https://www.cnblogs.com/revercc/p/17641855.html
https://blog.csdn.net/qq_43355637/article/details/127208395