Unity的et热更新分析和补丁

admin 2024年4月22日02:59:34评论3 views字数 2685阅读8分57秒阅读模式


前言

unity项目,市面上多数都是c#通过il2cpp转换的代码,核心逻辑都在libil2cpp.so(安卓)或者主程序中(ios)。et框架的核心代码并没有经过il2cpp,而是跑在ilruntime上,主包并不包含核心逻辑。核心逻辑是首次运行下发,然后动态加载的。这里想介绍并记录下ilruntime上的反射来获取游戏数据,并调用热更新中的代码的方式。


热更新代码保存方式

1、以安卓为例,在sdcard上找到热更新后的目录,然后找到code.untiy3d,这个便是核心模块。头部0x120长度的内容删掉,然后就能用assetbundle打开了。
内容如下:
Unity的et热更新分析和补丁
Unity的et热更新分析和补丁
2、将这些asset直接到处,就能看到hotfix.dll的c#代码,也是游戏的核心代码。核心代码不在Assembly-CSharp中。


patch方案和反射

1、替换二进制文件,直接打patch:使用dnspy直接修改hotfix.dll,然后保存。在游戏loadasseembly的时候,将内容替换成修改后的hotfix.dll,这种方式实践后一加载就挂,根本不能用。
加载loadassembly的代码:
Unity的et热更新分析和补丁
Unity的et热更新分析和补丁
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部分官方文档内容如下:
Unity的et热更新分析和补丁
3.1 翻译:appdomain.LoadedTypes["TypeName"]这句的反射获取方式。首先获取ilruntime的appdomain,经过研究et框架的,找到hotfix这个类,它对象的0x10偏移处就是appdomain。
Unity的et热更新分析和补丁
Unity的et热更新分析和补丁
Unity的et热更新分析和补丁
得到appdomain后,然后它获取它的成员LoadedTypes(是个字典,反射的话,是在不好解析,直接解析内存数据,也不会解析。翻看ilruntime源码,准备放弃的时候。在ida函数中到一个函数ILRuntime_Runtime_Enviorment_AppDomain__GetType,frida试了下,传递类型,返回的正好是itype,也就是上边这句appdomain.LoadedTypes["TypeName"]效果一致)。
Unity的et热更新分析和补丁
Type type = t.ReflectionType(官方文档未更新,写成了ReflectedType)这句比较好翻译,直接在ida中找到了对应的函数ILRuntime_CLR_TypeSystem_ILType__get_ReflectionType。同样的,找到t.GetField("xxx"),这句,也能找到到对应的ida函数ILRuntime_Reflection_ILRuntimeFieldInfo__GetValue,还有静态成员(ILRuntime_Reflection_ILRuntimeFieldInfo__GetValue),property(System_Type__GetProperty_40653988)成员,方法(System_Type__GetMethod_40652536),都能找到一个函数与c#的语句对应。
最后,就是调用函数。官方文档给出了两种反射调用热更新模块中的函数的方法。我使用的的是appdomain.invoke(同样的在ida中找到invoke的实现函数ILRuntime_Runtime_Enviorment_AppDomain__Invoke)的方法。
Unity的et热更新分析和补丁
Unity的et热更新分析和补丁
上图中的this,就是我们之前获取的appdomain,type就是c#的string类型(可以用过il2cpp_string_new来创建),method就是方法名,instance就是对象被反射调用的对象指针(静态函数的话,就穿null,其它的话,就通过反射constructor来构造,多数都是另一个类的静态成员)。
System_object_array就是函数参数。这个构造方法,经过我不断的尝试,可以通过il2cpp_new_array_special来创建,并设置。最后一个参数传null。创建并构造system_object_array的代码如下:
Unity的et热更新分析和补丁
Unity的et热更新分析和补丁
经过上边的处理,调用ilruntime中的指定类的指定方法就可以了。剩下的就是选择,你要调用哪些c#函数。


hook抓包

1、安卓,这个比较好处理,直接用dobby的hook就可以。et框架的代码是下沉到il2cpp中了。我想截取游戏所有的收发包,经过分析学习et框架,找到四个函数能够抓取http和tcp的所有代码。
下图依次是抓取tcp收包、tcp发包、http发包和http收包。选择这四个hook点的原因是,现有市面框架,无法hook到热更新中的c#函数。只能被迫找il2cpp中的函数,恰好被我找到这四个函数了。
Unity的et热更新分析和补丁
2、ios。ios上的非越狱,是不太好hook的,新申请的内存设置无法可执行。越狱下跑hook正常,非越狱直接挂壁。但是,经过我的搜索,dobby作者,五年前还在更新一个machostaticpatcher的代码(现在删了不知何故)。我试了下,能打静态patch,patch也能在非越狱手机上,加签名来跑了。


总结

主要就是反射采集游戏数据,抓包分析游戏数据。我想记录下做过的事情,也希望对分析unity热更新的后来者有所帮助。

Unity的et热更新分析和补丁

看雪ID:wuaiwu

https://bbs.kanxue.com/user-home-213417.htm

*本文为看雪论坛优秀文章,由 wuaiwu 原创,转载请注明来自看雪社区
Unity的et热更新分析和补丁

# 

原文始发于微信公众号(看雪学苑):Unity的et热更新分析和补丁

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月22日02:59:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Unity的et热更新分析和补丁https://cn-sec.com/archives/2632003.html

发表评论

匿名网友 填写信息