十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

《大侠立志传》ES3存档修改全攻略:从解密定位到回写避坑

《大侠立志传》ES3存档修改全攻略:从解密定位到回写避坑 玩《大侠立志传》的玩家多少都有过这种时刻剧情走到岔路一个选择把门派好感全崩了或者某个BOSS卡了三天属性就是差那几点。重新开档太痛苦CE内存修改又是每次启动游戏都得重新来一遍。这时候直接动存档文件才是最根本的解法。《大侠立志传》的存档后缀通常是.es3或.save网上搜这个格式很多人都会告诉你这是Unity的Easy Save 3插件写的。这篇文章就是想把这套“ES3存档解密修改”的完整思路讲透从怎么判断加密方式到怎么定位字段、改数值、回写验证再到我实际踩过的各种坑一次性理清楚。这篇东西适合两类人第一类是剧情党只想把某些错过的好感、声望或物品随手改回来继续享受武侠世界第二类是研究党想搞明白Easy Save 3的存档格式到底长什么样以后玩其他Unity游戏时也能直接套用。不管你属于哪种改之前先记住一句话这是单机存档怎么改都不影响别人但一定要备份原文件。1. 存档文件为什么叫“ES3”先弄清楚再动手1.1 Easy Save 3Unity游戏里常见的存档方案如果你用AssetStudio之类的工具看过《大侠立志传》的程序集或者只是把存档文件拖进Hex编辑器里看一眼就会发现文件开头经常有ES3三个字符。这个ES3不是“第三版”的意思它是Moodkie这家公司做的Unity插件Easy Save 3的缩写。国内很多单机团队做存档功能时不会自己去造一个复杂的序列化格式直接接这个插件一行代码ES3.Save(Gold, 100, save.es3)就能把数据写到本地文件里。Easy Save 3本质上是一个键值对数据库。你可以把它理解成一个“精简版JSON文件”只是它有自己的二进制编码规则。它支持int、float、string、bool、Vector3、数组、字典、甚至自定义对象的序列化。正因为支持的类型多所以游戏里几乎任何数据——金钱、经验、好感、物品数量、当前位置坐标、任务进度标记——都有可能以某种方式躺在这个文件里。外人看到的是乱七八糟的字符但只要你理解了它的存储逻辑修改起来并不比改配置文件难多少。1.2 大侠立志传的存档到底放在哪里先解决一个最基础的问题存档文件在哪儿。Unity引擎的游戏存档路径通常不归游戏根目录管而是在Windows的用户目录下。主流位置是C:\Users\你的用户名\AppData\LocalLow\DefaultCompany\大侠立志传\C:\Users\你的用户名\AppData\LocalLow\大侠立志传\也有可能是C:\Users\你的用户名\AppData\Local\..\下面的相关目录DefaultCompany是很多Unity默认发布商名称如果你看到这个目录多半就是它了。不同版本、不同安装平台存档路径可能有差异。最省事的办法是直接用Everything这类工具全盘搜*.es3几秒钟就能把所有相关文件列出来。游戏里看到的存档槽位一般对应一个.es3文件文件名可能是slot0.es3、Save0.es3、1.es3之类的我见过最直观的是直接叫Archive_0.es3。搜索的时候注意Steam云存档会把文件同步一份到Steam安装目录的userdata下但你本地真正读写的还是LocalLow这个位置。后文会单独讲云存档这个坑。2. 解密不是玄学先判断这段数据属于哪一类2.1 用文本编辑器打开存档第一步永远是“定级”拿到.es3文件后先别急着拿游戏存档编辑器去开。我建议你复制一份副本然后用Notepad或VSCode打开。这一步的核心目的不是看内容而是判断这个文件到底属于哪一类因为后续操作方案完全不同。我用一个表格直观点展示常见情况打开后看到的特征判断结果可行方案大量中文/英文可读文本甚至有Base64码未加密或仅做了Base64编码直接文本替换/解码后修改乱码为主但能搜索到若干英文单词或中文片段Easy Save 3默认二进制模式十六进制编辑器按字节修改完全随机字节搜不到任何可读字符可能启用了AES加密或自定义压缩谨慎处理难度很大大侠立志传目前网上能搜到的案例多数属于前两类。换句话说游戏并没有把存档做成“完全密文”开发者大概率只是图省事用了Easy Save 3的默认配置。但“默认配置”和“没做任何编码”是两回事所以还是按这个流程先判断一次别想当然地直接找工具改。2.2 Base64形态的存档先解码再做修改如果文件打开后是一整段连续的M0V9...、4p2/...这种只在Base64字符表里出现的字符那说明游戏在写入时把二进制数据做过一次Base64编码方便在文本环境中存储。这种情况下你的“解密”动作就很简单先把整段Base64解码成原始二进制再按二进制模式处理。用Python处理大概是这样import base64 with open(slot0.es3, rb) as f: raw f.read() decoded base64.b64decode(raw) with open(slot0.decoded.es3, wb) as f: f.write(decoded)解码后得到的.decoded.es3如果出现ES3开头说明核心数据确实是Easy Save 3格式。修改完这个解码文件之后还要用一段对称代码把它重新编码回Base64再放回存档目录import base64 with open(slot0.decoded.es3, rb) as f: data f.read() encoded base64.b64encode(data) with open(slot0.modified.es3, wb) as f: f.write(encoded)有个细节要注意有些在线Base64工具会对超大文件做换行或截断处理一旦换行格式不对游戏就读不出来。所以能本地脚本处理就不要用网页工具。2.3 二进制形态的存档能搜到字符就能改如果文件头是ES3后面跟着大量乱码同时你又能通过搜索发现Name、Level、Exp这样的明文字符串那恭喜你这是最标准的Easy Save 3未加密二进制形态。这个文件并不需要做任何“整体解密”你只需要把它当作“半结构化二进制”来处理。什么叫半结构化就是说键名是明文保存的但值可能以二进制保存。比如Money这个键名后面跟着的可能就是4字节或者8字节的数值。你搜索的时候要同时搜索“键名字符串”和“数值的十六进制字节”。这种感觉很像在一个装满杂物的抽屉里找东西标签键名是看得见的但你得把对应的“抽屉”值打开才知道里面装的是什么。后面第三节会具体讲定位方法。3. 实战修改从“定位字段”到“改数写回”3.1 用已知数值反查字段位置对于绝大多数玩家来说最简单的定位方法不是直接找键名而是先记住游戏里的一个当前数值然后关掉游戏拿这个数值去二进制里搜。举个例子你现在的金钱是12345。关掉游戏后把备份出来的存档文件拖进010 Editor或HxD里切换成十六进制视图然后搜索这几个可能存在的形态12345的ASCII字符串字节形式是31 32 33 34 35int32小端39 30 00 00float32小端需要先算MySQL不需要算一下IEEE 754表示12345.0的十六进制是0x4640E400小端写入就是00 E4 40 46我用Python给一个简单的搜索脚本可以把所有出现位置打印出来import re data open(slot0.es3, rb).read() def search_ints(value): patterns { int32_le: int(value).to_bytes(4, little), int64_le: int(value).to_bytes(8, little), ascii: str(value).encode(utf-8), } for name, needle in patterns.items(): start 0 while True: idx data.find(needle, start) if idx -1: break print(f{name} at 0x{idx:X}: {needle.hex()}) start idx 1 search_ints(12345)实测下来最容易命中的往往是ASCII字符串。如果你搜到了多个位置别急着全改。先把搜索结果里靠近某个键名比如Money、Gold、金钱的那几处记录下来再结合读取出来的上下文判断。如果一个位置前后跟着大量其他数字那大概率是被其他数据凑巧组成的假匹配要多试几次。3.2 不同数据类型的十六进制编码规则改存档有个绕不开的问题同一数值游戏里可能用int存也可能用float存甚至可能用string存。除非你能反编译游戏代码否则最好的办法是把常见编码都试一遍。下面是经常会遇到的存储类型和对应字节形态场景C#类型示例数值小端十六进制形态金钱、物品数量int3210064 00 00 00经验值、声望int64/long10064 00 00 00 00 00 00 00生命值、内力量float32100.000 00 C8 42开关标记booltrue01剧情文本string10031 30 30或带长度前缀重点说float。很多人第一次改存档明明搜到了100的ASCII字符串改完之后进游戏却显示“0”或者乱数。原因就是那个字段真实的存储类型是float你只改了一个文本副本。float的精确定位方法是先把它转成4字节小端import struct val 100.0 b struct.pack(f, val) print(b.hex()) # 输出 0000c842拿到0000c842之后再去十六进制文件里搜索这4个字节。注意顺序小端模式下字节和人类习惯的十六进制表示是反着的。3.3 回写存档的正确顺序和验证方法修改完成后回写是很多人翻车的地方。我的习惯顺序是这样关闭游戏进程确保存档文件没有被系统锁定。把原始存档改名为.bak而不是直接覆盖。把修改后的文件放到原路径文件名和扩展名保持完全一致。启动游戏读取这个槽位进游戏看数值是否变化。为什么要先改名而不是直接覆盖因为如果新文件格式不对游戏读取时会直接报“存档损坏”。这时如果你已经把原文件覆盖了哭都来不及。保留一个.bak出问题只需要把新文件删掉再把.bak改名回来就行。验证时还有个小技巧不要一开始就改十几个字段。先只改一个最显眼的数值比如金钱或主角经验确认读档正常后再批量处理其他数据。这个习惯能帮你把改坏存档的损失降到最低。4. 我把存档改坏过几次之后总结出的避坑清单4.1 文件长度被改动存档瞬间变“坏档”这是新手最容易犯、也最隐蔽的坑。如果你是把数字当字符串直接做“查找替换”比如把存档里的999替换成10000文件的字节数就会变长。Easy Save 3在读取时很多字符串和值前面是有长度前缀的你增加一个字符后面的所有偏移都会错位读档结果就是直接打不开。解决思路有两种。第一种是“等长替换”三位数改成三位数四位数改成四位数比如100改成999这类操作在文本替换层面就是安全的。第二种是“二进制替换”如果字段本身是int或float类型则直接改对应的4字节或8字节长度完全不变这才是最推荐的做法。记住一个底层逻辑改长度会破坏整个文件结构改编码值不会。除非你非常确定某个字符串的确是纯文本且没有任何长度依赖否则尽量不要让文件总字节数发生变化。4.2 搜索不到值的三种原因与排查顺序有时候你搜遍了整个文件都找不到目标值不一定是方法错了很可能是下面几种情况一是值被“派生计算”过。游戏里显示的金钱可能是金钱 基础金钱 身上物品折算存档里存的只是基础值你拿显示值去搜当然搜不到。这种情况先去游戏里把一个角色装备卸掉让显示值变成最原始的状态再搜。二是数据类型不匹配。前面举过float和int的区别。如果搜int搜不到尝试转成float再搜搜float搜不到再尝试搜索它的字符串表示。三是值被压缩或分段存储。有些游戏会把大数字拆成多个小字段或者先统一做个偏移加密。遇到这种就不要再硬搜了去看那个字段附近的键名通常能顺藤摸瓜找到关联数据。实测中90%的“搜不到”都是第一和第二种原因。4.3 云存档与多重保存目录的干扰《大侠立志传》走Steam平台时云存档和本地存档之间很可能不是即时同步关系。你改了本地文件Steam云同步可能在你启动游戏时又把它覆盖回旧版本反过来你启动游戏前没关云同步客户端也可能用线上的坏档覆盖你刚改好的文件。最稳妥的操作顺序是先打开Steam在游戏属性里把云存档同步临时关掉再改本地文件改完进入游戏验证没问题后再重新开启云存档并手动让客户端上传你最新的存档。如果游戏内自带“保存/读取”界面确认存档列表里的时间和修改后的文件时间戳一致那就说明路径找对了。4.4 AES加密的情况判断出来就收手最后说一个不那么乐观的情况。如果你用文本编辑器打开存档发现不仅没有任何可读字符甚至连常见文件头都找不到那很大概率是开发者启用了Easy Save 3的AES加密选项。如果真的是这样普通玩家靠Hex编辑器人肉搜索就基本无解了因为你看到的不是“被编码的数据”而是“被加密的数据”需要密钥才能解开。该不该继续往里深挖我的建议是及时收手。想要提取AES密钥通常得用dnSpy去反编译游戏的Assembly-CSharp.dll过程复杂不说针对这类单机存档加密花大量时间并不划算。愿意折腾的可以去看游戏是否有官方控制台或创意工坊工具不愿意折腾的直接另找其他修改思路比如用内存修改器临时改都比钻AES的黑盒要省力得多。5. 进阶玩法不只有改数值5.1 批量替换和脚本化修改思路当你已经摸清一个字段的存储位置和类型之后如果有多个存档文件都要改或者一个文件里想改几十个数值靠手点Hex编辑器就不太行了。我建议写个小脚本把整个过程自动化。简单思路如下import re import shutil # 备份 shutil.copy(slot0.es3, slot0.bak.es3) with open(slot0.es3, rb) as f: data f.read() # 示例把所有 Exp 后面的4字节int32统一加上一定偏移 # 注意这里只是思路演示实际偏移要根据文件结构修改 pattern re.compile(rbExp(.{1,4}), re.DOTALL) def add_offset(match): prefix match.group(1) # 这层处理要看具体字节布局我只是演示逻辑 return bExp prefix new_data pattern.sub(add_offset, data) with open(slot0.es3, wb) as f: f.write(new_data)这个脚本的逻辑很粗糙真正动手前一定要先搞懂目标字段的完整字节布局。自动化最大的价值不是“快”而是“可复现”——你反复调整数值时不会因为手误把某个无关字段一起改了。5.2 物品、坐标、剧情标记等其他可改内容数字字段是最简单的但存档里能改的不只是数值。大侠立志传这种RPG存档里通常还包含了角色坐标、任务标记、物品ID列表这类结构化数据。物品数量可以直接改数值但物品本身的ID往往是以字符串或者哈希形式存在的。想新增物品你至少需要先知道这个物品在游戏里的内部ID然后仿照同类型物品的字节结构完整构造出一条新记录。坐标字段通常以Vector3结构存储也就是三个float。如果你在某个位置同时搜到三个连续的小端float那很有可能是当前角色的世界坐标。复制一套坐标值粘贴到另一个存档里可以实现一种“近似传送”的玩法。不过要小心某些关键剧情地点会有触发器硬改坐标可能导致角色卡进墙体或者触发异常剧情分支。剧情标记则更麻烦它们经常是bool值或短字符串。改这类数据之前最好先在游戏里做一次“事件触发前”和“事件触发后”的存档差异对比拿工具做个二进制diff这样才能准确定位到哪些字节发生了变化。5.3 工具安全不要乱下“存档解密器”网上搜ES3存档相关的内容经常能搜到各式各样的“存档解密器”“一键修改器”。我的建议是除非你能确认这个工具的开源代码和发布渠道否则尽量不要下载运行。存档修改本身是单机行为但来路不明的第三方工具通常捆绑了各种额外行为拿一个游戏存档去换一个被植入木马的电脑这笔账怎么算都不划算。自己动手的好处不只是安全更重要的是你能逐渐理解这种“键值对二进制”格式的一般规律。之后遇到另一个用Easy Save 3的Unity游戏你几乎能无缝复用这套方法。我在实际改《大侠立志传》的过程中最大的体会是不只是手驰几个数字而是把“二进制编辑器类型判断字节替换”这条链路跑通了。每次改完一个新字段再进游戏验证那种“猜对了存储类型”的正反馈比角色变强本身还有意思。最后分享一个小习惯每改完一个字段就在备份文件旁新建一个modify_log.txt记录改了什么位置、什么类型、改成了什么值。这么做看似麻烦但当你改到第五个、第十个字段时会庆幸自己当初记了这份日志。存档修改是一场跟二进制数据的对话记性再好也不如烂笔头。
返回列表