-
-
[原创]unity的et热更新分析和补丁
-
发表于:
2024-3-21 15:35
11556
-
一、unity项目,市面上多数都是c#通过il2cpp转换的代码,核心逻辑都在libil2cpp.so(安卓)或者主程序中(ios)。et框架的核心代码并没有经过il2cpp,而是跑在ilruntime上,主包并不包含核心逻辑。核心逻辑是首次运行下发,然后动态加载的。这里想介绍并记录下ilruntime上的反射来获取游戏数据,并调用热更新中的代码的方式。
二、热更新代码保存方式
1、以安卓为例,在sdcard上找到热更新后的目录,然后找到code.untiy3d,这个便是核心模块。头部0x120长度的内容删掉,然后就能用assetbundle打开了。内容如下:
2、将这些asset直接到处,就能看到hotfix.dll的c#代码,也是游戏的核心代码。核心代码不在Assembly-CSharp中。
三、patch方案和反射
1、替换二进制文件,直接打patch:使用dnspy直接修改hotfix.dll,然后保存。在游戏loadasseembly的时候,将内容替换成修改后的hotfix.dll,这种方式实践后一加载就挂,根本不能用。加载loadassembly的代码
2、替换二进制,首先生成一个自己的c#的dll,使用ilrepack合并到hotfix.dll中,在hotfix的c#代码中,将特定函数的代码进行patch,并将这个特定函数的代码,写到自己的c#的dll中,这样就能无限扩充逻辑了,不受限原来函数的字节码长度。这样就能保证原来的特定函数,不会应该dnspy添加il字节码,超过特定函数的原本的长度。不过,这个仅仅是我的思路。实际操作,ilrepack合并完。loadassembly加载并替换的时候,就直接挂壁了。
3、ilruntime的反射。由于通过il2cpp的api,去获取assembly,再去获取image,这种方式压根不能获取热更新的模块,所以,也无法通过il2cpp的api去反射调用热更新中的代码。ilruntime中执行的assembly。根据ilruntime的官方文档,要先找到ilruntime的appdomain,然后找到loadedtypes。这个loadedtypes中存放了热更新的所有类的类型,然后才能获取到原本的relectiontype。ilruntime部分官方文档内容如下:
3.1 翻译:appdomain.LoadedTypes["TypeName"]这句的反射获取方式。首先获取ilruntime的appdomain,经过研究et框架的,找到hotfix这个类,它对象的0x10偏移处就是appdomain。
得到appdomain后,然后它获取它的成员LoadedTypes(是个字典,反射的话,是在不好解析,直接解析内存数据,也不会解析。翻看ilruntime源码,准备放弃的时候。在ida函数中到一个函数ILRuntime_Runtime_Enviorment_AppDomain__GetType,frida试了下,传递类型,返回的正好是itype,也就是上边这句appdomain.LoadedTypes["TypeName"]效果一致)。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!