首页
社区
课程
招聘
[原创] XYCTF两道Unity IL2CPP题的出题思路与题解
发表于: 2024-4-28 23:35 13398

[原创] XYCTF两道Unity IL2CPP题的出题思路与题解

2024-4-28 23:35
13398

在这次的“新生赛”上出了两道unity il2cpp逆向的题,没有设计游戏内容,只有一个check,单纯的考察il2cpp逆向的知识。因为考虑了是新生赛,所以check部分没有设计的很复杂,并且比赛时长接近一个月,所以目的就是让新生们通过搜索资料学习来解出这两题,并且对游戏引擎逆向有一些了解和经验。事实证明有很多新人师傅们做到了,这里也夸夸师傅们太强了哈哈。

因为看到ez unity让大家坐牢太久了,所以连夜又赶了一个简单版本的出来
这题没有对il2cpp部分做任何魔改,单纯为了压缩题目文件,所以加了个upx

本题属于游戏引擎逆向,引擎为unity,并使用il2cpp打包
如果熟悉il2cpp的话,可以知道他把C#中的类名、方法名、属性名、字符串等地址信息记录在global-metadata.dat文件中,程序启动时会按需从中读取。
这里我们可以使用Il2CppDumper来静态dump

学会检索资料和使用工具,更重要的是在用之前多阅读一下工具的文档,就不会有一些奇奇怪怪的问题了
比如有问我为什么dump后的dll里没有源码,首先在README里有说明,其次再去理解一下什么是IL to CPP
还有问我为什么找不到libil2cpp.so的,这是Windows呀,肯定不会有so嘛

出这题的时候思考了很久,单纯的加密global-metadata.dat文件直接内存中dump即可拿到解密后的文件,感觉有点过于简单,所以考虑直接修改Il2CPP的东西了。但是我尝试了直接修改libil2cpp的源码,结果就是要么编译失败,要么游戏运行直接崩了,不确定具体是什么问题
最后的方案是去分析了一下build的部分,修改了sanity,然后在Il2cppGlobalMetadataHeader中间插入了一个magic(第一张图里忘记写了,应该还有一个list.Add()的),但貌似这样会导致最后一个成员被挤掉了,但是不影响游戏正常运行我也就没管了,有大佬会这方面的还请提提意见Orz
图片描述
图片描述

首先这题对global-metadata.dat的结构做了一些特殊修改,所以工具是无法直接使用的
这里有两种做法,一个是逆向修复结构(力气活),然后 Il2cppDumper->ida脚本恢复符号信息->找到关键方法->AES+BASE64解密
理论上这样做会很耗时耗力,但是这题我没有对结构做很复杂的魔改,所以这样解也在预期解内
这里简单讲讲另一种做法,Runtime下调用 il2cpp api,原理可以自行了解一下,这里直接使用 frida-il2cpp-bridge来解决了

注入,随便输点击一下按钮,就得到密文了 pNufkEIU9dHjKXYXWiFyrthHYFEfqJAWcPM/t8/zX1w=

很轻松就拿到了key和iv key = "a216d5d34c2723f5", iv = "9f68268f755b1363"

再次祭出我们万能的厨子
图片描述

这题的解题方法应该是很开放性的,这里贴一下看到的选手的一些解题方法,基本上都是预期到的解法,不过我是真没想到有人bindiff...还得是ctfer哈哈

小白的第一次出题,最后看到题目解出数量也在预期内,也算是没有失误哈哈,如果有更好的建议还请各位师傅们尽管提!

import "frida-il2cpp-bridge";
 
Il2Cpp.perform(() => {
    console.log(Il2Cpp.unityVersion);
 
    Il2Cpp.dump("dump.cs", "./")
});
import "frida-il2cpp-bridge";
 
Il2Cpp.perform(() => {
    console.log(Il2Cpp.unityVersion);
 
    Il2Cpp.dump("dump.cs", "./")
});
// Assembly-CSharp
class Check : UnityEngine.MonoBehaviour
{
    System.Void Start(); // 0x0027d670
    System.Void Update(); // 0x0027d670
    System.Void OnClick(); // 0x0027d4e0
    System.Boolean CheckFlag(System.String input); // 0x0027d460
    static System.String AESEncrypt(System.String text, System.String key, System.String iv); // 0x0027d200
    static System.String AESDecrypt(System.String text, System.Byte[] key, System.Byte[] iv); // 0x0027d000
    System.Void .ctor(); // 0x0027d680
}
// Assembly-CSharp
class Check : UnityEngine.MonoBehaviour
{
    System.Void Start(); // 0x0027d670
    System.Void Update(); // 0x0027d670
    System.Void OnClick(); // 0x0027d4e0
    System.Boolean CheckFlag(System.String input); // 0x0027d460
    static System.String AESEncrypt(System.String text, System.String key, System.String iv); // 0x0027d200
    static System.String AESDecrypt(System.String text, System.Byte[] key, System.Byte[] iv); // 0x0027d000
    System.Void .ctor(); // 0x0027d680
}
import "frida-il2cpp-bridge";
 
Il2Cpp.perform(() => {
    console.log(Il2Cpp.unityVersion);
 
    const String = Il2Cpp.corlib.class("System.String");
    Il2Cpp.trace(true).classes(String).and().attach();
});
import "frida-il2cpp-bridge";
 
Il2Cpp.perform(() => {
    console.log(Il2Cpp.unityVersion);
 
    const String = Il2Cpp.corlib.class("System.String");
    Il2Cpp.trace(true).classes(String).and().attach();
});
❯ python .\main.py 'ez unity.exe'
2022.3.17f1c1
il2cpp:
0x0077b6f0 ┌─System.String::FastAllocateString(length = 24)
0x0077b6f0 └─System.String::FastAllocateString = ""       
 
il2cpp:
0x0077afd0 ┌─System.String::op_Equality(a = "arpEeXJzJ5Fh4j+2tx6fIw==", b = "pNufkEIU9dHjKXYXWiFyrthHYFEfqJAWcPM/t8/zX1w=")
0x0077afd0 └─System.String::op_Equality = false
 
il2cpp:
0x0077afd0 ┌─System.String::op_Equality(a = "Wrong!", b = "Wrong!")
0x0077afd0 └─System.String::op_Equality = true
❯ python .\main.py 'ez unity.exe'
2022.3.17f1c1
il2cpp:
0x0077b6f0 ┌─System.String::FastAllocateString(length = 24)
0x0077b6f0 └─System.String::FastAllocateString = ""       
 
il2cpp:
0x0077afd0 ┌─System.String::op_Equality(a = "arpEeXJzJ5Fh4j+2tx6fIw==", b = "pNufkEIU9dHjKXYXWiFyrthHYFEfqJAWcPM/t8/zX1w=")
0x0077afd0 └─System.String::op_Equality = false
 
il2cpp:
0x0077afd0 ┌─System.String::op_Equality(a = "Wrong!", b = "Wrong!")
0x0077afd0 └─System.String::op_Equality = true
import "frida-il2cpp-bridge";
 
Il2Cpp.perform(() => {
    console.log(Il2Cpp.unityVersion);
 
    const AssemblyCSharp = Il2Cpp.domain.assembly("Assembly-CSharp").image
 
    const Check = AssemblyCSharp.class("Check");
    Il2Cpp.trace(true).classes(Check).and().attach();
});
import "frida-il2cpp-bridge";

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-4-28 23:40 被TubituX编辑 ,原因: 修复一些错误
收藏
免费 11
支持
分享
最新回复 (6)
雪    币: 3573
活跃值: (31026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-4-29 09:52
1
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
到哪里看 选手的解题
2024-5-8 09:35
0
雪    币: 2274
活跃值: (2036)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
mb_dvaiomvi 到哪里看 选手的解题
他们应该有发博客的,可以去搜一下看看
2024-5-9 17:52
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
作为第一次来看雪的小白,弱弱的问一句,题目里的GameAssembly.dll和global-metadata在哪里下载啊?
2024-6-11 13:04
0
雪    币: 2274
活跃值: (2036)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
6

1

最后于 2024-6-11 16:09 被TubituX编辑 ,原因:
2024-6-11 16:08
0
雪    币: 2274
活跃值: (2036)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
7
mb_efeveydv 作为第一次来看雪的小白,弱弱的问一句,题目里的GameAssembly.dll和global-metadata在哪里下载啊?

这是两题的附件

https://www.lanzouw.com/iF6VX21k8j2d

https://www.lanzouw.com/iEfqN21k8isd


2024-6-11 16:09
0
游客
登录 | 注册 方可回帖
返回
//