因为游戏采用了一种执行时解密技术,相关技术介绍文章:击败 Theia 反篡改完整脱壳方案(Arc Raiders PioneerGame.exe),当然内容仅提供思路,如果照搬原文的解法,其实已经很早失效了。后续考虑单开一章进行该技术的讲解。其实直接Dump就可以获取到我们所需的所有数据的。
在之前的文章中我们已经演示了通过字符串:aMissingtablein定位(定位到函数execGetDataTableRowFromName),原理这里我们就不再赘述。

那么我们这里就拿到了FProperty结构体的大小。
我们直接进入我们的TheSameLayout函数后他的内部会调用ArePropertiesTheSame函数,从中可以拿到我们的ElementSize。

因为ArePropertiesTheSame基本在所有UE引擎游戏中都是直接内联的,所以在ida中就是以下这种状态: 
我们对这一行按下tab键后获取ArrayDim和ElementSize的偏移:

我们这里并不能确定ElementSize是其中哪一个,只能通过注入后看ElementSize的值或者动态分析才能确定。当然肯定是两者其一。
这里的第一个if对应函数确实是我们FField结构体下Name的偏移,但是这里并不好直接复制解密算法,我们在其他位置找能直接复制的。
我们回到execGetDataTableRowFromName中依次定位->Generic_GetDataTableRowFromName->CopyScriptStruct
其中调用了:
那么MinAlignment出现两次,PropertiesSize出现一次对应IDA中:

当然这里存在默认构造函数,导致我们如果用UE源码跟的话篇幅会变大,所以我们用有pdb的对照观看:

execGetDataTableRowFromName->CopyScriptStruct->CopyCompleteValue_InContainer->ContainerPtrToValuePtr->ContainerVoidPtrToValuePtrInternal
对应我们的ida中的位置:

这样我们就获取到了Offset的解密算法:
在类TFieldIterator的构造函数中

对应ida的样式:

我们在UE引擎中可以定位到函数:FArrayProperty::ImportTextInnerItem
函数内有字符串:
text "UTF-16LE", '%s is a fixed-sized array of %i values. Additional '
我们在ida中定位:

可以看到UE引擎在没有魔改的情况下:
我们的FName是在+0x0的位置,但是这款游戏将结构进行了修改。我们只需要在源码内找到任何一个使用了FFieldClass.Name的位置即可定位偏移。
这里我们提供字符串:aFboolproperty text "UTF-16LE", 'FBoolProperty',可以定位到函数 FBoolProperty::StaticClass()或者FBoolProperty::Construct(),然后我们定位到函数FFieldClass::FFieldClass,FFieldClass的构造函数中使用到了FFieldClass.Name。 
这样我们就拿到了FFieldClass.Name的解密算法:

我们如果直接看伪代码发现所需参数v10并没有给它赋值.

但是函数内部却对这个变量进行了解引用取值,这时候我们看汇编代码即可。 
可以看到rcx=rsp+58h,那么我们模拟两次+0x10解引用,rsp+0x68解引用是我们这里的rax,rax=rsp+30,然后再+0x10解引用,讲就是我们的xmm0,也就是这里的参数其实就是我们的v9,我们外部移植时去掉多余的解引用即可。在ProcessEvent和StaticFindObject中用到了同样的方式,我们不管是通过注入调用还是使用vt断点断在主线程上下文调用,都需要构建相同的多层结构体进行传参即可。剩余的FName::ToString基本照抄即可,能最快还原。
定位方式依旧是之前文章提到的先定位ProcessEvent然后在内部找到UFunction::Invoke。该游戏对UFunction::Invoke进行了混淆: 
不过只要不是vmp我们静态逐句分析都能定位到我们要的数据,快速定位方式就是一个一个分支的查看2个参数的函数(针对该游戏分析了一年多依旧适用的方式,仅针对该游戏).

这个函数内部依旧混淆。我们只需要找到一个形同ProcessEvent调用特征的(函数指针,三个参数), 
我们查找v43的来源即可:

这样我们就轻松的定位到了Func的偏移0x150.
依旧是和以前文章一样的路径,通过aSTime3f3f3f定位函数UEnum::GetNameByValue。一次性就可以修复完UEnum结构体。在此不再赘述。
字符串:aFindremappedfi text "UTF-16LE", 'FindRemappedFieldImpl',0
定位到函数:FindRemappedFieldImpl<FField> 可以拿到SuperStruct的偏移

传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!