逆向某游戏加密文本——IL2CPP
今天来解密一下一款名叫圣骑士莉卡的游戏。游戏的文本以及存档都做了加密,而且游戏打包用的IL2CPP这就加大了逆向的难度(一般用IL2CPP打包的游戏比较容易劝退)。
不过对于我这种没事就搞搞Unity逆向的人来说其实跟Mono差不多,只是增加了一点分析难度。
首先老套路,先用IL2CppDumper对脚本进行初步的解析。一般来说,没动过手脚的脚本IL2CppDumper自动分析就行了。分析完后,主要用到dump.cs 和 stringliteral.json 这两个文件。dump.cs 用来分析脚本的大致逻辑,里面包含所有类和方法的基本信息。
当然,也可以用dnspy直接分析DummyDll目录下生成的C#脚本。
stringliteral.json 则包含了脚本内部会用到的字符串信息(需要在后续IDA分析中用到)。

本次主要是分析加密解密的方法,前期的方法的定位过程就大致略过了。
定位:
首先要定位加密解密脚本,这里我发现,如果直接把部分游戏文本删掉的话,游戏依然能运行,缺失的文本位置,全部都会由索引用的字段代替。而且在游戏存档位置的log文件中,会看到报错。
通过报错信息,可以大致得到加载文本涉及到的类和方法。
于是通过一系列分析,最终定位到了Crypt这个类。

可以看到,该类有两个私有字符串类型的字段,pw和salt,非常明显,加密应该用到这两个字段,奇怪的是这两个字段没有初始值,应该是IL2CppDumper没分析出来,因为有.cctor类型初始化器的话,应该至少有一个字段是有初始值的,不然应该不会存在。
那只能继续用IDA分析了。

进到IDA后直接跳到0x1819A4F90处查看类型初始化器。

稍微做了一下备注(备注的有点不对),
其中
对应的是变量 pw
对应的是变量 salt
而图中的 pw, salt 其实是这两个变量的初始值的地址。
然后在stringliteral.json中搜索 pw和salt 对应的地址偏移




得到了两个字符串,
接下来就是分析解密方法,

该类重载了两个Crypt方法,
一个参数是字符串类型,返回字符串类型,
另一个参数是字节数组,返回也是字节数组。
也就是说理论上来讲,游戏应该存在两种形式的加密类型数据,一种是二进制文件,一种是字符串型的加密。而字符串类型应该都是base64的形式。
该游戏恰巧存在这两种类型的文件。
首先分析一下,参数是string的Decrypt。

一些重要方法都已经将名字改回来了,
前面一大堆都是一些寻址初始化啥的(猜的,反正不影响),
这一块可以看到,输入的字符串经过FromBase64String后返回了字节数组,其实一般也就是这样,字符串基本都是经过base64的。
然后data之后输入到Decrypt_byte这个方法里,
之后返回值又经过get_UTF8的解码,
之后一大堆已经没有意义了,基本可以确定是返回了一串字符串。
在这一过程中,最重要的环节就是Decrypt_byte 这个方法。
Decrypt_byte 为了便于查看自己改了一下名字,其实就是另一个的输入为byte[] 的Decrypt。
显然解密的关键最终其实就是byte[] Decrypt(byte[] encrypted)

接下来查看该方法



从中可以看出,用了AES加密,然后KEY是128位(16字节),IV也是128位(16字节) 模式是CBC, 末尾补齐是PKCS7。
然后是KEY和IV的生成,可以看到用的是Rfc2898DeriveBytes这个类(即PBKDF2)
主要是输入两个字符串,作为密钥和盐进行循环x次某种计算获得一串hash值。Hash值中截取一部分就可以作为AES加密用的KEY和IV了,
从上面的伪代码中看出,所有的参数基本都是默认的,甚至是代码都可能是照着网上一些固定模板抄的,用到的字符串也是之前获得的两个字符串也就是说自己写个C#脚本,就能解密了。
附上C#代码:( pwd, salt )请自行查找
以及python版本: