如何对游戏存档文件进行编码以提升防篡改能力?
游戏本地存档防篡改方案(针对save.dat文本类存档)
针对你提到的「存档是重命名为save.dat的txt文件,用base64编码完全防不住篡改」的问题,下面给几个实用的方案,能大幅提高普通用户的篡改门槛(注:本地存档不可能100%防住硬核玩家,但拦大部分人足够了):
1. 哈希签名验证(最推荐,实现简单)
核心逻辑是给存档数据加个「防伪标签」,读取时核对标签是否一致:
- 把所有核心数据(金币、角色ID、关卡进度等)拼接成一串字符串,比如
gold:1200,char_id:3,level:5 - 加上一个只有你知道的自定义密钥(别直接硬编码在代码里,比如拆成几个字符串片段在代码不同位置拼接),用SHA-256生成哈希值
- 把原始数据和哈希值一起写入save.dat,比如用
|分隔:gold:1200,char_id:3,level:5|a1b2c3d4... - 读取存档时,先拆分出原始数据和哈希值,用同样的密钥重新生成哈希,对比两个值:一致就正常加载,不一致说明存档被改了,直接拒绝加载或者恢复默认存档
示例伪代码(Python):
import hashlib # 自定义密钥(别直接写死,可混淆处理) SECRET_KEY = "my_game_save_secret_123" # 保存存档 def save_game(): save_data = "gold:1200,char_id:3,level:5" # 生成哈希签名 signature = hashlib.sha256((save_data + SECRET_KEY).encode()).hexdigest() # 写入文件 with open("save.dat", "w") as f: f.write(f"{save_data}|{signature}") # 读取存档 def load_game(): try: with open("save.dat", "r") as f: content = f.read().strip() save_data, saved_signature = content.split("|") # 重新计算签名 computed_signature = hashlib.sha256((save_data + SECRET_KEY).encode()).hexdigest() if computed_signature != saved_signature: print("存档已被篡改,恢复默认存档") return get_default_save() return parse_save_data(save_data) except: print("存档损坏,恢复默认") return get_default_save()
2. 对称加密(比编码靠谱的多)
Base64只是编码不是加密,换用AES这类对称加密算法,把存档数据加密后再写入文件:
- 用AES把原始数据加密成二进制,写入save.dat(此时文件内容是乱码,普通用户看不懂也没法直接改)
- 读取时用密钥解密,解密失败就判定存档被篡改
示例伪代码(Python,用cryptography库):
from cryptography.fernet import Fernet # 生成密钥(只生成一次,妥善保存,别丢) # key = Fernet.generate_key() SECRET_KEY = b"your_aes_secret_key_here" fernet = Fernet(SECRET_KEY) # 保存存档 def save_game(): save_data = b"gold:1200,char_id:3,level:5" encrypted_data = fernet.encrypt(save_data) with open("save.dat", "wb") as f: f.write(encrypted_data) # 读取存档 def load_game(): try: with open("save.dat", "rb") as f: encrypted_data = f.read() save_data = fernet.decrypt(encrypted_data).decode() return parse_save_data(save_data) except: print("存档被篡改或损坏,恢复默认") return get_default_save()
3. 数据混淆+冗余校验(辅助手段)
可以和上面的方法搭配用,进一步提高篡改难度:
- 把数据字段名或数值打乱,比如把
gold:1200改成dlog:0021(字段名反向,数值反转),读取时再还原 - 加冗余校验位,比如计算所有数值的总和,把总和存在存档里,读取时核对总和是否匹配(比如金币1200+角色ID3+关卡5=1208,存档里存
check_sum:1208,读取时重新计算总和对比)
关键提醒
- 密钥一定要保护好,别直接写在代码里,可通过字符串拼接、混淆、甚至存在资源文件里的方式隐藏,避免反编译后直接拿到
- 本地存档永远没法完全防篡改,硬核玩家可以通过内存修改、反编译破解密钥,但上面的方法足以拦住90%以上的普通用户
- 如果要绝对安全,只能把核心存档数据放在服务器端,本地只存一个验证token,每次读取从服务器拉取,但这需要联网功能
内容的提问来源于stack exchange,提问作者Meskyy076
相关产品推荐
相关产品推荐

