【Unity学习笔记】MonoBehavior的读取
LC_ilmlp
编辑于 2022年09月24日 02:16

前言:属于是困扰了好一阵子的问题了,另外大概也是给接下来一篇的思路作准备


第一节:什么是MonoBehavior?为什么要读取它?

以我比较熟悉的逆向方面作为切入点,当我们用AssetStudio加载Assetbundle时,可能会看到一些类型名为MonoBehavior的东西

这里面定义了Unity游戏中每个物体组件的对应脚本的各种参数信息,比如上图所示的MonoBehavior,表示的就是目标物体包含的资源情况。

如果用Unity来举例的话,上述脚本对应的是如下效果

相关项目:

如果Unity能读取到这部分的信息的话,对于还原游戏来说会轻松不止一点半点。

那么就马上来试试吧!

第二节:读取AssetBundle

还是以我比较熟悉的马娘模型来举例,目标是获取到重炮的身体模型的MonoBehavior

同样是名为AssetHolder的脚本

那么,按着之前的经验

先将AB包中的模型加载进场景

然后查看MonoBehavior的情况

显示并没有找到关联的脚本,不过...关联的脚本会在呢?

第三节:脚本在哪里?

就我的理解来说,游戏再读取完AB包之后会在编译后的GameAssembly.dll中找到相关的函数进行处理

将这个DLL经过il2cppdumper解析之后,就可以查看函数大致的情况,比如下图就是AssetHolder相关的信息

好像是文件太大,我这边的VS解析就会出问题所以一堆波浪线

那么也就是说,如果Unity也能分析这个dll的话,大概就能让MonoBehavior的内容显示出来了吧...

嗯,沿着这个思路,然后我就卡住了。

第四节:MonoBehavior是怎么对应到脚本的?

接下来的内容特别感谢UmaViewer提供的方法:https://github.com/katboi01/UmaViewer

Unity分析DLL计划大失败,还是换个路子吧。

就我的理解来说,MonoBehavior就是要输入进目标脚本里的各种参数,那么是如何记录其对应的脚本的信息的呢?我们再打开AssetStudio观察一下

重点关注这里

这边定义的就是该MonoBehavior对应的脚本的位置信息(PathID)了,不过在左边的PathID项并没有发现这个ID...

其实这个PathID是有的,因为AS并没有显示而已,那么就换个工具吧

接下来使用的是UABE:https://github.com/SeriousCache/UABE

读取目标文件

找到对应的pathID

是一个类型名为MonoScript的东西,我们可以通过右边的ViewData查看其数据情况

哈希值暂时不知道有什么用,所以忽略

可以看到里面有用的数据大概就是AssemblyName(程序集名称),Namespace(命名空间),以及ClassName(类名),如果说MonoBehavior所对应的就是这东西的话,那么游戏也就是通过这些数据来找到目标的。

虽然Unity无法分析dll,但有没有办法伪造出一个对应的[AssemblyName(程序集名称),Namespace(命名空间),以及ClassName(类名)],让MonoBehavior能够找到目标呢?

第五节:程序集名称?

关于命名空间以及类名相信写过脚本的都知道是什么东西,关键问题在于怎么伪造AssemblyName,也就是程序集名称。

就目前的情况来分析的话,我们需要想办法模拟出叫umamusume.dll的东西。

不过刚好,Unity的asmdef提供了相应的功能。

https://docs.unity3d.com/Manual/cus-asmdef.html

通过一个叫做.asmdef的文件,我们就可以自定义脚本所在的程序集了

具体原理可以查看官网信息,接下来直接开始实战。

第六节:创建替代脚本

新建一个文件夹,在里面创建Assembly Definition

在属性栏内将其名称改成umamusume

这样,这个文件夹的空间内的脚本就都属于叫umamusume.dll的程序集里了

所以我们在这里新建一个脚本,命名为AssetHolder

打开编辑对应命名空间以及类名,保存

然后就可以重新载入AB包,看看有没有对应上这个脚本了

没有保存,也就是成功了,不过还得让它显示出MonoBehavior的相关信息才行。

第七节:编辑代替脚本

虽然可以自己对照着解析出来的MonoBehavior编写,不过一个简单的方法是,我们可以把dump后得到的信息给复制过来,如下图

将用到的Field都复制到代替脚本上

不过这个类的信息还会用到其相关的子类,所以根据dump文件将别的类的信息也复制过来

又引用到了新的东西,继续处理...

那么把东西都复制齐了之后,代码大概长这样

最后保存,重新载入AB包,查看情况

这样,AssetHolder里面的内容就可以显示出来了。

当然这方面也有一点小坑,比如说如果AssetHolder里面引用了别的MonoBehavior对象的话,必须先建立代替该MonoBehavior的脚本,然后里面的对象才会显示,否则就为空也就是什么都没有。

小结

这样就解决了加载AB包却丢失脚本,所以无法获得相关数据的问题了,当然之后也可以在代替脚本进一步加些代码来模拟游戏所达到的效果。嘛...虽然这一整篇的思路都是在看了UmaViewer的源码后发现"居然还可以这个样子!&#​34;后才弄明白的。