吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 25252|回复: 338
上一主题 下一主题
收起左侧

[Android 原创] 元气骑士存档解密(Unity IL2Cpp 游戏逆向记录)

    [复制链接]
跳转到指定楼层
楼主
mlgmxyysd 发表于 2023-10-10 20:40 回帖奖励
声明:以元气骑士为例,仅用于学习研究。



最近玩元气骑士玩的有些上头,一闲下来就想打两把。

新出的迷迭岛游记赛季更新了神器级别武器,但能开出神器的赛季宝箱限制了每周只能购买 10 个。放着一大把之前赛季攒下来的赛季币没处花,精炼低的神器打的又不爽。

想到商店是联网更新的,那么可以抓一下商店请求包,扔进 Charles 中,没抓到任何有用的东西,应该不是 HTTP 请求,放弃。于是更换思路,直接修改存档。






说干就干,先使用游戏自带的 Google Play Games 云存档功能,将游戏存档同步到另一台有 root 权限的设备中,经过简单的目录和文件结构分析,我们得到了有用的文件列表:

[Shell] 纯文本查看 复制代码
files/backup.data # 游戏数据备份 加密方式 1
files/battles.data # 未完成的游戏 明文 JSON
files/game.data # 游戏基础数据 加密方式 1
files/item_data.data # 物品存档 加密方式 2
files/mall_reload_data.data # 商城刷新数据 加密方式 2
files/monsrise_data.data # 怪兽崛起数据 加密方式 2
files/net_battle.data # 在线联机数据 明文 JSON
files/sandbox_config.data # 电脑配置 明文 JSON
files/sandbox_maps.data # 电脑地图 明文 JSON
files/season_data.data # 赛季数据 加密方式 2
files/setting.data # 游戏设置 加密方式 2
files/statistics.data # 地下室统计 加密方式 2
files/task.data # 任务数据 加密方式 2
shared_prefs/com.ChillyRoom.DungeonShooter.v2.playerprefs.xml # 游戏数据 明文 XML


使用文本编辑器打开,可以大致得出,一共有两种加密方式,还有一些是未加密的明文。






打开 split_base_asset.apk 和 split_config.arm64_v8a.apk,发现了 assets/bin/Data 和 lib/arm64-v8a/libil2cpp.so,可以判定这是一个使用了 Unity 引擎,并使用 IL2Cpp 打包方式写的游戏。我们直接取出 split_base_assets/assets/bin/Data/Managed/Metadata/global-metadata.dat 和 split_config.arm64_v8a/lib/arm64-v8a/libil2cpp.so 两个文件,喂给 Il2CppDumper 辅助分析,程序报错 ERROR: This file may be protected.



根据文档提示,加保护的软件要用 GameGuardian 来 dump 内存中的 libil2cpp.so,但我没搞懂怎么 dump。(浇浇)

以普遍理性而论,旧版可能没有加保护,并且旧版的加密方法和新版一样,不然用户从旧版更新到新版,存档直接就报废了。



依照这个前提,我们在 APKMirror 里下载了一个 1.8.4 远古版,提取文件再次喂给 IL2CppDumper,成功跑出分析文件。



IDA 打开 libil2cpp.so,等分析完之后点击 File – Script File...,选择 IL2CppDumper 里的 ida_py3.py ,选择分析出的 stringliteral.json。



等脚本跑完再次执行脚本,这次选择 ida_with_struct_py3.py,选择分析出的 script.json 和 il2cpp.h,脚本运行时间比较长,让 IDA 先在后台跑。



用文本编辑器打开 stringliteral.json,搜索文件名 game.data,复制 address 中的地址。



等 IDA 跑完脚本,找到 IDA View 窗口,按 G 键,粘贴刚才复制的地址,点击 OK 跳转。



右键这个字符串的名字,点击 List cross references to… 来列出字符串的交叉引用。



我们需要知道的是,IL2Cpp 后的方法名是 Package.Class$$Method,在伪代码中,.$ 都会显示成 _,例如 System.String.Contact() -> System.String$$Contact() -> System_String__Contact(),了解这个规律会对我们之后的代码分析有帮助。

交叉引用中有一个 RGSaveManager.get_Path,直觉告诉我们这个就是读取存档的方法,跳转过去按 F5 查看伪代码。



右键方法名,选择 Jump to xref…




我们找到了 RSSaveManager.LoadGameData



分析代码,程序获取到路径后首先判断是否存在,如果存在就读取,然后跳转到 0x57C188,否则跳转到 0x57C170。按 G 跳转到 0x57C188



如果调用方法签名有问题,记得右键重命名一下方法签名。分析代码得出加密方式为 Xor,数据格式为 JSON。

跳转到 Abo.CryptUtil.DecryptXor 方法,再次跳转找到真实方法。




for 内的是加解密方法实现,使用一个递增变量,对每个字符进行两次 Xor 运算。第一次 v15 是遍历一个 15 位(i % 0xF)的固定密码表,第二次 v7 是遍历传入的密钥。



往前翻代码,并没有找出传入的密钥是什么,只能看到一个没解析出来的字符串 (v8 + 36),但这不妨碍我们继续反编译。

我们已经知道了数据格式是 JSON,那么文件的前两位解密后应该是 {"(左花括号和双引号),转为十六进制 0x7B 0x22

重写一下密码表的算法,运行程序得到密码表。



用 010 Editor 打开 game.data,得出前两位为 0x08 0x4E





打开 Windows 计算器 – 程序员,计算 0x7B XOR 0x08 XOR 0x00,得出密钥第一位为 0x73(ASCII 字符为 s),计算 0x22 XOR 0x4E XOR 0x01,得出密钥第二位为 0x6D(ASCII 字符为 m)。



在 stringliteral.json 中搜索以 sm 开头的字符串,一共有两个结果。



其中 small 下面还有两个字符串为 mediumlarge,明显是一组,不大可能是密钥。在刚才的密码表算法基础上加入密钥计算,尝试使用另一个搜索结果 smg 作为密钥解密。



解密成功,图中为皮肤数据。





这一种加密方式我们就解出来了,那么还剩下另一种明显不一样的加密方式,文件做了 Base64 处理。



在 Functions Window 中可以看到,除了 Xor,还有 DES 加密,猜测应该就是他了,先看下他是怎么实现的。



同样,跳转两次找到真实方法。




已知 DES 加解密需要 8 位的密钥和 8 位的初始化矢量。传入参数 passwordCopyTo 到了 v11 变量,然后 GetBytesv21 作为解密的 Key;v16 变量 GetBytesv23 作为解密的 IV,往上翻发现 v16v6 的 CopyTo,而 v6 为一次 Xor 解密的结果,其中 StringLiteral_8985StringLiteral_8986 分别作为 Xor 的密文和密钥。



StringLiteral_8985 包含一个不可见字符,IDA 看不到。



在 stringliteral.json 中找到这两个,复制过来,这个 DES 加解密方法就重写好了,由于 IV 不够 8 位,需要用 0 补足。



方法写好了,但我们还不知道密钥,按照一开始的方法,在 stringliteral.json 中搜索文件名。



复制地址跳转分析。




进入 Abo.JsonUtil.LoadJsonWithCrypt.ItemData 这个方法,使用了 DES 解密,刚才我们已经重写好了。



根据方法签名,第三个参数 StringLiteral_9924 是就密钥,原来就在文件名下面。



运行代码,解密成功。





按照这个方法,把其他几个文件也都分析了一遍,除了 statistic.data 的密钥是独立的,其他相同加密方式的文件都用了同一个密钥。



修改一下程序,自动根据文件名判断加解密方式和密钥。






分析存档内容,发现神器精炼等级保存在 item_data.data 的 mythicWeapons 对象中。



level 字段全改成 3,重新加密,覆盖数据,运行游戏,精炼等级已经变成我们想要的结果。





其他存档文件里面还有一些很有意思的字段,这里不再赘述,有兴趣的可以自行解密研究。

免费评分

参与人数 123吾爱币 +121 热心值 +111 收起 理由
AkaiSuisei + 1 + 1 用心讨论,共获提升!
soest + 1 + 1 牛波一
piboos + 1 热心回复!
0ling + 1 用心讨论,共获提升!
fjj945 + 1 用心讨论,共获提升!
TLPG + 1 用心讨论,共获提升!谢谢你的帖子
milu2004 + 1 谢谢@Thanks!
evalPrivateJS + 1 + 1 谢谢@Thanks!
juliusnan + 1 + 1 思路清晰!
Lanly + 1 + 1 我很赞同!
peiqihaoshuai + 1 我很赞同!
SilentNocturne + 1 + 1 我的天。。。这绝对是大神啊,每一步的逻辑都写清楚了。。。
LIN24 + 1 + 1 我很赞同!
lelele1 + 1 我很赞同!
abcdef969 + 1 + 1 谢谢@Thanks!
JerryGod + 1 + 1 谢谢@Thanks!
youren4987 + 1 + 1 我很赞同
ruocai + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Victoryship + 1 + 1 我很赞同!
GUANXUN + 1 我很赞同!
lkyhr + 1 我很赞同!
liliqingchuan + 1 + 1 我很赞同!
Tisfy + 1 + 1 谢谢@Thanks!
awesomewyz + 1 + 1 我很赞同!
Jshow + 1 + 1 用心讨论,共获提升!
yuzaizi521 + 1 + 1 我很赞同!
junjia215 + 1 + 1 谢谢@Thanks!
Tushen + 1 + 1 我很赞同!
JBYJLW + 1 我很赞同!
cflollolcf + 1 谢谢@Thanks!
ohssr + 1 + 1 谢谢@Thanks!
nyazhou + 1 + 1 谢谢@Thanks!
yunshaoa + 1 谢谢@Thanks!
chuan9 + 1 + 1 谢谢@Thanks!
shenzhouruoyi + 1 + 1 我很赞同!
ykss2023 + 1 我很赞同!
twl859588 + 1 谢谢@Thanks!
cenmuyan + 1 我很赞同!
zzz2580 + 1 + 1 谢谢@Thanks!
wangduanqueqiao + 1 + 1 用心讨论,共获提升!
cncprz + 1 + 1 鼓励转贴优秀软件安全工具和文档!
zhoumeto + 1 + 1 用心讨论,共获提升!
ctmaomao + 1 谢谢@Thanks!
wolaipao + 1 + 1 用心讨论,共获提升!
pelephone + 1 + 1 我很赞同!
unknownAI + 1 + 1 我很赞同!
jiangrui98 + 1 + 1 我很赞同!
q6790296 + 1 + 1 谢谢@Thanks!
fjtu04 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
dizzy0001 + 1 + 1 热心回复!
Vik09 + 1 + 1 谢谢@Thanks!
soyiC + 1 + 1 用心讨论,共获提升!
Baichun + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hzlei + 1 + 1 用心讨论,共获提升!
qiaoyong + 1 + 1 热心回复!
jsyczxyh + 1 用心讨论,共获提升!
LvMou + 1 + 1 用心讨论,共获提升!
Zhenzhuo + 1 + 1 谢谢@Thanks!
linsen6733 + 1 + 1 热心回复!
Leo625 + 1 + 1 我很赞同!
龙骑士尹志平 + 1 我很赞同!
LonelyCrow + 1 + 1 用心讨论,共获提升!
林暮云 + 1 谢谢@Thanks!
freehds588 + 1 + 1 用心讨论,共获提升!
lingyan + 1 我很赞同!
heimaojingzhang + 1 + 1 我很赞同!
erzi + 1 + 1 我很赞同!
1436581545 + 1 + 1 谢谢@Thanks!
Fanqim + 1 + 1 高手受教了
debug_cat + 2 + 1 用心讨论,共获提升!
杨顶天 + 1 + 1 厉害厉害
wjks86 + 1 谢谢@Thanks!
_小白 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
DamonLin + 1 + 1 用心讨论,共获提升!
三滑稽甲苯 + 2 + 1 用心讨论,共获提升!
zqds + 1 用心讨论,共获提升!
paomianhaochi + 1 + 1 我很赞同!
一个电脑小白 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Laign + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
k854053320 + 1 + 1 --------看不懂,但是我被震撼到了
ainstan + 1 + 1 热心回复!
aatrox、 + 1 + 1 用心讨论,共获提升!
vaycore + 1 + 1 用心讨论,共获提升!
hamxbb + 1 + 1 我很赞同!
wurenxi + 1 我很赞同!
M1SAKAZ + 1 + 1 用心讨论,共获提升!
Coldandcolder + 1 + 1 我很赞同!
tenleaf + 1 + 1 谢谢@Thanks!
gunxsword + 1 + 1 谢谢@Thanks!
HundSimon + 1 + 1 用心讨论,共获提升!
杨辣子 + 1 + 1 热心回复!
peiki + 1 + 1 我很赞同!
crizquan + 1 + 1 谢谢@Thanks!
2025888543 + 1 + 1 谢谢@Thanks!
xxxesa6xxx + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
courierma + 1 + 1 我很赞同!
DaKxhq54zDH + 1 好评加鹅
Bob5230 + 1 + 1 热心回复!
mq5123 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
diary 发表于 2023-10-29 23:05
本帖最后由 diary 于 2023-10-29 23:09 编辑

贴一个可行的解码的脚本代码,拿到存档可以直接破解
[PHP] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
68
<?php
//存档解密
function xor_crypt($ciphertext, $password)
{
    for ($i = 0; $i < strlen($ciphertext); ++$i) {
        $ciphertext[$i] = chr(ord($ciphertext[$i]) ^ ord($password[$i % strlen($password)]) ^ $i % 15 * ($i % 5) % 92);
    }
    return $ciphertext;
}
 
function des_crypt($ciphortext, $password, $encrypt = false)
{
    $iv = str_pad(substr(xor_crypt(hex2bin("112035352023"), "PASSWORD"), 0, 8), 8, hex2bin("00"));
    if ($encrypt) {
        return base64_encode(openssl_encrypt($ciphortext, "des-ede3-cbc", $password, OPENSSL_RAW_DATA, $iv));
    } else {
        return openssl_decrypt(base64_decode($ciphortext), "des-ede3-cbc", $password, OPENSSL_RAW_DATA, $iv);
    }
}
$keys = [];
$keys["game"] = "smg";
$keys["data"] = "iambo";
$keys["statistic"] = "crstl";
// 获取外部终端输入的文件路径
if (!isset($argv[1])) {
    die("请输入文件路径,例如:php sk.php file/game.data\n");
}
$file_path = $argv[1];
 
// 根据文件名来判断使用哪种解密方法
$name = pathinfo($file_path, PATHINFO_FILENAME); // 获取不带扩展名的文件名
$content = file_get_contents($file_path);
$decrypted_data = '';
 
switch ($name) {
    case "game":
        echo "Using XOR mode with game key.\n";
        $decrypted_data = xor_crypt($content, $keys["game"]);
        break;
    case "task_*_":
    case "item_data_*_":
    case "season_data_*_":
    case "moonrise_data_*_":
    case "mall_reload_data_*_":
        echo "Using DES mode with data key.\n";
        $decrypted_data = des_crypt($content, $keys["data"]);
        break;
    case "statistic_*_":
    case "statistic":
        echo "Using DES mode with statistic key.\n";
        $decrypted_data = des_crypt($content, $keys["statistic"]);
        break;
    default:
        echo "\033[32mFile is plaintext, nothing to do.\033[0m\n";
        exit;
}
 
$output_directory = './data_new/';
if (!file_exists($output_directory)) {
    mkdir($output_directory, 0777, true);
}
// Save the decrypted content to .txt and .json files
file_put_contents($output_directory . $name . ".txt", $decrypted_data);
// file_put_contents($output_directory . $name . "_diff.json", $decrypted_data);
// file_put_contents($output_directory . $name . ".json", $decrypted_data);
 
echo "Decryption completed and saved as .txt!\n";
?>

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
mlgmxyysd + 2 + 1 用心讨论,共获提升!

查看全部评分

推荐
 楼主| mlgmxyysd 发表于 2023-12-13 03:04 |楼主
awesomewyz 发表于 2023-12-5 15:54
厉害了,忽然明白了为啥版本加密之后一样被破解掉了,原来还能从老版本摸索出门道

哈哈,不过我在新帖子中,把新版本的也一样破掉了
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1844587
推荐
zxy1992123 发表于 2023-10-11 10:53
上次玩了破解版的,也没啥好玩的。其实关卡都一样的,纯打材料
沙发
diweiyi123 发表于 2023-10-10 20:47
学到了学到了
3#
菜苗小豆 发表于 2023-10-10 21:12
非常奈斯
4#
aa361328 发表于 2023-10-10 23:21
标记一下!!!!
5#
k452b 发表于 2023-10-10 23:42
好厉害,没看懂
6#
zhouxinyi 发表于 2023-10-10 23:55
这个可以标记备用,分析得不错
7#
amami520 发表于 2023-10-11 07:08
看不明白,看个热闹,还需要努力才行啊
8#
ErenLuo 发表于 2023-10-11 08:02
大佬求抱大腿
9#
feizaier 发表于 2023-10-11 08:29
逆向真是条漫长的路啊
10#
chyduck 发表于 2023-10-11 08:34
太厉害了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-5-19 19:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表