吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10954|回复: 33
收起左侧

[Android 原创] 无Root修改应用内部存储数据

  [复制链接]
Forwindz 发表于 2021-5-16 12:51

萌新一枚,这篇算是一个笔记吧

起因是玩某个国外的单机内购游戏,然后受不了肝度打算改存档

刚买的米10,root需要先刷开发版再申请解锁,so....
(模拟器上这破游戏打不开,不然root后就很轻松了(:з」∠)

主要思路:

安卓有备份与恢复机制,大部分应用允许从备份数据恢复。
这是无root下覆写内部存储数据最轻松的方式。

不过应用自己也能禁止或者管理备份文件,具体查Android Developer Documentation

手机:MIUI 12,安卓版本11
开始折腾:

解包备份

首先备份,只备份想要的应用。
然后把备份文件拉到电脑上去
MIUI上是存储设备\MIUI\backup\AllBackup\
bak文件拉出来,拖到HxD里看二进制

Android的备份文件很简单,主要是安卓备份文件头+tar压缩文件,当然国产MIUI还有自己额外的文件头。

文件头:

选中的区域就是Android备份文件头,
ANDROID BACKUP标识,备份版本(5.0),加密模式(none)
选中区域上方是MIUI备份文件头
选中区域下方就是压缩文件开始部分

去掉MIUI文件头(选区上方数据),然后用abe.jar解包成tar文件↗github
java -jar abe.jar unpack xxxx.bak xxx.tar

abe.jar实现的是比较通用的安卓备份协议,然而MIUI里备份设置超级简单,就是MIUI文件头+Android备份文件头+tar文件内容,无压缩无加密,所以直接在HxD里把两个文件头去了直接当tar也行...

tar文件直接7zip解压就行,至此,应该能拿到备份的数据了:
apk和cache,Android/data/包名下的数据,应用私有的数据

Unity逆向

然后是逆向Unity,不过小游戏一般没什么壳和加密,所以直接上
apk解压,assets/bin/Data/,资源文件基本都在这儿,一般拿Unity Studio↗或者disUnity↗解压一下就行

然而更多情况是遇到新版本和加密,解析不出来(doge
disunity支持的unity版本确实过老了,个人觉得Unity Studio更好用,而且还有GUI(短期记忆每天被迫查文档...
虽然我最后还是没能提取资源,有空再研究下(瘫

反编译代码

所以美术资源先放一边,先来代码
Unity现在应该都是il2cpp backend了,mono就不提了,所以直接定位路径:
运行库so:lib\arm64-v8a\libil2cpp.so
元数据文件:设备\Android\data\应用包名\il2cpp\Metadata\global-metadata.dat
然后把两个文件丢给Il2CppDumper↗,dump一下class和方法声明
Il2CppDumper.exe ibil2cpp.so global-metadata.dat
生成一堆文件,对于我来说里面最有用的是dump.cs,所有C#类和方法声明,外加每个方法的虚拟地址
然后开始递归搜索,搜Diamond查找相关方法,然后在ida中查看相应的Assembly-CSharp.dll文件,分析具体代码...

实际上根本分析不动(╯‵□′)╯︵┻━┻,但至少现在有汇编可以看了

存档文件

回头看存档文件,apps\com.ssicosm.dungeon_princess_2_free\sp\com.ssicosm.dungeon_princess_2_free.v2.playerprefs.xml
800KB+,一看就是存档(用Preference Key-Value存档是认真的吗...)
点进去大概是这种画风:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="LFZGUwhpJ11cQitXDFRvBTl5FUxZWQhgBFRFU1A%3D">0%2FevWhQCAEK4%2FBE%3D</string>
    <string name="MFZZQjkFOm9VVxZZC2cBaSlGEVFfWFM%3D">DwIABV3MAg%3D%3D</string>
    <string name="MFZZQjkAOm9VVxZZC2cCaSpg">VW5pdAUCAGnZ1gg%3D</string>
    <string name="LFZGUwhpJ0pRVQNEFnRVVxJeAEpvBzl5FUxZWQhgBFRFU1E%3D">SW52ZRQCAGnZ1gg%3D</string>
    <string name="LFZGUwhpLV1cWwNCKFlZWjkCOndAQg9ZC25RWhNTVg%3D%3D">SW52ZRQCAGnZ1gg%3D</string>

%3D,很明显,URL编码,先过一遍URL解码
LFZGUwhpJ11cQitXDFRvBTl5FUxZWQhgBFRFU1A%3D=>LFZGUwhpJ11cQitXDFRvBTl5FUxZWQhgBFRFU1A=  

末尾等号,多半是base64之类的,然后直接base64解码...  

...获得了一堆乱码

然后只能回头分析代码,看来是简单加密过了(doge

存档解密

众所周知,AES, DES 是超级常用的加密算法,
然后我顺着C#和Unity相关的密码学库(Encrypt)找引用...找了半天没找到,淦(时间成本+⑨)
只能从存档相关变量入手,比如Diamond这个变量,
直接在dump.cs里搜,找到相关类Data_Manager_Cntr,是个数据存储工具人,
查关键字save,找到SaveStageDataAll()方法,对应虚拟地址0xA7FDD4,离文件存储指日可待
IDA启动,载入DummyDll下的Assembly-CSharp.dll分析  

实际上完全没必要看懂代码,直接找B 0xABCDEF之类的地址跳转指令和调用函数指令,
一路跳到真正的加密解密的地方:ObscuredInt, ObscuredByte, EncryptIntValue
看汇编我怀疑是异或,因为有EOR这个指令,异或计算是最高效简便的办法,至少能直接拦住改存档的萌新数个小时(比如我)

实际上看到一半啃不动了,打开iLSpy↗,看了一下包名,毕竟小型游戏或多或少会用些SDK和社区插件,除了我这种动不动就想要造一个轮子的人(专门生产不能用的方轮子)
然后查到了有个叫anti-cheat toolkit的插件,C#源代码(旧?新版本)直接到手,完美(:з」∠),剩下的就很简单了

看了下源码,和ida中比对了一下,虽然有的地方不同,但变化不大。
加密算法非常简单,就是异或!
作者指定一个key,(这个key可能和设备唯一标示符有关),然后数据转成字节流,按位与key进行异或就行了,key长度不够的话就循环用key
对于一个键值对,键名会被初始key异或混淆一下,然后键名+初始key组成一个新的key来异或键值对的值,然后再加上3bytes的类型信息和4bytes的原始数据的xxhash
异或用来混淆的话,加密解密计算就很简单了,异或奇数次,加密,异或偶数次,解密(不用遇到数论题真是太好了)

现在问题就是怎么获取key
如果能挂断点分析的话,应该能很轻松地拿到了
打开安卓模拟器,游戏启动失败...不对,可能设备相关,我模拟器拿到的key可能不管用

Android_ID高版本下,每个应用获得的ID与 硬件信息,软件信息,APP本身签名信息关联,所以很有可能每个应用拿到不一样的ANDROID_ID。Unity中用deviceUniqueIdentifier获得唯一标示符,参考  

手机没root,告辞(当然可以考虑强制让系统dump内存,可是...C#的GC会把内存搬来搬去)
还是静态分析吧(误

进入游戏变动游戏数值,比如Diamond 16->15,然后备份,拉取存档,和原文比较,
找到变动的值,S2lhbQUCAI5W1RE= => VGlhbQUCAEi9msI=
对应的键:IVFRWwlYAQ==

好吧,看不出来什么,转成二进制
S2lhbQUCAI5W1RE= =>0x5469616d 05 02 00 48bd9ac2
VGlhbQUCAEi9msI==>0x4b69616d 05 02 00 8e56d511
按照加密算法,`0x5469616d0x4b69616d是加密数据,其他是类型信息0x05 02 00和哈希信息0x48bd9ac20x8e56d511
所以
0x5469616d xor key = 16
0x4b69616d xor key = 15
解得key=0x5b 69 61 6d

但是这个key只对这个变量起作用,并且键值对的键也作为key的一部分,所以,我们拿这个key去还原对应的键IVFRWwlYAQ==
对应二进制为0x2151515b095801,获得Diam四个字母,注意到这和Diamond相似,且正好匹配7个字节,那就可以认为这个键的真实值是Diamand字符串了
得到真正的原始key="0x45383036663665",7个字节的key,先扔进xml解密一下  

注意到解密出artifac这个单词(artifact),遗物当然得拼全了,于是更新下我们的key到8位0x4538303666366538

再次解密,这次拿装备名字试试,比如inven_Br怎么看都应该是inven_Bracer,得到key=0x453830366636653830366636
注意到key非常长,但对一些长字符串数据仍解密不成功,考虑到循环,尝试缩短key,得到key=0x653830366636
这个就是真正的key了,解密后数据就是

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="Inven_BeltMail_3_OptionValue6">1.7000000476837158 @20@2@0</string>
    <string name="Unit_3_Weapon_1_Option5"> @15@2@0</string>
    <string name="Unit_6_Weapon_2_LV">0 @5@2@0</string>
    <string name="Inven_BracersLeather_1_OptionValue7">0.0 @20@2@0</string>

总之看起来非常舒服就是了233

另外anti-cheat toolkit也对内存数据部分进行了异或混淆,所以就算内存查找也多半搜不到真实数据,需要一些特别的技巧

打包备份文件

这部分本来应该很简单的,我们不是有abe.jar吗,直接java -jar abe.jar pack xxx.tar xxx.ab不就行了....

然后我就凉了(MIUI直接恢复失败)

首先是tar打包的问题,abe.jar对应的github readme提示过,先把原备份文件的文件单给拉下来(文件在tar包中存储的顺序很重要)
tar tf 原备份文件.tar | grep -F "com.包名.name" > package.list
然后再根据此列表打包,
tar cf 打包的压缩名.tar -T package.list
package.list存储了你要压缩的文件,这样能保证严格按照安卓备份的文件顺序打包

注意linux和windows下打包产生的tar可能还是不满足Android/MIUI备份文件要求,
虽然MIIUI告诉我恢复成功了,但是app数据从原先8MB变成了100KB,很明显没有完全成功啊)

抓取debug日志分析,adb.exe找不到的话用这个来抓取日志↗


05-16 00:57:08.924 W/BpBinder(30448): Slow Binder: BpBinder transact took 3851ms, interface=miui.app.backup.IBackupManager, code=3 oneway=false
05-16 00:57:08.924 I/ACC_EVENT_TRIGGERED( 7597): TYPE: 2048     PACKAGE: com.miui.backup
05-16 00:57:08.924 I/AUTOSTART_DEBUG( 7597): EVENT IS VALID     TYPE: 2048     PACKAGE: com.miui.backup
05-16 00:57:08.925 E/Backup:BackupManager(30448): IOException
05-16 00:57:08.925 E/Backup:BackupManager(30448): java.io.IOException: write failed: EPIPE (Broken pipe)
05-16 00:57:08.925 E/Backup:BackupManager(30448): 

免费评分

参与人数 11威望 +1 吾爱币 +29 热心值 +10 收起 理由
RedOFox + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
amus + 1 + 1 热心回复!
Noyi + 1 + 1 谢谢@Thanks!
chenyongqi + 1 + 1 谢谢@Thanks!
miyatotora + 1 + 1 谢谢@Thanks!
d0cklng + 1 + 1 我很赞同!
Intro + 1 谢谢@Thanks!
caleb110 + 1 + 1 热心回复!
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
HQXZ + 1 + 1 我很赞同!
一块砖头 + 1 热心回复!

查看全部评分

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

ryanhn717 发表于 2023-11-16 09:29
逐字逐句看完了,目前正在使用GG修改单机游戏,涉及到异或的加密从游戏面板内存数据端已经发现了几种,一直想弄明白更进一步的加密方式,这篇随写正好解决了我部分疑虑。真的感谢!

RedOFox 发表于 2021-5-19 09:52
S2lhbQUCAI5W1RE= =>0x5469616d 05 02 00 48bd9ac2
VGlhbQUCAEi9msI==>0x4b69616d 05 02 00 8e56d511
这两串好像写反了

后面的看不懂,我还在学习中
CIBao 发表于 2021-5-17 09:54
bjxiaoyao 发表于 2021-5-17 10:32
思路清奇,方法得当,感谢分享。
plauger 发表于 2021-5-17 10:36
嗯,IOS的方式也类似,修改备份,再同步回去
雨之幽 发表于 2021-5-17 11:20
看不懂。。。
丶man 发表于 2021-5-17 12:40
学习了~找时间试试
xdfg 发表于 2021-5-17 15:41
卧潮,难度这么大?
cacuts 发表于 2021-5-17 19:34
太秀了吧你也,玩个游戏这么拼
HQXZ 发表于 2021-5-17 21:53
感谢分享
xixicoco 发表于 2021-5-17 23:33
不錯,優秀文章
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 08:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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