CelestialCosmic / themeblog

blog articles by Celestial_Cosmic,source code by chanshiyucx
1 stars 0 forks source link

roguelike 逆向(二) #51

Open CelestialCosmic opened 5 months ago

CelestialCosmic commented 5 months ago

本文为两年前 roughlike 逆向(一)的后续

起源

两年过去了,游戏作者居然有更新,有别的作品,还发掘到了一些我之前所不知道的秘密

虽然这作已经停止了开发,但最后一个版本起码中文是有了的,但其实我也能看懂基本日文了......除此之外,新作还在积极更新,今年 12 月甚至还要发作品!借助他人的存档、留言和文件,两年前留下的各类资料、工具融合新的经验与经历,我将通过分析十六进制存档和反汇编后的程序来挖掘以前不知道的信息

只可惜了我以前花了起码十几个小时造的那个超级畜生的饰品的存档读不了了(翻了翻又找回来了,好耶)

存档数据

我翻出了我所有的存档,几番翻找后,最终找到了三个各有特色的存档,外加从论坛上下的别人的存档,丰富性足够了:

存档名 时间 备注
save_03.dat 2021/04/10 100% 完成度 + 绝大多数 30级服装
save_04.dat 2022/08/15 80% 完成度 + 究极厨圣装备
save_15.dat 2021/12/15 100% 完成度

两年前玩的时候(居然最老的档有三年了),那时候就知道存档是十六进制的,也修改出了一些东西,但因为学艺不精,导致了一次坏档,所以最后游戏生命结束的时候,装备和完成度分别存在于两个存档上,还有一个存档只解锁了 CG

不论如何,让我们再试一次吧

还有 2021 年 12 月留下的资料,现在也能派上用场

通关记录

我的存档因为天神下凡的缘故,通关记录甚少,但游戏时间甚多,不过还好从论坛上下下来的存档的原档主则是实实在在打了十几个小时,数据很脏,也因此非常有辨识度

借助旧的资料、新的存档和新的观察,我得到了结果

二进制地址 对应关系
00-03 未知
04-07 时间(time32_t)
F4-FF 施工现场(int8,int8,int8)
100-107 未知(int8,int8)
108-113 商店街(int8,int8,int8)
114-11B 未知(int8,int8)
11C-127 临村之森(int8,int8,int8)
128-12F 未知(int8,int8)
130-13B 进街大道(int8,int8,int8)
134-143 未知(int8,int8)
144-14F 萨达拉图书馆(int8,int8,int8)
150-157 未知(int8,int8)
158-163 往孤岛的航路(int8,int8,int8)
164-16B 未知(int8,int8)
16C-177 炼金术研究所(int8,int8,int8)
178-17F 未知(int8,int8)
180-18B 临村之森 EX(int8,int8,int8)
18C-193 未知(int8,int8)
194-19F 工厂(int8,int8,int8)
1A0-1A7 未知(int8,int8)
1A8-1B3 往孤岛的航路EX(int8,int8,int8)
1B4-1BB 未知(int8,int8)
1BC-1C7 风奈山(int8,int8,int8)
1C8-1CF 未知(int8,int8)
1D0-1DB 哈斯诺岳 EX(int8,int8,int8)
1DC-1E3 未知(int8,int8)
1E4-1EF 风音小学(int8,int8,int8)
1F0-1F7 未知(int8,int8)
1F8-203 迷宫最深处(int8,int8,int8)
204-20B 未知(int8,int8)
20C-217 哥布林巢穴 EX(int8,int8,int8)
218-21F 未知(int8,int8)
220-22B 地狱次元 EX(int8,int8,int8)

关卡的三个 int8 分别是挑战次数、进度、通关次数 另外,存档内先排的普通关再排 EX 也是出乎意料的

每段关卡后面附带的00 00 00 00 04 00 00 00目的未知

也暂时不知道特典地牢(论坛中提到的三个 key 的新地图)是什么,但是新加的怪已经出现在衣服里面了,这个是实实在在看得到的

服装等级

很久以前,我通过修改 FF 的方式把很多衣服的点都做成了 30/30,但时过境迁,那些存档修改为 FF 的存档已经用不了了,能用的 30/30 也已经不是 FF 形态了,之前留下来的资料中揭示的地址也是没法用的......

所以这方面的工作只能重新开始

通过修改启用等级,发现启用是从文件末端,以 78 为界的下一个 int8 开始的,直到 EOF 都是启用段

又发现前面还有一个 78,那是不是那部分就是等级上限呢?

修改了一下,发现确实是,又搜索了一下,发现只有两个 78

也就意味着,在文件中有两段 第一个 78 开始到第二个 78 记录的是服装的等级 第二个 78 到 EOF 则记录服装的是启用的等级

我将数值从 00 00 00 00 修改为 FF 00 00 00,发现只变成了 15 级,改成 FF FF 00 00 才叠满 30 级

道具

除了那个合成了非常厨圣的道具的档以外,我注意到新存档都拿到了十几个带着各种强力新词条的顶级道具......不会有人不想要吧(

所以我开始尝试迁移旧背包的内容过去。为了比对背包,我拆了背包里面的所有消耗品,看看物品是如何记录的,些许尝试后发现它们是以列表的形式存放的,而物品移动也只是在存档里换了个位置,看不出来背包和库存间有什么关系,只是在比较过程中发现了开头存在一个 int 是存放物品数量的,可能与数组长度有关

头疼,最终我把背包里面所有的物品全拆了,只留了那件装备,然后试图通过把背包复制过去来进行物品迁移,然后我又创了个新档,然后将背包区段完全删除,再将这段重新插入,这次成功了,也是这晚上唯一一次成功

在新档的情况下,230-253 是一段未知的内容,从 254 开始直到衣服那段就是背包

物品也慢慢摸出了规律:

19 00 00 00 ;装备 id
45 00 4E 00 43 00 48 00 41 00 4E 00 54 00 5F 00 50 00 52 00 45 00 46 00 49 00 58 00 5F 00 41 00 44 00 44 00 5F 00 45 00 50 00 5F 00 55 00 2D 00 2D 00 04 00 00 00 05  ;强化大类
00 00 00 D9 FF FF FF 07 ;强化数值 1,强化小类 1
00 00 00 C7 FF FF FF 08 ;强化数值 2,强化小类 2
00 00 00 F5 FF FF FF 59 ;强化数值 3,强化小类 3
00 00 00 F2 FF FF FF 18 ;强化数值 4,强化小类 4

这个我没看到源代码怎么写的,上面只是猜测,可能并不准确

int8 物品id enchant_perfix 标记加强类 然后是一个特殊结构:00 00 00 AA FF FF FF BB,其中 00 00 00 AA 是数值(如果是负数就会在游戏内以负面状态显示),FF FF FF BB 是类型,借此我成功地修改了装备的数值

弄了一晚上唯一的好消息是定位到了游戏读取的 access violation ,根据计算,这个位置在 game.exe+D37C0 意味着这个位置可能与存档读取有关,但此时已经一点了,只能第二天上班再去逆

然后第二天发现也不是这么回事......但是突然我的脑中跳出了一个主意:牺牲一个满级饰品,然后只粘贴它的强化项,把这件装备“借尸还魂”

一开始的测试结果还是崩溃

最终我把所有顶级饰品全拆了然后另外存了个档,发现其实装备的词条居然还在存档里面,但是那些装备 id 的 int 全部变成了0!此时如果再去把装备 id 写回去,就能得回那个位置的装备

那这下思路就清晰了,我如法炮制,将那件装备也拆了,存档然后比较了两存档间不一样的部分,再加上几番操作,终于把新装备嫁接进去了!

通过两天大概七八个小时(光 x64dbg 就有 5 小时的记录)的工作,我得出了如下方法:

一定要备份存档!此处记转出的存档和转入的存档分别为存档 A 和 存档 B 如果 A 存档之前有拆别的装备,首先用十六进制编辑器清洗掉无关的词条再存档,此时存档会比原来干净很多

  1. 在两个档中都将装备放在一个位置,建议是背包一号位
  2. B 档在一号位和二号位放入两件装备,存档一份,然后拆掉这两件装备,存档并备份
  3. A 档只保留那件装备,存档一份,然后拆掉这件装备,存档并备份
  4. 比较 A 档的两个档之间的差距,复制第一件装备的十六进制
  5. 比较 B 档的两个档之间的差距,将第一件装备的内存空间用第二件装备替代
  6. 此时读取存档应该就可以看到被转移的装备了

最终,以一个兔子戒指为代价,成功合并存档!

最后总结一下:游戏中装备的存储是连在一起的,以 id 开头,接加强类,然后是具体加强类型,再是数值

另外,不要尝试在存档中新加装备,这样的处理要么不读取,要么崩溃,去地牢随便捡一个回来再替,这个思路坑了我不少的工作时间

x64dbg 中报告的字符串

x32dbg 中显示字符串中有十几段与游戏运行数值高度相关的东西:

地址 字符串
001318E2 L"LV:"
0013197E L"EXP:"
00131A18 L"MANA:"
00131B78 L"HP:"
00131CDD L"MP:"
00131EE8 L"EP:"
00131F93 L"ATK:"
00132081 L"DEF:"
001321A3 L"SPD:"
001322A6 L"Resistance:"

后面还有,再写就太长了,这些虽然说明不了什么,但至少根据经验能看出来奏和怪物拥有同一个类......以前做 ct 表的时候也早就知道奏和怪物是共享一个伤害函数的,也就是伤害函数是和实体类一起的

逃脱与崩溃读条

束缚一直是个很头大的地方,上次就没有弄出来,因为我对它所使用的数据类型和变量大小一无所知,通过 CE 都难以追踪的变量

但这次上天赏饭吃,我之前定位了奏的角色类地址,把内存视图放在那块上,她又在拘束状态和崩溃状态读条的状态下,我正操作着想摆脱拘束,却正好给我看到了一块一直在跳动的内存,注意到那块内存以后,我随手故意地不规律操作了一下,突然发现这块内存随着我的操作而变动!我赶忙把它从内存里面扣出来加到 ct 表里面,又把数据类型轮流试了一遍,发现它是一个单浮点数类型的束缚!

将值锁到 100 时,在还有血的前提下,只要进行些许挣扎,即便已经崩溃读条满了也能强制脱出,而且只要逃脱读条锁了 100 崩溃读条还会循环读条!终于不用担心 99 级时开箱子被宝箱怪吞了

又尝试了锁到 999,发现控制就和秒解净化一样,但还是会倒地的,依旧需要手动帮她站起来

发现了这个犹如发现了新大陆,崩溃的读条想必就在附近!

因为循环崩溃读条的特点,但是因为上一个值是单浮点数的惯性思维,稍微费了点功夫,找到了崩溃读条,其实它就在逃脱读条 +4 的位置,但一直认为它也同样是浮点数所以一直没认出来,然而奇怪的是,它却不是浮点数,而是一个上限为 200 的 4 字节......

把这个解决了以后,被压住还是会被搞,不过起码大数值是没有了

高兴之余,还无奈地发现,在被大量敌人围住的情况下,哪怕天神下凡到这个程度,奏还是站不起来的......有例外,但总之被弄个十几轮才能挥一刀就是了

做这两个数值吃了 8 级的精和 4 级的史莱姆、4 级的史莱姆苗床......是我太菜了