文章总结: 本文通过UnityIL2CPP手游Demo逆向实践,验证了Il2CppDumper提取的符号信息与原始C#源码结构高度一致,发现编译后函数内存布局顺序与源码书写顺序无关,并演示了字段偏移验证、Hook技术应用等逆向分析方法。 综合评分: 82 文章分类: 逆向分析,移动安全,安全工具
Unity IL2CPP手游逆向指南:最好的方式是开发与逆向结合
原创
凉子不会玩 凉子不会玩
零基础学逆向
2026年1月22日 10:47 四川
在小说阅读器读本章
去阅读
纯手工制作了一个游戏Demo(有点简陋(⊙^⊙)),用于学习和逆向分析Unity IL2CPP编译后的代码结构。
跑起来看看实际效果。
游戏采用回合制,玩家攻击会削减Boss血量,同时Boss也会立即反击,对玩家造成伤害。
观察为主,分析为辅
看一下游戏的lib下的so文件,这三个是Unity引擎Android平台的核心动态库:libunity.so、libmain.so、libil2cpp.so、burst_generated.so(burst_generated是unity性能优化支持库)
libmain.so 和 libunity.so 属于Unity运行时的基础支撑层,负责启动引导与引擎初始化;libil2cpp.so 包含了所有由C# 编译的游戏业务逻辑,是核心功能模块
直接分析libil2cpp.so
通过观察发现,使用Il2CppDumper从libil2cpp.so提取的符号信息(dump.cs),其结构、类名、方法名及字段布局与原始C# 源码保持高度一致。
| | | — | | 变量定义和函数定义顺序与源码一致,函数申明信息一致,如Update函数的private属性,并且生成了MyBoss构造函数 |
先看一下构造函数.ctor,显然是调用父类构造(遵循先构造基类、再构造派生类规则)
1) Start函数
偏移 0x28 确为 MyBoss 类中的 m_hp 字段。查看 dump.cs 中的类定义可证实,m_hp字段存储了Boss的生命值。
汇编实现与源码一致
2)Update函数
Update 函数内部按序调用了两个方法:IsDead() 与 UpdateHP_Viewer(),首先检查Boss是否死亡(IsDead),然后更新血量的UI显示(UpdateHP_Viewer)
3)IsDead函数
异常处理,如果this指针(即MyBoss对象)为NULL,则会抛出Il2CppExceptionWrapper异常。
设置MyPlayer.m_result_text的text属性(但是这里很奇怪的是这里调用的不是TMPro.TMP.Text的SetText函数)
调用SetActive函数禁用对象
m_hp_viewer.text
通过hook发现Text.text走的是UnityEngine.UI命名空间下Text类的set_text函数(text属性对应的set方法)
根据观察,函数在源码中的书写顺序与其编译后在代码段(.text节)中的存储顺序没有相关性。
我在C# 中定义的方法书写顺序为 Start、Update、AttackPlayer、UpdateHP_Viewer、IsDead。
而代码在内存中布局顺序是Start、Update、IsDead、UpdateHP_Viewer、AttackPlayer。
推测是编译器根据代码扫描顺序来布局的,最后Myboss类扫描完成没有发现用户没有定义构造函数,最后生成的默认构造函数
调整了一下结构(手动定义了构造函数并初始化血量),验证如下:
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:零基础学逆向 凉子不会玩 凉子不会玩《Unity IL2CPP手游逆向指南:最好的方式是开发与逆向结合》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论