这个题,卡很久了,还记得上次来劲搞了好几天没搞出来,心烦直接扔回收站了。
今天打算做题的时候又心血来潮,想要再试一试。
因为先前没有unity3d的逆向经验,网上也没有关于这题的解题分析…于是搜遍百度,Google.拿着前辈们的经验,一点点摸索。
使用工具
- Riru-Il2CppDumper
- Android Studio
- IDA Pro
- Frida
正题
从libil2cpp.so入手
关于il2cpp,详情可以参考 用Unity做游戏,你需要深入了解一下IL2CPP
为什么要从libil2cpp.so入手,因为源码就包含在其中.
然而光靠IDA根本无从下手,连调用的函数都不清楚。
查看apk的lib目录
libil2cpp放到IDA里,分析比较慢,而且暂时用不到,扔一边。
利用Riru-Il2CppDumper进行dump
相比于Il2CppDumper,使用了Riru框架,在Android环境下对相关释放函数Hook并dump出解密后的metadata.具体的原理和使用可以看GitHub
使用 Android Studio 打开
修改game头文件
使用Gradle进行模块编译
编译成功后在out目录下会生成模块
在Magisk中安装插件,重启。
打开app,使用adb push出 data/data/包名/files/dump.cs
打开dump.cs,能够看到几万行的代码.
找到我们需要分析的函数
我也没什么特别好的办法。 只能是通过字段的猜测还有Assembly-CSharp.dll的index进行定位.
既然RVA已经出来了,那么我们就可以使用IDA进行分析。
IDA的静态分析
跳转到地址0x518b54,将函数名改成CheckFlag,F5查看伪代码。将Sub_****函数改为我们已知的名字,方便分析。
int __fastcall CheckFlag(int a1, int a2) { int v3; // r0 int v4; // r0 int v5; // r4 if ( !byte_69C825 ) { sub_4B82BC(1279); byte_69C825 = 1; } v3 = dword_698140; if ( (*(_BYTE *)(dword_698140 + 178) & 1) != 0 && !*(_DWORD *)(dword_698140 + 96) ) { il2cpp_runtime_class_init_0(); v3 = dword_698140; } AESEncrypt( *(_DWORD *)(v3 + 80), a2, *(_DWORD *)(*(_DWORD *)(v3 + 80) + 4000), *(_DWORD *)(*(_DWORD *)(v3 + 80) + 2364)); v5 = v4; if ( (*(_BYTE *)(dword_696FB8 + 178) & 1) != 0 && !*(_DWORD *)(dword_696FB8 + 96) ) il2cpp_runtime_class_init_0(); return sub_7D644(0, v5, dword_69B7F0, 0);
最后返回的值是调用了sub_7D644,代码分析,猜测传入的v5是AES加密后的参数。继续跟。
bool __fastcall sub_7D644(int a1, int a2, int a3) { int v5; // r0 if ( !byte_693576 ) { sub_4B82BC(5543); byte_693576 = 1; } v5 = dword_696FB8; if ( (*(_BYTE *)(dword_696FB8 + 178) & 1) != 0 && !*(_DWORD *)(dword_696FB8 + 96) ) v5 = il2cpp_runtime_class_init_0(); return sub_D15EC(v5, a2, a3); }
没什么关键的处理,继续跟函数sub_D15EC。
bool __fastcall sub_D15EC(int a1, int a2, int a3) { _BOOL4 result; // r0 bool v4; // zf int v5; // r12 _DWORD *v6; // r2 _DWORD *v7; // lr bool v8; // zf int v9; // r1 int v10; // r3 bool v11; // zf result = 1; if ( a2 != a3 ) { v4 = a2 == 0; result = 0; if ( a2 ) v4 = a3 == 0; if ( !v4 ) { v5 = *(_DWORD *)(a2 + 8); if ( v5 == *(_DWORD *)(a3 + 8) ) { v6 = (_DWORD *)(a3 + 12); v7 = (_DWORD *)(a2 + 12); if ( v5 <= 7 ) { LABEL_16: if ( v5 >= 4 ) { if ( *v7 != *v6 || v7[1] != v6[1] ) return result; v5 -= 4; v6 += 2; v7 += 2; } if ( v5 >= 2 ) { if ( *v7 != *v6 ) return result; v5 -= 2; ++v6; ++v7; } result = 1; if ( v5 ) result = *(unsigned __int16 *)v7 == *(unsigned __int16 *)v6; } else { while ( 1 ) { v8 = *v7 == *v6; if ( *v7 == *v6 ) v8 = v7[1] == v6[1]; if ( !v8 ) break; v9 = v6[2]; v10 = v7[2]; v11 = v10 == v9; if ( v10 == v9 ) v11 = v7[3] == v6[3]; if ( !v11 ) break; v5 -= 8; v6 += 4; v7 += 4; if ( v5 < 8 ) goto LABEL_16; } } } } } return result; }
伪代码很长…静下心,仔细看下来,看到 if ( a2 != a3 )
分析可以结束了。
a2是之前经AES加密后的密文,a3是dword_69B7F0,那么只要a2==a3,CheckFlag就会返回1.
而传入参数dword_69B7F0很可疑,尝试使用 Frida 进行 Hook。
Frida native Hook
Frida这工具就不介绍了,网上资料已经很多了。
直接找到libil2cpp.so 基址,再加上之前dump.cs中得来的偏移量,对未导出函数进行Hook。
Hook的过程有一个坑就是Hook到的参数是宽字符 ,导致直接使用ReadCString()失效。
使用hexdump进行替代即可解决。
我这里同时Hook了CheckFlag调用到的过程函数,来加深理解。
Java.perform(function(){ var soAdrr = Module.findBaseAddress("libil2cpp.so"); send("[soAdrr] "+ soAdrr); var ptrCheckFlag = soAdrr.add(0x518a24); send("[ptrCheckFlag] " + ptrCheckFlag); Interceptor.attach(ptrCheckFlag,{ onEnter: function(args){ console.log(("enter ptrCheckFlag args[0]->" + args[0])); console.log("enter ptrCheckFlag args[1]->\n" +hexdump(args[1], { offset: 12, length: args[0].toInt32() * 2 + 12 })); }, onLeave: function(args){ console.log(args.toInt32()); args.replace(1); console.log(args); } }) var ptrAESEncrypt = soAdrr.add(0x518b54); send("[ptrAESEncrypt] " + ptrAESEncrypt); Interceptor.attach(ptrAESEncrypt,{ onEnter: function(args){ console.log(("enter ptrAESEncrypt args[0]-> " + args[0])); console.log(("enter ptrAESEncrypt args[1] text->\n" + hexdump(args[1]))); console.log(("enter ptrAESEncrypt args[2]-> password\n" + hexdump(args[2],{ offset: 12, length: 12 + 16 * 2 }))); console.log(("enter ptrAESEncrypt args[3]-> iv\n" + hexdump(args[3],{ offset: 12, length: 12 + 16 * 2 }))); }, onLeave: function(args){ //send("leave->"+args); console.log("enter ptrAESEncrypt retvalue->\n" + hexdump(args)); } }) var ptrD15EC = soAdrr.add(0x0D15EC); send("[ptrD15EC] " + ptrD15EC); Interceptor.attach(ptrD15EC,{ onEnter: function(args){ console.log(("enter ptrD15EC args[0]-> " + (args[0]))); console.log(("enter ptrD15EC args[1] ->\n" + hexdump(args[1]))); console.log(("enter ptrD15EC args[2]-> \n" + hexdump(args[2]))); }, onLeave: function(args){ console.log("enter ptrD15EC retvalue-> " + args); } }) })
最后的结果
message: {'type': 'send', 'payload': '[soAdrr] 0xd67e8000'} data: None message: {'type': 'send', 'payload': '[ptrCheckFlag] 0xd6d00a24'} data: None message: {'type': 'send', 'payload': '[ptrAESEncrypt] 0xd6d00b54'} data: None message: {'type': 'send', 'payload': '[ptrD15EC] 0xd68b95ec'} data: None enter ptrCheckFlag args[0]->0xa enter ptrCheckFlag args[1]-> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF f33fe91c 6d 00 61 00 73 00 6f 00 6e 00 63 00 72 00 61 00 m.a.s.o.n.c.r.a. f33fe92c 6b 00 65 00 k.e. enter ptrAESEncrypt args[0]-> 0xf340f000 enter ptrAESEncrypt args[1] text-> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF f33fe910 80 65 ee f2 00 00 00 00 0a 00 00 00 6d 00 61 00 .e..........m.a. f33fe920 73 00 6f 00 6e 00 63 00 72 00 61 00 6b 00 65 00 s.o.n.c.r.a.k.e. f33fe930 00 00 00 00 00 00 00 00 80 65 ee f2 00 00 00 00 .........e...... f33fe940 09 00 00 00 6d 00 61 00 73 00 6f 00 6e 00 63 00 ....m.a.s.o.n.c. f33fe950 72 00 61 00 6b 00 00 00 00 00 00 00 00 00 00 00 r.a.k........... f33fe960 80 65 ee f2 00 00 00 00 0a 00 00 00 6d 00 61 00 .e..........m.a. f33fe970 73 00 6f 00 6e 00 63 00 72 00 61 00 6b 00 65 00 s.o.n.c.r.a.k.e. f33fe980 00 00 00 00 00 00 00 00 80 65 ee f2 00 00 00 00 .........e...... f33fe990 09 00 00 00 53 00 65 00 6c 00 65 00 63 00 74 00 ....S.e.l.e.c.t. f33fe9a0 41 00 6c 00 6c 00 00 00 00 00 00 00 00 00 00 00 A.l.l........... f33fe9b0 80 65 ee f2 00 00 00 00 0a 00 00 00 63 00 6f 00 .e..........c.o. f33fe9c0 6c 00 6c 00 65 00 63 00 74 00 69 00 6f 00 6e 00 l.l.e.c.t.i.o.n. f33fe9d0 00 00 00 00 00 00 00 00 80 65 ee f2 00 00 00 00 .........e...... f33fe9e0 0b 00 00 00 55 00 6e 00 69 00 74 00 79 00 45 00 ....U.n.i.t.y.E. f33fe9f0 6e 00 67 00 69 00 6e 00 65 00 00 00 00 00 00 00 n.g.i.n.e....... f33fea00 80 65 ee f2 00 00 00 00 0b 00 00 00 53 00 79 00 .e..........S.y. enter ptrAESEncrypt args[2]-> password 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF ef4b71bc 39 00 31 00 63 00 37 00 37 00 35 00 66 00 61 00 9.1.c.7.7.5.f.a. ef4b71cc 30 00 66 00 36 00 61 00 31 00 63 00 62 00 61 00 0.f.6.a.1.c.b.a. ef4b71dc enter ptrAESEncrypt args[3]-> iv 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF ef4b3eac 35 00 38 00 66 00 33 00 61 00 34 00 34 00 35 00 5.8.f.3.a.4.4.5. ef4b3ebc 39 00 33 00 39 00 61 00 65 00 62 00 37 00 39 00 9.3.9.a.e.b.7.9. ef4b3ecc enter ptrAESEncrypt retvalue-> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF f3401840 80 65 ee f2 00 00 00 00 18 00 00 00 55 00 65 00 .e..........U.e. f3401850 74 00 37 00 7a 00 67 00 49 00 43 00 4a 00 75 00 t.7.z.g.I.C.J.u. f3401860 75 00 4f 00 70 00 48 00 5a 00 50 00 74 00 56 00 u.O.p.H.Z.P.t.V. f3401870 78 00 6d 00 4a 00 41 00 3d 00 3d 00 00 00 00 00 x.m.J.A.=.=..... f3401880 80 65 ee f2 00 00 00 00 18 00 00 00 55 00 65 00 .e..........U.e. f3401890 74 00 37 00 7a 00 67 00 49 00 43 00 4a 00 75 00 t.7.z.g.I.C.J.u. f34018a0 75 00 4f 00 70 00 48 00 5a 00 50 00 74 00 56 00 u.O.p.H.Z.P.t.V. f34018b0 78 00 6d 00 4a 00 41 00 3d 00 3d 00 00 00 00 00 x.m.J.A.=.=..... f34018c0 80 65 ee f2 00 00 00 00 18 00 00 00 55 00 65 00 .e..........U.e. f34018d0 74 00 37 00 7a 00 67 00 49 00 43 00 4a 00 75 00 t.7.z.g.I.C.J.u. f34018e0 75 00 4f 00 70 00 48 00 5a 00 50 00 74 00 56 00 u.O.p.H.Z.P.t.V. f34018f0 78 00 6d 00 4a 00 41 00 3d 00 3d 00 00 00 00 00 x.m.J.A.=.=..... f3401900 80 65 ee f2 00 00 00 00 17 00 00 00 45 00 76 00 .e..........E.v. f3401910 65 00 6e 00 74 00 2f 00 47 00 72 00 61 00 70 00 e.n.t./.G.r.a.p. f3401920 68 00 69 00 63 00 20 00 52 00 61 00 79 00 63 00 h.i.c. .R.a.y.c. f3401930 61 00 73 00 74 00 65 00 72 00 00 00 00 00 00 00 a.s.t.e.r....... enter ptrD15EC args[0]-> 0xf2ee6580 enter ptrD15EC args[1] -> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF f3401840 80 65 ee f2 00 00 00 00 18 00 00 00 55 00 65 00 .e..........U.e. f3401850 74 00 37 00 7a 00 67 00 49 00 43 00 4a 00 75 00 t.7.z.g.I.C.J.u. f3401860 75 00 4f 00 70 00 48 00 5a 00 50 00 74 00 56 00 u.O.p.H.Z.P.t.V. f3401870 78 00 6d 00 4a 00 41 00 3d 00 3d 00 00 00 00 00 x.m.J.A.=.=..... f3401880 80 65 ee f2 00 00 00 00 18 00 00 00 55 00 65 00 .e..........U.e. f3401890 74 00 37 00 7a 00 67 00 49 00 43 00 4a 00 75 00 t.7.z.g.I.C.J.u. f34018a0 75 00 4f 00 70 00 48 00 5a 00 50 00 74 00 56 00 u.O.p.H.Z.P.t.V. f34018b0 78 00 6d 00 4a 00 41 00 3d 00 3d 00 00 00 00 00 x.m.J.A.=.=..... f34018c0 80 65 ee f2 00 00 00 00 18 00 00 00 55 00 65 00 .e..........U.e. f34018d0 74 00 37 00 7a 00 67 00 49 00 43 00 4a 00 75 00 t.7.z.g.I.C.J.u. f34018e0 75 00 4f 00 70 00 48 00 5a 00 50 00 74 00 56 00 u.O.p.H.Z.P.t.V. f34018f0 78 00 6d 00 4a 00 41 00 3d 00 3d 00 00 00 00 00 x.m.J.A.=.=..... f3401900 80 65 ee f2 00 00 00 00 17 00 00 00 45 00 76 00 .e..........E.v. f3401910 65 00 6e 00 74 00 2f 00 47 00 72 00 61 00 70 00 e.n.t./.G.r.a.p. f3401920 68 00 69 00 63 00 20 00 52 00 61 00 79 00 63 00 h.i.c. .R.a.y.c. f3401930 61 00 73 00 74 00 65 00 72 00 00 00 00 00 00 00 a.s.t.e.r....... enter ptrD15EC args[2]-> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF f340cc30 80 65 ee f2 00 00 00 00 2c 00 00 00 77 00 30 00 .e......,...w.0. f340cc40 5a 00 79 00 55 00 5a 00 41 00 48 00 68 00 6e 00 Z.y.U.Z.A.H.h.n. f340cc50 31 00 36 00 2f 00 4d 00 52 00 57 00 69 00 65 00 1.6./.M.R.W.i.e. f340cc60 36 00 33 00 6c 00 4b 00 2b 00 50 00 75 00 56 00 6.3.l.K.+.P.u.V. f340cc70 70 00 5a 00 4f 00 62 00 75 00 2f 00 4e 00 70 00 p.Z.O.b.u./.N.p. f340cc80 51 00 2f 00 45 00 2f 00 75 00 63 00 70 00 6c 00 Q./.E./.u.c.p.l. f340cc90 63 00 3d 00 00 00 00 00 80 65 ee f2 00 00 00 00 c.=......e...... f340cca0 2b 00 00 00 74 00 79 00 70 00 65 00 20 00 69 00 +...t.y.p.e. .i. f340ccb0 73 00 20 00 6e 00 6f 00 74 00 20 00 61 00 20 00 s. .n.o.t. .a. . f340ccc0 73 00 75 00 62 00 63 00 6c 00 61 00 73 00 73 00 s.u.b.c.l.a.s.s. f340ccd0 20 00 6f 00 66 00 20 00 4d 00 75 00 6c 00 74 00 .o.f. .M.u.l.t. f340cce0 69 00 63 00 61 00 73 00 74 00 64 00 65 00 6c 00 i.c.a.s.t.d.e.l. f340ccf0 65 00 67 00 61 00 74 00 65 00 00 00 00 00 00 00 e.g.a.t.e....... f340cd00 80 65 ee f2 00 00 00 00 2b 00 00 00 4f 00 6e 00 .e......+...O.n. f340cd10 6c 00 79 00 20 00 73 00 69 00 6e 00 67 00 6c 00 l.y. .s.i.n.g.l. f340cd20 65 00 20 00 64 00 69 00 6d 00 65 00 6e 00 73 00 e. .d.i.m.e.n.s. enter ptrD15EC retvalue-> 0x0 0 0x1 enter ptrD15EC args[0]-> 0xf2ee6580 enter ptrD15EC args[1] -> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF ef4ddde0 80 65 ee f2 00 00 00 00 10 00 00 00 43 00 6f 00 .e..........C.o. ef4dddf0 6e 00 67 00 72 00 61 00 74 00 75 00 6c 00 61 00 n.g.r.a.t.u.l.a. ef4dde00 74 00 69 00 6f 00 6e 00 73 00 21 00 00 00 00 00 t.i.o.n.s.!..... ef4dde10 80 65 ee f2 00 00 00 00 0f 00 00 00 45 00 72 00 .e..........E.r. ef4dde20 72 00 6f 00 72 00 20 00 6c 00 6f 00 61 00 64 00 r.o.r. .l.o.a.d. ef4dde30 69 00 6e 00 67 00 20 00 27 00 00 00 00 00 00 00 i.n.g. .'....... ef4dde40 80 65 ee f2 00 00 00 00 0f 00 00 00 41 00 73 00 .e..........A.s. ef4dde50 73 00 65 00 6d 00 62 00 6c 00 79 00 2d 00 43 00 s.e.m.b.l.y.-.C. ef4dde60 53 00 68 00 61 00 72 00 70 00 00 00 00 00 00 00 S.h.a.r.p....... ef4dde70 80 65 ee f2 00 00 00 00 0e 00 00 00 55 00 6e 00 .e..........U.n. ef4dde80 69 00 74 00 79 00 45 00 6e 00 67 00 69 00 6e 00 i.t.y.E.n.g.i.n. ef4dde90 65 00 2e 00 55 00 49 00 00 00 00 00 00 00 00 00 e...U.I......... ef4ddea0 80 65 ee f2 00 00 00 00 0f 00 00 00 55 00 6e 00 .e..........U.n. ef4ddeb0 69 00 74 00 79 00 45 00 6e 00 67 00 69 00 6e 00 i.t.y.E.n.g.i.n. ef4ddec0 65 00 2e 00 64 00 6c 00 6c 00 00 00 00 00 00 00 e...d.l.l....... ef4dded0 80 65 ee f2 00 00 00 00 0f 00 00 00 55 00 6e 00 .e..........U.n. enter ptrD15EC args[2]-> 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF ef4ddde0 80 65 ee f2 00 00 00 00 10 00 00 00 43 00 6f 00 .e..........C.o. ef4dddf0 6e 00 67 00 72 00 61 00 74 00 75 00 6c 00 61 00 n.g.r.a.t.u.l.a. ef4dde00 74 00 69 00 6f 00 6e 00 73 00 21 00 00 00 00 00 t.i.o.n.s.!..... ef4dde10 80 65 ee f2 00 00 00 00 0f 00 00 00 45 00 72 00 .e..........E.r. ef4dde20 72 00 6f 00 72 00 20 00 6c 00 6f 00 61 00 64 00 r.o.r. .l.o.a.d. ef4dde30 69 00 6e 00 67 00 20 00 27 00 00 00 00 00 00 00 i.n.g. .'....... ef4dde40 80 65 ee f2 00 00 00 00 0f 00 00 00 41 00 73 00 .e..........A.s. ef4dde50 73 00 65 00 6d 00 62 00 6c 00 79 00 2d 00 43 00 s.e.m.b.l.y.-.C. ef4dde60 53 00 68 00 61 00 72 00 70 00 00 00 00 00 00 00 S.h.a.r.p....... ef4dde70 80 65 ee f2 00 00 00 00 0e 00 00 00 55 00 6e 00 .e..........U.n. ef4dde80 69 00 74 00 79 00 45 00 6e 00 67 00 69 00 6e 00 i.t.y.E.n.g.i.n. ef4dde90 65 00 2e 00 55 00 49 00 00 00 00 00 00 00 00 00 e...U.I......... ef4ddea0 80 65 ee f2 00 00 00 00 0f 00 00 00 55 00 6e 00 .e..........U.n. ef4ddeb0 69 00 74 00 79 00 45 00 6e 00 67 00 69 00 6e 00 i.t.y.E.n.g.i.n. ef4ddec0 65 00 2e 00 64 00 6c 00 6c 00 00 00 00 00 00 00 e...d.l.l....... ef4dded0 80 65 ee f2 00 00 00 00 0f 00 00 00 55 00 6e 00 .e..........U.n. enter ptrD15EC retvalue-> 0x1
我输入的文本为masoncrake
Hook到 AES加密的key为 91c775fa0f6a1cba
,iv为 58f3a445939aeb79
,加密后的base64密文为:Uet7zgICJuuOpHZPtVxmJA==
这些都不是重点,重点是我们把flag的密文拿到了 w0ZyUZAHhn16/MRWie63lK+PuVpZObu/NpQ/E/ucplc=
用解密工具解密,成功!得到flag
N1CTF{h4ppy_W1TH_1l2cpp}
写在最后
看起来分析也很简单,实际上踩得的坑太多了,花了将近一天的时间。
也算是积攒一点unity逆向方面的知识吧。相比于cocos2dx,对加固后的unity3d游戏的分析难度相当。
发表回复