资讯动态

Flash小游戏存档逆向全记录:从SWF反编译到加密恢复

发布时间:2026/10/17 6:51:08 来源:尧图企业网站定制
周六晚上翻移动硬盘翻出一个几年前从某4399平台缓存下来的Flash小游戏。点开试了试游戏能跑但存档加载直接报错。看那架势游戏里的进度大概是找不回来了。本来想直接删文件了事转念一想反正手头有工具干脆把这个SWF的存档机制逆向一遍。分析过程不算短但走完之后收获比想象中大得多。如果你也在折腾老Flash游戏的数据迁移、想看懂某个SWF里的加密存档或者想拿一个小目标练手学习逆向分析这篇记录可以给你一条完整的参考路线。先说这次逆向的目标搞清楚游戏本地档案的存储位置、存储格式和加密方式最终把旧档解开让进度回到游戏里。整个过程绕开了任何联网授权只针对本地文件做静态拆解和算法还原。所有素材都是自己硬盘里本来就有的东西没有涉及付费内容绕过也没有传播任何破解产物。下面按实际操作顺序把从文件头到解密脚本的完整过程拆开讲。1. 目标选定与工具准备1.1 为什么选Flash小游戏做逆向入口Flash游戏SWF在逆向学习里是个非常友好的入口原因有三个。第一SWF文件本身是公开格式结构里标签边界清晰没有复杂的壳压缩也基本是zlib那点事。第二ActionScript 3编译出来的字节码反编译还原度很高用现成工具能得到接近源码的代码读起来不像原生汇编那么劝退。第三这类文件在本地缓存里散落很多拿自己电脑上的旧文件做实验没有任何版权负担。对我这种边恢复存档边练手的人来说再合适不过。说完优点也要泼一盆冷水Flash逆向不是万能的有些SWF做了很强的混淆比如字符串加密、类名改写成A0B1之类甚至把逻辑套到动画帧上分析难度会直线上升。但日常小游戏绝大多数没有这么重的保护尤其是很多从其他作品改版过来的代码风格一眼能看出是赶工产物。所以选目标时先挑文件体积中等几MB到十几MB、来源简单的Flash小游戏成功率最高。1.2 工具清单和选型理由这次全程用到的工具不多不少刚好覆盖从静态到动态的完整链路。工具用途为什么选它JPEXS Free Flash DecompilerFFDECSWF反编译、资源导出、P-code查看开源免费跨平台AS3还原度极高010 Editor / HxD十六进制查看文件头、标签偏移看头部和原始字节分布很直观7-Zip解压CWS的zlib内容处理压缩态SWF时顺手Python3写脚本验证解密算法自带base64、zlib库做算法复现最省事Flash Player Projector调试版动态运行和trace输出独立播放器不受浏览器限制选型逻辑很简单能用免费工具解决就不用商业工具。我之前试过用商业反编译器打开这个文件界面倒是花哨结果解析半分钟直接卡死。FFDEC反而两秒就响应导出代码也更干净。再加上它支持把SWF里的PNG、声音素材批量拖出来对分析美术资源也很管用。可以说这一套工具链已经覆盖了Flash逆向里最常用的环节短期内不太需要再添别的。2. 静态拆解把SWF翻成可读代码2.1 先确认文件格式拿到SWF文件第一步不要急着反编译先用十六进制工具点开。文件头三个字节如果看到FWS是未压缩CWS是zlib压缩ZWS是LZMA压缩。这次的文件头是CWS说明整体内容被zlib压过。第三字节之后是Flash版本号这里是13对应Flash Player 11.x时代算是比较老的产物。再往下四个字节是解压后的文件总长度这些信息在后面的标签遍历里都要用到。对于CWS文件很多标签结构要等解压后才好读。我习惯先把文件丢进7-Zip看一眼压缩比或者直接交给FFDEC它会自动解压。真正关心的是其中一个标签DoABC。几乎所有AS3代码都挂在这个标签下面找到它就等于找到了整个游戏的逻辑核心。如果文件头是FWS那直接用010 Editor在标签区搜DoABC四个字节也能定位到只是CWS压缩状态下看不见明文所以最佳路径还是先反编译。2.2 第一次反编译怎么下手把SWF拖进FFDEC等待左侧脚本树加载。界面左侧主线是脚本目录下面按类展开右侧是当前类的属性、方法和反编译代码。第一眼可能觉得类很多我的习惯是先在顶部的搜索里输入关键词而不是一个个翻。常用关键词SharedObject、save、load、data、encode、decode。这一轮搜下来基本能定位存档相关类的位置。如果文件偏大可以右击某标签选择只加载脚本树避免渲染图片时卡顿。FFDEC还有一个反编译P-code和显示AS3源码切换按钮平时默认看AS3源码就行遇到反编译露馅的地方再切成P-code逐条看字节码。第一轮分析的目标不是看懂全部代码而是把这些类和函数的地图画出来谁来调用它、几个入口、数据流向哪里。有了这张地图后面的还原工作才不至于迷路。2.3 快速定位存档相关类这次的搜索结果里出现一个叫GameSaveHelper的类为避免涉及具体项目类名做了简化处理里面两个主要方法saveGame和loadGame。方法内部调用了SharedObject.getLocal(game_save_01)一眼就知道这是游戏档的载体。顺着代码往下看saveGame做的事情很清晰把对象的属性按顺序写入一个ByteArray然后对这个ByteArray执行一系列操作最后把结果转成字符串写进SharedObject。loadGame就是逆向操作。到这里存档的存储位置基本确定剩下的工作就是弄明白ByteArray被怎么处理。这里有个小提醒反编译出来的代码偶尔会多出编译器自动生成的临时代码比如一些局部变量被拆成好几行判断读的时候不要被干扰。重点关注的是数据流转链路不是每一行都要看得懂。我通常会先看一眼类名看一遍属性列表再看看方法的入参和返回类型最后才进入方法体深读。这种方法比从头到尾硬读一整段代码高效得多。3. 存档加密的还原过程3.1 存档读写入口的代码结构先给一个简化到只剩骨架的示意代码帮助你理解后面要操作什么public function loadGame(): ByteArray { var so: SharedObject SharedObject.getLocal(game_save_01); if (so.data.raw null) return null; // 第一步还原成二进制 var bytes: ByteArray Base64.decode(so.data.raw as String); // 第二步逐字节异或 var key: ByteArray this.makeKey(); for (var i: int 0; i bytes.length; i) { bytes[i] ^ key[i % key.length]; } // 第三步解压 bytes.uncompress(); return bytes; }读这段代码的时候有几个点容易忽略。第一Base64.decode返回的ByteArray默认是网络序还是主机序不同引擎实现不同这个直接影响下面异或循环的顺序但当你用Python复现时统一按小端处理一般没问题。第二SharedObject取名和版本号经常有关游戏更新一次就会换个名字然后老档就失效了——很多玩家更新以后进度没了就是这么来的。第三uncompress对应的压缩格式默认是zlibPython里直接用zlib.decompress就能对上。3.2 从乱码数据里认出加密套路看清那个sharedObject里存的raw数据时第一反应是Base64因为字符串里只有大小写字母、数字、加号和斜杠末尾还有一个等号。这种特征太明显。顺手写一个Base64解码脚本解码出来的字节序列开头几个字节是0x78 0x9C——这几乎是zlib压缩格式的指纹说明开发者先把对象序列化又压缩然后再Base64编码。如果只到这一步存档其实没加密只是编码了。继续往下才发现真正的加密藏在另一层。解码Base64后的数据前面几十个字节看着有规律中间却乱得完全不像压缩流还有个无法解释的短重复周期。用已知明文试探一下正常情况下游戏会把玩家名称字符串写进取档我把Base64解开的二进制和名词典中的明文做异或几个字节对上了。这说明在Base64和压缩之间还夹了一次异或操作。整个处理链应该是序列化 - 压缩 - 异或 - Base64。反编译代码里makeKey()位置也印证了这一点密钥来自一个固定算法和游戏版本号强绑定。3.3 用Python把解密流程复现出来加了异或之后事情反而好办了。搞清楚顺序逆向就变成了正向脚本。下面这个Python函数就是我当时用来解档的你可以直接套用import base64 import zlib # 密钥由makeKey()生成这里简化成一个ByteArray # 实际场景请从反编译代码中提取密钥生成逻辑 key bKEY_SUBSTITUTE def decode_save(raw: str) - bytes: # 第4步逆向Base64解码 data base64.b64decode(raw) # 第3步逆向逐字节异或还原 buf bytearray(len(data)) for i in range(len(data)): buf[i] data[i] ^ key[i % len(key)] # 第2步逆向解压 return zlib.decompress(bytes(buf)) # 从SharedObject的sol文件或者游戏导出窗口里复制出raw字符串 saved_raw 在这里粘贴你从sol文件里复制出来的存档字符串 print(decode_save(saved_raw).decode(utf-8, errorsignore))运行之后终端里打出了玩家名称、金币数、关卡ID、道具列表。那一刻的感觉很奇妙一个快被遗忘的老游戏里面存的进度就这么被还原成了肉眼可读的文本。脚本跑通只是第一步我还顺手把它改成加密方向用负负得正的方式把新档写了回去再塞进SharedObject的sol文件里游戏顺利读取了新进度。要注意的是写回前最好备份原sol文件因为格式稍微错一位都可能把整个档整废。4. 实操中的坑与排查方法4.1 反编译结果残缺时怎么办FFDEC并不是总能100%还原方法体尤其是当代码里用了大量动态特性比如反射或者自定义命名空间。这时候AS3视图里可能只看到一行代码或者一个空壳。我的做法是切到P-code视图直接找指令段。AS3字节码虽然也抽象但里面每一行都对应一个实际操作比反编译结果可靠得多。那个类名乱成一团的情况也可以从P-code里的getlex指令找出真正引用的常量名从而定位到实际类。如果你发现某个类根本不在脚本树里那可能是它被藏在了别的DoABC标签下或者被放进了资源目录中的二进制数据标签。FFDEC有个功能是解析所有DoABC需要手动点一下脚本树根节点附近的设置。某个SWF如果加载了外部SWF主文件里常常只留了一个加载器桩真正的逻辑得去找它运行时加载的那个子文件这个在平台场景里很容易踩坑。4.2 字符串搜索找不到目标数据我在打开第二个游戏文件时就遇到了这种情况搜SharedObject完全没有结果。后来发现开发者把所有关键字符串都做了拼装处理比如把Shared和Object拆开运行时再相加或者在字符中间插入转义码。搜索时你可以换几个更长的关键片段在常量池里找或者直接搜方法名。常量池里往往保留着所有类和字符串的明文记录只要方法名没有被动态重新生成就能搜到。另一个常见情况是字符串本身经过编码处理比如转成\uXXXX的Unicode序列。FFDEC的搜索结果会把这类显示成\u开始的一串字符乍看不直观但你用编码解码工具转回来再拼出原词去搜基本就能命中。总之不要只依赖一种搜索表达式多换几个角度试探比盲目翻代码效率高得多。4.3 运行时调试和Flash版本兼容静态分析够用之后有时我还想确认某个函数的实际返回值。老Flash游戏在现在跑起来最大的障碍是浏览器不再支持Flash插件解决办法是装Flash Player Projector独立版它不依赖浏览器双击就能运行SWF。配合调试版还能输出trace信息。启用方式是在运行目录下放一个mm.cfg里面写一行TraceOutputFileNamelog.txt比如这样TraceOutputFileNamelog.txt然后在代码里或反编译补丁里调用trace(...)运行结束后打开log.txt就能看到输出。这个环节最头疼的是版本兼容。一些老SWF是用Flash 6-8时代的AS2写的用新版Projector运行可能会白屏或报错这时候要装对应年代的独立播放器。我电脑上就常备几个版本遇到不兼容就换。另外如果你把修改过的SWF重新导出到游戏里要先把原文件复制出来备份导出的SWF可能会因为工具链优化出现微小的行为变化排查半天可能只是这个原因。5. 合规边界与技能延伸5.1 什么场景可以逆向什么不能碰这部分必须单独拎出来说。逆向本身是中性技术但落到具体行为上有明显边界。可以做的是对自己合法持有的本地文件做技术分析比如这次恢复存档对开源或者授权范围内的代码学习原理在漏洞挖掘流程里对目标系统做合规评估。不能做的是破解商业软件的付费授权绕过账号验证提取并分发他人版权素材用于商用或者做游戏外挂。我在这次分析里没有碰任何授权保护机制存档加密只是数据编排方式不承担版权保护职责所以整个过程都在学习研究的合理范围内。这也提醒读者拿到任何一个SWF先想清楚自己有没有权限分析它以及分析成果是否会造成侵权或破坏。边界遵守得好这个技能能帮你处理很多实际问题走得偏了可能会惹上麻烦。技术本身没有善恶怎么用才是关键。5.2 这次分析长出来的可迁移技能这一整套流程不只是解决一个存档问题它更像一个完整的方法论识别文件格式 - 建立工具链 - 静态拆解 - 特征识别 - 算法还原 - 结果验证。这套流程在分析恶意SWF样本、查看老游戏的资源包、甚至分析某些移动端性能问题时都能复用。尤其是从乱码中辨识Base64和zlib指纹这一招在很多场景里都用到过。比如后来我在处理一个移动端游戏资源时也干了类似的事。游戏资源目录里有一批看似乱码的二进制文件用同样方法定位到zlib头部一把解压就把贴图和音频导了出来。虽然问题和SWF没有直接关系但思路完全是相通的。所以说逆向分析练习最值钱的不是某个具体结论而是那种先观察、再假设、最后用脚本验证的经验积累。这个习惯一旦养成遇到任何不透明的数据你都敢拆开看看。最后说点这次过程之外的体会。那次逆向的最终结论其实简单得很——一个Base64加异或再加zlib的套壳密钥藏在版本号旁边。但真正让我感慨的是一个快被遗忘的老游戏开发者在存档校验上竟然也写了三层处理说明当时的小游戏团队并不像大家想的那样都是敷衍了事。你要是手里也有类似的老Flash文件先别急着删也别急着四处找存档修改器。拿FFDEC拆一遍花一个下午把它的数据链路摸清楚你收获的会比游戏进度多得多。如果只是想单纯迁移存档不用走整个逆向流程直接把本机SharedObject对应sol文件复制过去更快。但如果你想搞明白它里面到底藏了什么那还是老老实实按上面的步骤走一遍吧。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑