手游存档篡改排查记录:明文、内存、完整性都查了什么

一个单机 / 弱联网项目做客户端安全验收,排查到存档这块问题不小。把过程记一下:现象、怎么定位、为什么能改、每层怎么堵、上线前过哪些检查项。

现象

抽查本地存档,金币、等级、背包全明文落盘,字段和值一眼能对上,改完塞回去客户端照读。先复现确认:用存档编辑器改文件、数值直接生效,问题坐实。

排查

第一步,看存档落哪、是不是明文。

Unity 项目先翻 PlayerPrefs。Android 上就是一个明文 XML:

/data/data/<pkg>/shared_prefs/<pkg>.v2.playerprefs.xml

金币一行 <int name="gold" value="99999" />,背包、任务是 JSON 和 flag。Unity 官方文档自己都写着 PlayerPrefs 不加密、别存敏感数据。

第二步,验证是不是只有文件这一条路。

把存档加密后再测,数值还能改。挂 GameGuardian 观察:它根本不碰存档文件,直接搜内存:搜当前金币、花掉一点再搜、几轮锁定地址就改了。说明文件层之外,还有内存层这条独立的路。

第三步,看程序能不能发现“被改过”。

存档没有任何完整性标记,改完读回时,程序无从判断它还是不是原始版本。篡改和正常存档在程序眼里没区别。

分析

三条线对应三个独立问题:

  • 文件明文:存档要被游戏反复读写、写回成自己能认的格式,对拿着设备的人天生就是敞开的,不加密等于裸奔。
  • 内存可改:文件加密只堵文件这条路,游戏一加载金币在内存里就是明文 int,GG 搜内存跟加没加密无关。
  • 无完整性:没有校验,程序发现不了篡改。

再深一层:加密和校验的密钥都在客户端,SO / DLL 拖进 IDA / dnSpy 能把密钥扒出来,造一份“合法”存档。判定只要在客户端做,就有天花板。

方案

按层堵,成本从低到高。

文件层:AES 加密 + 完整性校验。给存档算 HMAC,或一个数存两份(值 + 反码)交叉校验,改文件当场露。

string mac = HmacSha256(saveKey, saveBytes);  // 存成 {data, mac}
// 加载重算比对,对不上 = 被篡改

内存层:值不落明文,ObscuredInt 那套,内存里躺 gold ^ key,用时才还原。

int _key = Rand();
int _enc = gold ^ _key;   // 内存里是异或后的值
int Gold => _enc ^ _key;

这只挡裸搜。GG 有针对 XOR 的加密搜索(a;b)和模糊搜索,还得叠交叉校验 + 反调试。

存放与密钥:存档放应用私有目录、别写公共目录;防拷贝就一机一把密钥,安装时随机生成、存进 Keystore / Keychain,账号 ID / 槽位 / 版本号当认证加密的 AAD。别拿 IMEI / Android ID 当密钥(会变、受权限、连累换机云恢复)。

服务端(带经济 / 交易 / 榜单):权威数据放服务端,客户端只当缓存;且服务端别把上传的存档原样入库,得做值域、字段自洽、必要时重演。

上线前检查项

  • 存档不落明文,键名别直白叫 gold
  • 有完整性校验(HMAC / 交叉校验),改文件能发现
  • 内存值做了混淆 + 交叉校验,GG 裸搜搜不到
  • 密钥没写死在代码,能换,尽量下沉 native
  • 存档在应用私有目录;设备绑定用安装期随机密钥,不用 IMEI
  • 带经济的:权威数据在服务端,且不原样入库

排到最后,结论很实在:存档在玩家手里、能读能写这条改不了,能做的是把成本抬到高过收益,把用编辑器和 GG 的大多数挡在外面。值钱的那份(能卖存档、能上榜交易的),最终算不算数别让客户端说了算。

(按文件 / 内存 / 服务端分层的完整做法和代码,搜「字节暗面 存档安全」有完整版。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值