论坛首页 安全编程开发区 阅读主题

[原创]记录一次Unity加固的探索与实现

273 浏览 15 回复
#1 楼主 2026-06-01 21:09:11
正值某比赛出题,一道困难题不知道要怎么出才好,突然想起了il2cpp在安卓平台的加密,但是本人又不太会这方面,只好从学习一下il2cpp的原理并且尝试进行加固,本文记录我的出题过程。要直到如何保护libil2cpp.so首先需要知道这个so文件是在什么时候被载入的,根据il2cpp安卓端的启动流程,我们可以发现载入位置,其流程图如下:

在此处我们可以看到libunity.so通过dlopen加载libil2cpp.so光保护il2cpp.so大抵是不够的,很多加固方案肯定都会选择加密global-metadata.dat,接下来我们看看il2cpp.so中负责加载global-metadata.dat的代码位置吧,如下是加载metadata的流程图

源码分析可知加载global-metadata.dat的代码位置在具体代码如下:正如上文所提到的,加固global-metadata.dat主要是在,理论上修改了此处的代码之后,再写一个脚本去加密metadata再打包回去,就可以运行了,但是如果直接修改MetadataLoader.cpp会导致后面如果不需要加固的项目每一次编译都需要加密global-metadata.dat才能运行,这样的话岂不是非常的不方便自然,这里先说一下一个可能的解决方案,也是我在NSSCTF 4th中出过的一个pyinstaller打包项目加固的原理,我们可以通过设置一个标记,比如MHY0,我们再魔改MetadataLoader的时候通过识别是否存在MHY0这个标识符来确定是否需要解密,这样就不会影响后续打包的项目直接运行。当然,还有更加优秀的办法,我们看到如下GitHub项目:
ee5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6T1j5h3c8m8M7s2m8D9k6e0l9H3x3g2)9J5c8V1W2D9x3X3y4H3M7p5g2F1j5%4u0@1P5i4m8@1我们在Unity Hub编写完主体代码之后就可以开始考虑加固了,接下来讲述一下Il2cppEncrtypt 这个项目构建时加固的原理。Unity有一个很有意思的机制叫做Editor Scripting (Unity 编辑器扩展系统)暨所有放在 Assets/Editor/ 或任何以 Editor 命名的文件夹里的脚本,都会被编译进一个 编辑器专用的程序集(Editor Assembly),不会进入打包的游戏。与此同时,Unity还存在IPostprocessBuildWithReport这个接口有什么用呢,来看一下介绍IPostprocessBuildWithReport:Unity 的构建管线接口,OnPostprocessBuild 会在构建完成后自动被调用,参数是 BuildReport,包含构建结果、输出路径、平台等信息。(上面的字那么多看的怪枯燥的吧,让GPT生成了一张图,润色一下,看个乐呵


同时在这个接口的上下文中,我们可以获取到打包的路径,从而进行对global-metadata.dat的加固那么其实我们就可以扩展这个接口,并且重写OnPostprocessBuild,就可以实现在构建项目的时候一并完成对global-metadata.dat加固了。以下代码摘自Il2cppEncrtypt:诚然,如果我们直接使用Unity Hub编译一个可以直接运行的unity app的话默认使用的是Unity Editor中的代码,这个十分坑爹,也许是我不知道如何修改,反正最后试了很久也是没招了。导出Unity 项目之后通过Android Studio直接编译:导出项目在装好安卓的SDK之后,Build Setting界面,直接就可以看到导出了。导出之后在导出目录下可以看到两个包launcher和unityLibrary,其中unityLibrary主要加载il2cpp的内容同时我们检查一下Metadata是否加密
其位置在于可以看到这里原本应该是有意义的symbol,但此刻变成了乱码,即Metadata成功被加密接下来我们需要在项目中的loader写入解密代码,但你会发现Android studio 好像无法完美识别到关于il2cpp.so的代码,我们需要手动在中修改,这里需要注意的是确保和我们加密代码一致,不然会导致崩溃。如下代码中所示,主要的点也就是在拿到fileBuffer 之后做解密即可。至此成功的完成了Metadata的加密,但是这够吗,显然远远不够,我们准备开始下一步探索,加密libil2cpp.so在上文中提到了,libil2cpp.so 是被libunity.so加载的,但是我们在libUnity的编译脚本中可以看见似乎build.gradle是没有编译libunity.so的逻辑的,代码如下同时我们编译一次项目也会发现JniLibs的目录出现了时间差种种迹象也说明了libunity.so似乎不再我们可控范围内,经过搜索得知这个unity.so是核心引擎,属于Unity的闭源部分,因此我们没有办法通过修改unity.so来拦截il2cpp的加载从而实现动态解密。既然无法从代码层面进行修改ilbunity.so,那么根据上文提到的il2cpp.so被加载流程,最后加载libunity.so肯定是要走dlopen的,那么是不是说我们只需要在这之前注册一个hook,但dlopen打开的是libil2cpp的时候我们进行加密呢,接下来我们开始尝试这里的Hook有很多方法,Github已经开源了很多好用的Hook框架,我这里使用dobby hook
468K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6B7L8i4m8W2N6%4y4Q4x3V1k6p5L8$3u0T1P5g2)9K6c8Y4c8S2j5W2)9K6c8s2u0W2j5h3c8E0k6g2)9J5k6r3!0$3i4K6u0V1k6X3W2D9k6b7`.`.dobby hook编译好后使用非常的简单啊
我的建议是编译成静态链接库
libdobby.a,dobby.h
静态链接库编译之后会直接融入到编译出来的so中,这样不容易被看出来用了hook框架。如何在项目中使用dobby hook呢?首先将libdobby.a放到Jnilibs中,然后把dobby.h放到include中
接下来给一份我的Cmakelist.txt 自行理解一下,其中加入了对静态链接库符号的去除编译完dobby hook之后我们会发现导出来的项目是没有自己的cpp代码的,我们需要自己添加这一步Android Studio 会帮我们完成但是 到了这一步 ,如果用Unity Editor目录里的NDK的话,编译的时候会各种报错,这个就非常离谱了,应为路径中带空格,并且Java 版本 以及ndk版本种种问题,导致在这一步卡了很久,但最后还是成功的编译出来了,(也许你不会出现这个BUG)另外Cmake的版本

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288985.htm
#2 2026-06-01 21:09:11
小弟膜拜膜拜你~
#3 2026-06-01 21:09:11
进军unity
#4 2026-06-01 21:09:11
强如swdd~
#5 2026-06-01 21:09:11
学到啦!
#6 2026-06-01 21:09:11
好文章!!!感謝分享
#7 2026-06-01 21:09:11
学习一下
#8 2026-06-01 21:09:11
学习一下
#9 2026-06-01 21:09:11
tql
#10 2026-06-01 21:09:11
狠狠学习
#11 2026-06-01 21:09:11
好文
#12 2026-06-01 21:09:11
学习学习

最后于 2025-11-6 16:06
被fei3ei编辑

,原因:
#13 2026-06-01 21:09:11
样本在哪里
#14 2026-06-01 21:09:11
mb_vhwdzyqo


样本在哪里

强网拟态Mobile方向Just赛题
#15 2026-06-01 21:09:11
学习
#16 2026-06-01 21:09:11
很实用!从构建阶段就考虑防护很专业,自动化加密和内存防泄密的设计也很巧妙。详细的技术分析可以参考思维导图!


最后于 2025-11-11 10:52
被mb_cizqyhuh编辑

,原因:
‹ 上一页 1 2 下一页 ›

请登录后参与讨论

立即登录 注册账号