吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1736|回复: 17
上一主题 下一主题
收起左侧

[原创] 记录一次我把VB6 小游戏的存档扒光

  [复制链接]
跳转到指定楼层
楼主
a3341736201 发表于 2026-9-12 20:56 回帖奖励
本帖最后由 a3341736201 于 2026-9-12 21:52 编辑

记录一次我把VB6 小游戏的存档扒光

先说结论:这游戏一共俩文件,一个 几十KB 的 Test.exe,一个 俩排多来字节的 log.txt。就这点东西,我断断续续折腾了好几天,中间数次都想直接放弃,但是弄不出来,晚上睡觉都不得劲,上课的时候 都在想解密方法,最后是终于理顺了【作者在存档里埋了个校验和、一个彩蛋、两处随机数、还有对玩家姓名的一点小心思。200 个字符,信息密度顶我一整个周末】
写篇流水文章记录一下,文末有全套工具和完整格式表,想直接抄作业的往后翻。但是记得给我加评分
练手程序:::https://wwaxn.lanzout.com/ioBoQ47tw5eh 密码:7j8v

一、案发现场

游戏叫《进制转换Go》,一个练进制转换的小练习题集,VB6 做的,很怀旧。玩法就是弹个数,让你转成另一个进制打进去。

我对它动手的动机很朴素:想改分。

结果第一天就碰壁了。这存档长得实在不讲武德:

  • 大小 250 字节上下飘(247~259 都见过)
  • 但你按字符数,永远是 200 个字符 + 一个 CRLF
  • 内容既不是明文也不是规整的二进制,而像是把三种东西硬揉在一起

而且它防篡改防得很认真:改任意一个字节,再进游戏读档,它直接甩你一句

数据校验错误,请选择重新开始

好嘛,那就走流程吧。先刷样本。


二、啥也不说,先刷他 19 份存档

手动点最稳:新建角色 → 起名字 → 退出 → 点"是"保存。我点到第七个的时候开始怀疑人生,后来写了个自动化脚本替我点,开始踩坑了,后面懒得自己写,直接豆包干(PowerShell + SendInput 模拟真实按键,这里略过不表,都是泪)。

最后攒出十九份有效样本,覆盖不同姓名、不同游玩程度。然后把文件拖进 Python,逐字符铺开对齐看。

第一眼发现的东西是这位:

第 27 位(数字块内计数)永远是 '1'。

换了几份全是 1。我一度兴奋:这不会是版本号吧?

后来发现,第 49 位也永远是 '1'。

再后来,把 19 份样本按列做统计,才发现真相远比版本号有喜感——这先按下不表,往后看。


三、啃最硬的骨头:20 个校验字符

文件最后 20 个字符是校验区。这玩意挡了我最久。

断断续续逆了一晚上,把算法抠出来了。核心长这样:

对 i = 1..20:
    acc = 0
    for j = i .. i+40:
        acc = (acc + 109 + Asc(S[j]) % 67 + Asc(S[j+60]) % 23 + Asc(S[j+120]) % 19) % 96
    校验字符[i] = Chr(48 + acc)

S 是文件前 180 个字符。用 Python 抄一遍就能验证:

def srem(v, d):
    # VB6 的 Mod 是"向零截断",余数符号跟着被除数走
    r = abs(v) % d
    return r if v >= 0 else -r

def checksum(codes):  # codes: 前 180 个字符的字符码
    out = []
    for i in range(1, 21):
        acc = 0
        for j in range(i, i + 41):
            v1, v2, v3 = codes[j-1], codes[j-1+60], codes[j-1+120]
            acc = srem(acc + 109 + srem(v1, 67) + srem(v2, 23) + srem(v3, 19), 96)
        out.append(48 + acc)
    return out

拿全部有效样本跑:20/20 个校验字符全中。

为了反向验证,我还做了几份"变异样本":单字节改动后,失配数的分布是这样的——

变异位置 校验区失配数
前缀区(改 1 字节) 20 / 20
前缀区(另一处) 15
校验区自己(只改 1 个) 1

跟"这个位置被几个滑窗覆盖"的数学推算是完全对上的。到这里我基本可以宣布:这校验算法已经姓我了。

顺带说几个 VB6 的脏细节,坑了我一下午:

  • Asc() 对双字节汉字返回的是 16 位编码(有符号),所以 %67 这类运算要做有符号余数;
  • 生成的校验字符如果落在没法构成合法字符的值上,写进文件时会变成 '?'——不是报错,是静默替换,读档时也按 '?' 重算,所以依然自洽。

四、然后我发现了"你猜呢" 感觉被嘲笑了!

继续拆前面的部分。文件前 60 个字符是一坨单双字节混排的"乱码"。我寻思这大概就是加密后的姓名。

把 60 个字符按位置 mod 3 分成三组,各自统计分布,看聚簇:

组0的中心 ≈ 45762
组1的中心 ≈ 50392
组2的中心 ≈ 50403

这三个数字看着眼熟。丢进 GBK 一查——

  • 45762 = 猜
  • 50392 = 呢
  • 50403 = 你

好家伙。

填充料是"你猜呢"三个字,逐字做了 ±50 的随机偏移,重复 20 组硬凑满 60 个字符。

我又回去翻了翻 exe 的字符串表,果然在启动逻辑里躺着一句 你猜呢。行吧,作者是个有意思的人。这仨字我现在看着都觉得它在嘲笑我。


五、姓名到底藏哪了

彩蛋归彩蛋,玩家姓名还是得存的。继续对着样本找,发现规律很粗暴:

每隔 5 个字符,插一个姓名原文汉字。 完全没加密,明文。

比如你的名字叫"张伟",那么在某个 5 步长的位置序列上,会依次出现 张、伟 两个汉字;"测试小王"就是四个字各就各位。

不过这个序列的起点是随机的——它来自保存时生成的一个随机数 m(后面还会出场):

姓名插入链起点 = (4 − m) mod 60,  m = Int(Rnd()*30) + 5

所以每次保存,汉字的位置都会换地方。之前我有一瞬间觉得"汉字怎么以大概 10 字节的间隔散布",答案就是这个——一个汉字占 2 字节,加上空隙正好。


六、数字块:一场精心设计的填空游戏

中间 120 位数字是重头戏。用列统计法一照(19 份样本逐列数,看哪列的值域窄得不像随机数),发现了 7 个"受控位":

位置(文件字符) 内容 实测
第 78–79 位 随机字段 n 的两位十进制数 n = Int(Rnd()*20)+8,全样本落在 [8,27]
第 87 位 恒为 '1' 就是你最早发现的"第 27 位"
第 96 位 姓名长度 "测试小王"→4、"测试"→2
第 109 位 恒为 '1' 同胞兄弟
第 116–117 位 随机字段 m 的两位十进制数 m = Int(Rnd()*30)+5,落在 [5,34]

而其余的位置也不是自由发挥——反汇编里能直接看到它做了 6 段固定切片(代码里明晃晃写着 1/17、20/7、28/8、37/12、50/6、58/3 这几组字面量),切片之间正好被上面这 7 个位置隔开。拼满 60 位,一个不多一个不少。

好玩的是那个 m:我是先从不相关的线索(姓名链的起点)把 m 反推出来,再拿它去撞第 116–117 位那两位数字——全中。两条独立证据链咬死在同一个随机数上,这种瞬间是干这行最上头的时刻。


七、幽灵批次:S1 到 S8 的诡异事件

期间我用批处理脚本又造了 8 份样本(S1~S8),结果这 8 份行为怪怪的:

  • 第 96 位(姓名长度)恒为 3
  • 姓名链里全是没见过怪字

一度怀疑游戏还有隐藏分支。追了半天,把 S1 的姓名链字符按顺序连成字节:

E6 B5 8B E8 AF 95

眼熟。这是 "测试"两个字的 UTF-8 编码。

案情还原:那个批处理脚本存成了 UTF-8 无 BOM,PowerShell 5.1 按 GBK 读脚本,把 "测试" 读成了 "娴嬭瘯",然后把这三个字当姓名输进游戏了。游戏很无辜地把它存了下来,长度 3,于是"第 96 位恒 3"。

我盯着屏幕笑了半分钟。合着不是游戏的隐藏机制,是我自己脚本的锅。

各位 PowerShell 5.1 用户记住了:中文脚本要么存 GBK,要么带 BOM,不然你永远不知道自己输进去的是什么。


八、最后一厘米:上调试器,逮到那个 0

前面还留了个尾巴:第二段数字块的地方,反汇编里有一段逻辑——当某个数 N 大于 0 时,会每隔 6 位写一个 (n + N) % 10 的受控数字。

但奇怪的是:所有没玩过游戏的存档里,这段逻辑像从来没生效过,数字块纯随机。

那 N 到底是多少?代码说:它来自某个控件的文本,用 R8ValFromBstr 解析。反正不是 0 就是什么别的。

我盯着"某个控件"四个字看了很久,最后决定不猜了,直接抓现行。

用 64 位 Python 写了个迷你调试器去调这个 32 位小程序(中间踩的 WOW64 坑足够单开一篇:DEBUG_EVENT 的 union 在 64 位下偏移是 16 不是 12、32 位代码的断点异常码是 0x4000001F 不是 0x80000003、WOW64_CONTEXT 里 Eip 在 0xB8……),在写档函数里那个 fstp [esi+0xe8] 后面下了个断点。

游戏被我骗着正常操作了一遍,关窗、确认、写档——啪,断点命中。

N = [esi+0xe8] = 0.0
被解析的文本 = "0"   (直接从 BSTR 里读出来的)

N = 0,实锤。 没玩过的存档里,这个数字就是 0,那个 N > 0 的分支压根不执行,所以第二段数字块是 100% 纯随机——之前拟合不上的谜题到此闭合。

顺带这也解释了那两个恒 '1':它们是 Chr(Len(该显示文本)+48) 算出来的,显示文本现在是单字符 "0",所以是 '1'。

先立个预言:只要有办法让那个显示的数字变成两位数(比如玩一会儿让它涨上去),这两处就应该变成 '2'。评论区交给你们验证,验证错了欢迎来打我脸。


九、完整格式表(抄作业区)

梳理一下,200 个字符 = 60 + 120 + 20:

区间 内容
第 1–60 字符 "你猜呢"三字的 ±50 随机编码 × 20 组 + 姓名明文每 5 位一个(起点随机)
第 61–180 字符 两段 60 位数字流;第一段 = 6 段切片 + 7 处插入(两个随机字段的十进制、姓名长度、两个恒 '1')
第 181–200 字符 20 个校验字符(滑窗 41 次累加 mod 96,见上文算法)

校验算法就不重复贴了,往上翻第三节。

配套工具我也写好了(Python,无依赖):

python save_tool.py check  你的.log     # 校验完整性
python save_tool.py dump   你的.log     # 铺开看 60/120/20 三段明细
python save_tool.py checkdir 目录        # 批量校验

拿游戏里存的档直接跑,PASS/FAIL 一目了然。改过字节的档全被检出,和游戏里的报错行为完全一致。

比如把其中一份铺开看:

[60..179] 数字块 120 位:
   +  0: 623520763250404991058165131970542164515823961895110782034367
   + 60: 466692762256324092454907233323774056792546334429025152172574
   受控位 idx=17 (文件第 78 字符): 1  ← n 的十位
   受控位 idx=26 (文件第 87 字符): 1  ← 恒 '1'
   受控位 idx=35 (文件第 96 字符): 4  ← 姓名长度
   解码: n=[0x104]=10 (在 [8,27] 范围内 ✓)   m=[0x106]=34 (在 [5,34] 范围内 ✓)
[180..199] 校验块: fNYz?PgJ@2OQe4P?GKUC
  校验:PASS(20/20 校验字符一致)——数据完整

当然还有改分器一并打包给你们 在一个压缩包!!
进制转换Go-存档工具包.zip (9.55 KB, 下载次数: 12)


十、后记

回头看看这 200 个字符:

一个彩蛋("你猜呢")、一个校验和、两处随机数、一处姓名长度,还有一段给"玩过的玩家"准备的受控数字——但这游戏主要是给没玩过的人做练习的,那段逻辑大部分人一辈子也碰不到几次。

你说这算加密吗?算不上,全场最大的"密钥"是三个字的彩蛋。

你说这不加密吧,它又能防住所有想改分数的人。

这大概就是 VB6 年代小游戏作者的一种浪漫:明明就是个练习小程序,存档还是要给你整上全套仪式感。

最后,感谢这位不知名的作者,也感谢你没给游戏加壳——不然这篇文章就没有后半段了。


最后,感谢关注+评分,期待有更多好的作品文章能够带给大家,谢谢!

免费评分

参与人数 4吾爱币 +2 热心值 +3 收起 理由
丶七年 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
dgjbn + 1 谢谢@Thanks!
Issacclark1 + 1 谢谢@Thanks!
BCDHY + 1 谢谢@Thanks!

查看全部评分

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

沙发
BCDHY 发表于 2026-9-12 21:03
太强了思路方法和过程都很详细,受教了
3#
Turbo86 发表于 2026-9-12 21:12
4#
zdyzzgdnnyx 发表于 2026-9-12 21:29
5#
 楼主| a3341736201 发表于 2026-9-12 21:39 |楼主
zdyzzgdnnyx 发表于 2026-9-12 21:29
lz,如果用ce行不行,这个好难啊

没试过,不过理论 可以,改了之后 ,保存,校验只要对了,就可以成功
6#
semiuel 发表于 2026-9-12 21:45
很久以前我们用FPE2000修改游戏。
7#
fqhs 发表于 2026-9-12 22:18
这么厉害?受教了
8#
why12 发表于 2026-9-13 07:06
这个可以,思路清晰!
9#
vtf007 发表于 2026-9-13 11:30
学习下思路,受益匪浅
10#
nig0414 发表于 2026-9-13 12:17
感谢思路!让我想起之前没改成的一个游戏,回头有时间再改改看
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-10-13 08:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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