前言
UnityCN
UnityCN是Unity游戏引擎中国区的官方加密,对于其加密实现本文暂且不表,因为已经有很多现成的开源工具用于UnityCN的解包,可以自行查看其解密源代码理解加密流程
本文主要解决如何拿到UnityCN加密Key
判断是否是UnityCN加密
需要用到Il2CppDumper来dump出libil2cpp.so文件相关内容(libil2cpp.so文件在 lib/{cpu架构} 目录下),如何dump libil2cpp.so项目文档中已经详细列出,此处不再赘述。
在dump出的文件中找到dump.cs,使用notepad打开,搜索SetAssetBundleDecryptKey,如果能搜到说明该游戏极大概率(99.99%)是使用UnityCN加密的
1
2
|
// RVA: 0x269C2CC Offset: 0x269C2CC VA: 0x269C2CC
public static void SetAssetBundleDecryptKey(string password) { }
|
SetAssetBundleDecryptKey方法其中的String类型的password参数就是我们的目标
当然也有大佬能一眼看出(反正我是不能),通过直接观察ab头,参考AXiX大佬的:UnityCN的加密与解密
工具准备(环境安装)
硬件环境:
- Windows电脑一台
- Root手机一台(我使用的小米6X)(不要用模拟器,不要用模拟器!!!)
- USB数据线
软件环境:
- Python
- VSCode
- QTScrcpy(用于在电脑上操纵手机,非必须)
- Nodejs(方法1)
Python安装frida
CMD命令:
1
2
|
pip install frida
pip install frida-tools
|
安装完成后输入如下命令,获取frida版本
1
2
|
C:\Users\430>frida --version
16.4.10
|
Windows安装ADB
可以在官方网站下载压缩包:Android SDK Platform-Tools下载完毕后解压,配置环境变量:系统变量->Path->新建环境变量->adb.exe所在目录。环境变量配置完毕后再CMD中输入adb –version命令查看安装信息,如果有正常版本输出则安装成功:
1
2
3
4
|
C:\Users\430>adb --version
Android Debug Bridge version 1.0.41
Version 33.0.1-8253317
Installed as ......\adb.exe
|
在手机上启动frida-server
首先要确定你手机的CPU架构,在手机中 开发者选项 找到 USB调试 选项,可以把相关功能都打开,这样就能畅快使用啦

然后在Windows中打开CMD:
1
2
3
4
5
6
|
C:\Users\430>adb devices
List of devices attached
485dda7 device(说明已经连接上了)
C:\Users\430>adb shell getprop ro.product.cpu.abi
arm64-v8a(手机CPU架构为arm64-v8a)
|
在GitHub中找到frida项目地址:https://github.com/frida/frida
在Release中找到2.1节frida相应的版本(这里是16.4.10)
根据我的手机CPU架构arm64-v8a,选择对应的 frida-server-16.4.10-android-arm64.xz,使用压缩包工具打开,解压其中的文件并重名为frida_arm64_new(非必要步骤,只是为了方便), 需要将该文件复制到手机中,需要使用adb push命令。打开CMD:
1
2
3
4
5
6
7
8
|
C:\Users\430>adb push ......\frida_arm64_new /data/local/tmp (命令解析:adb push local remote)
......\frida_arm64_new: 1 file pushed, 0 skipped. 28.6 MB/s (56475128 bytes in 1.886s)
C:\Users\430>adb shell
wayne:/ $ su (获取super user权限)
wayne:/ # cd /data/local/tmp (进入目录)
126|wayne:/data/local/tmp # chomd 777 frida_arm64_new (将frida-server的权限设置为777,这样才能运行,否则会出现"can't execute: Permission denied"这样的错误)
wayne:/data/local/tmp # ./frida_arm64_new
|
在VSCode搭建frida-il2cpp-bridge
frida-il2cpp-bridge是一个 Frida 模块,用于在运行时转储、跟踪或劫持任何 Il2Cpp 应用程序,而无需 global-metadata.dat 文件。
搭建frida-il2cpp-bridge前,需要安装好Nodejs环境并配置好环境变量,然后下载frida-agent-example 并在VSCode中创建一个空项目,将frida-agent-example中内容放到该项目目录下

然后在VSCode中打开Powershell输入:
1
2
3
4
5
|
PS ......\frida> npm i frida-il2cpp-bridge
added 52 packages in 2s
5 packages are looking for funding
run `npm fund` for details
|
此时项目目录下会多出一个node_modules文件夹

实战Hook,以纯白和弦为例
使用frida-il2cpp-bridge hook
在1.2节中已经提到SetAssetBundleDecryptKey 函数是我们要hook的核心。首先要dump出libil2cpp.so相关内容编写dump.ts
1
2
3
4
5
6
|
import "frida-il2cpp-bridge";
Il2Cpp.perform(() => {
Il2Cpp.dump()
})
|
在VSCode中的Powershell使用frida hook命令。注入模式与启动命令解析:
| 注入模式 |
描述 |
命令或参数 |
| Spawn |
将启动App的权利交由Frida来控制,即使目标App已经启动,在使用Frida注入程序时还是会重新启动App |
-f |
| Attach |
在目标App已经启动的情况下,Frida通过ptrace注入程序从而执行Hook的操作 |
|
由于不清楚so的加载时机我们采用Spawn模式注入App,com.rastar.cbhx 是包名可以通过MT管理器之类的工具或者查看,自行搜索
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
PS ......\frida> frida -U -f com.rastar.cbhx -l dump.ts
____
/ _ | Frida 16.4.10 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to MI 6X (id=485dda7)
Spawned `com.rastar.cbhx`. Resuming main thread!
[MI 6X::com.rastar.cbhx ]-> il2cpp: dumping mscorlib...
il2cpp: dumping Mono.Security...
il2cpp: dumping System.Xml...
[MI 6X::com.rastar.cbhx ]-> il2cpp: dumping System.Core...
il2cpp: dumping UnityEngine.SharedInternalsModule...
il2cpp: dumping UnityEngine.CoreModule...
il2cpp: dumping UnityEngine.AssetBundleModule...
il2cpp: dumping UnityEngine.PhysicsModule...
il2cpp: dumping UnityEngine.TextRenderingModule...
il2cpp: dumping UnityEngine.AudioModule...
il2cpp: dumping UnityEngine.GridModule...
il2cpp: dumping UnityEngine.IMGUIModule...
il2cpp: dumping UnityEngine.ImageConversionModule...
il2cpp: dumping UnityEngine.InputLegacyModule...
il2cpp: dumping UnityEngine.Physics2DModule...
il2cpp: dumping UnityEngine.TextCoreModule...
il2cpp: dumping UnityEngine.UnityWebRequestAssetBundleModule...
il2cpp: dumping UnityEngine.XRModule...
il2cpp: dumping System.Diagnostics.StackTrace...
il2cpp: dumping System.Globalization.Extensions...
il2cpp: dumping System.IO.Compression...
il2cpp: dumping UnityEngine.AIModule...
il2cpp: dumping UnityEngine.AndroidJNIModule...
il2cpp: dumping UnityEngine.AnimationModule...
il2cpp: dumping UnityEngine.DirectorModule...
il2cpp: dumping UnityEngine.GameCenterModule...
[MI 6X::com.rastar.cbhx ]-> il2cpp: dumping UnityEngine.InputModule...
il2cpp: dumping UnityEngine.JSONSerializeModule...
il2cpp: dumping UnityEngine.ParticleSystemModule...
il2cpp: dumping UnityEngine.TerrainModule...
il2cpp: dumping UnityEngine.TilemapModule...
il2cpp: dumping UnityEngine.UIElementsModule...
il2cpp: dumping UnityEngine.UIModule...
il2cpp: dumping UnityEngine.UIWidgetsModule...
il2cpp: dumping UnityEngine.UnityAnalyticsModule...
il2cpp: dumping UnityEngine.UnityWebRequestWWWModule...
il2cpp: dumping UnityEngine.VFXModule...
il2cpp: dumping UnityEngine.VRModule...
il2cpp: dumping UnityEngine.VideoModule...
il2cpp: dumping UnityEngine...
il2cpp: dumping netstandard...
il2cpp: dumping DOTween...
[MI 6X::com.rastar.cbhx ]-> il2cpp: dumping UnityEngine.UI...
il2cpp: dumping BetterStreamingAssets...
[MI 6X::com.rastar.cbhx ]-> il2cpp: dumping DOTweenPro...
il2cpp: dumping GameLog...
il2cpp: dumping Google.Protobuf...
il2cpp: dumping IFix.Core...
il2cpp: dumping Unity.TextMeshPro...
il2cpp: dumping spine-unity...
il2cpp: dumping Unity.Timeline...
il2cpp: dumping Assembly-CSharp-firstpass...
il2cpp: dumping Assembly-CSharp...
il2cpp: dump saved to /storage/emulated/0/Android/data/com.rastar.cbhx/files/com.rastar.cbhx_1.0.20.cs (该路径为dump出的文件保存位置)
|
关闭App,
1
2
3
4
5
6
|
Process terminated
[MI 6X::com.rastar.cbhx ]->
Thank you for using Frida!
PS ......\frida> adb pull /storage/emulated/0/Android/data/com.rastar.cbhx/files/com.rastar.cbhx_1.0.20.cs dump.cs (使用pull命令从手机下载到电脑)
/storage/emulated/0/Android/data/com.rastar.cbhx/files/com.rastar.cbhx_1.0.20.cs: 1 file pulled, 0 skipped. 34.1 MB/s (10253448 bytes in 0.287s)
|
搜索SetAssetBundleDecryptKey,搜索到如下内容
1
2
3
4
5
6
7
|
// UnityEngine.AssetBundleModule
class UnityEngine.AssetBundle : UnityEngine.Object
{
...
static System.Void SetAssetBundleDecryptKey(System.String password); // 0x0269c2cc
...
}
|
拿取到重要信息并编写 hook.ts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import "frida-il2cpp-bridge";
Il2Cpp.perform(() => {
console.log("Unity version: " + Il2Cpp.unityVersion);
const img = Il2Cpp.domain.assembly("UnityEngine.AssetBundleModule").image;
const AssetBundle = img.classes.filter(klass => klass.name.includes("AssetBundle"))[0];
if (!AssetBundle) {
console.error("AssetBundle not found!");
return;
}
Il2Cpp.trace(true)
.classes(AssetBundle)
.filterMethods(method => method.name.includes("SetAssetBundleDecryptKey"))
.and()
.attach();
});
|
运行hook.ts
1
|
PS ......\frida> frida -U -f com.rastar.cbhx -l hook.ts
|
如果没有信息输出,则点击提示下载资源包下载资源包,不用着急。

加密key就是yulong1868gnoluy ,把它转成16进制后就可以在解密软件中使用了:79756c6f6e6731383638676e6f6c7579
常规方法hook
hook.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
Interceptor.attach(Module.findExportByName(null, "dlopen"), {
onEnter: function(args) {
this.path = Memory.readCString(args[0]);
},
onLeave: function(retval) {
if (this.path.indexOf("libil2cpp.so") !== -1) {
console.log("[+] libil2cpp.so loaded at: " + retval);
var baseAddr = Module.findBaseAddress("libil2cpp.so");
if (baseAddr) {
console.log("[+] libil2cpp.so base address: " + baseAddr);
var targetFunc = baseAddr.add(0x269C2CC);
Interceptor.attach(targetFunc, {
onEnter: function (args) {
console.log("SetAssetBundleKey called");
var strArgPtr = args[0];
var strArg = Memory.readCString(strArgPtr);
console.log(hexdump(strArgPtr));
},
onLeave: function (retval) {
console.log("SetAssetBundleKey returned");
}
});
} else {
console.error("[-] Failed to find base address of libil2cpp.so");
}
}
}
});
|
Powershell:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
PS D:\Game\noname\TOOL\AAAAA_Reverse\frida\tutorial\frida> frida -U -f com.rastar.cbhx -l hook.js
____
/ _ | Frida 16.4.10 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to MI 6X (id=485dda7)
Spawned `com.rastar.cbhx`. Resuming main thread!
[MI 6X::com.rastar.cbhx ]-> [+] libil2cpp.so loaded at: 0x2a0f8c1209669ad7
[+] libil2cpp.so base address: 0x7bc108c000
SetAssetBundleKey called
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
7b046fc7c0 00 38 f2 c0 7b 00 00 00 00 00 00 00 00 00 00 00 .8..{...........
7b046fc7d0 10 00 00 00 79 00 75 00 6c 00 6f 00 6e 00 67 00 ....y.u.l.o.n.g.
7b046fc7e0 31 00 38 00 36 00 38 00 67 00 6e 00 6f 00 6c 00 1.8.6.8.g.n.o.l.
7b046fc7f0 75 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 u.y.............
7b046fc800 50 41 e9 0b 7b 00 00 00 00 00 00 00 00 00 00 00 PA..{...........
7b046fc810 00 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 ................
7b046fc820 06 00 00 00 01 00 00 00 02 00 00 00 05 00 00 00 ................
7b046fc830 ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 ................
7b046fc840 00 38 f2 c0 7b 00 00 00 00 00 00 00 00 00 00 00 .8..{...........
7b046fc850 0c 00 00 00 50 00 61 00 79 00 4c 00 61 00 73 00 ....P.a.y.L.a.s.
7b046fc860 74 00 4f 00 72 00 64 00 65 00 72 00 00 00 00 00 t.O.r.d.e.r.....
7b046fc870 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7b046fc880 00 38 f2 c0 7b 00 00 00 00 00 00 00 00 00 00 00 .8..{...........
7b046fc890 0f 00 00 00 53 00 63 00 65 00 6e 00 65 00 4d 00 ....S.c.e.n.e.M.
7b046fc8a0 69 00 72 00 72 00 6f 00 72 00 46 00 61 00 6c 00 i.r.r.o.r.F.a.l.
7b046fc8b0 67 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 g...............
|
在地址7b046fc7d3-7b046fc7f2中可以解析出yulong1868gnoluy,(由于Unity引擎String类型使用的是UTF-16小端序2字节表示一个字符)
常见游戏UnityCN Key(网络收集) 持续更新中…
| name |
key |
| PGR GLB/KR |
6B75726F6B75726F6B75726F6B75726F |
| PGR CN/JP/TW |
7935585076714C4F72436F6B57524961 |
| Archeland/Kalpa of Universe |
426C61636B4A61636B50726F6A656374 |
| Archeland 1.1.14 |
50726F6A65637441726368654C616E64 |
| Neural Cloud |
31636162383436663532393031633965 |
| Higan: Eruthyll |
45317832633361346C35693662377572 |
| White Chord |
79756C6F6E6731383638676E6F6C7579 |
| Mecharashi |
33384338334631333245374637413041 |
| Castlevania: Moon Night |
31323334353637383132333435363738 |
| Huā Yì Shān Xīn Zhī Yuè |
494E484A6E68647970716B3534377864 |
| Doula Continent |
52346366773339474644326661785756 |
| Bless Global |
6C6F6E67747567616D652E796A66623F |
| Starside |
41394A3542384D4A50554D3539464B57 |
| Resonance Soltice |
5265736F6E616E63655265626F726E52 |
| Oblivion Override |
7179666D6F6F6E323331323433343532 |
| Dawnlands |
636F6465737339353237636F64657373 |
| BB |
5F6C4E3F3A3F233F3F3F3F663F1A3F3F |
| Dynasty Legends 2 |
746169686567616D6573323032323032 |
| SevenSphere |
3753484446474356433836356B6B514C |
| Evernight CN |
68687878747478736868787874747873 |
| Xintianlong Babu |
61323562623133346363326464333265 |
| Frostpunk: Beyond the Ice |
7368756978696E673838383838383838 |
| Elpis |
79756e67756968616f77616e31323334 |
后记
本人自学安卓逆向个人理解笔记,仅做学习用途
感谢 ChatGPT 提供技术支持
感谢 暗夜十三司 提供代码思路
参考文献: