感谢CODEX5.4的正确结果hhh
这份文档不是只给结论,而是按一次可复现的逆向过程来写,
目标是带着样本结构一路走到 freemote 所需的 -k / -l 参数。
这次样本的最终验证结果是:
-k 38757621acf82-l 131
验证命令:
.\tool\freemote\PsbDecompile.exe info-psb -k 38757621acf82 -l 131 .\压缩包\image_info.psb.m -o .\out_try
实际结果:
- 成功提取
837个文件
但重点不是记住这两个值,而是知道为什么它们就是答案。
1. 先做题目画像
样本目录里最重要的对象有三个:
main.elf压缩包\image_info.psb.m压缩包\image_body.bin
第一眼要先判断三者的分工。
1.1 我的初始假设
结合你给的线索:
- ELF
- krkr / e-mote / PSB
freemote-k-l
我一开始的高优先级假设是:
main.elf是游戏主程序或者资源加载器,不是单独的小工具。.psb.m和body.bin是一对资源容器,可能是 info/body 配对。-k和-l更可能来自程序初始化时设置的资源解密参数,而不是文件头里直接明文摆着。
这个判断背后的原因很简单:
- 如果
freemote需要参数,说明资源不是裸 PSB。 - 如果资源不是裸 PSB,最可靠的参数来源往往是“程序自己怎么初始化解密器”。
2. 第一轮:不进反编译,先看文件头
这一步的目标只有一个:
- 判断
.m和.bin是不是已经加了壳
这次我直接看了前 128 字节。
2.1 image_info.psb.m 文件头
00000000 6D 64 66 00 ...
2.2 image_body.bin 文件头
00000000 6D 64 66 00 ...
这里最关键的 4 个字节是:
6D 64 66 00- ASCII 就是
mdf\0
2.3 这一步为什么关键
很多人看到 .psb.m 会下意识以为是“已经是 PSB,只是后缀特殊”。
但这个样本不是。
它的外层是 MDF,不是裸 PSB。
这意味着:
freemote的参数不是“可选增强项”,而是解开外层封装的必要条件。- 如果你一开始去硬看 PSB 结构、字段表、对象树,很可能浪费时间。
3. 第二轮:先把工具参数语义搞清楚
这一步非常重要,因为如果你连参数含义都理解错,后面整条线都会偏。
我直接看了本地 freemote 的帮助。
命令:
.\tool\freemote\PsbDecompile.exe --help
.\tool\freemote\PsbDecompile.exe info-psb --help
得到的关键信息是:
-k|--key <KEY>: Set key-l|--length <LEN>: Set key length. Default=131-s|--seed <SEED>: Set MT19937 MDF seed
4. 这一步帮我们排除了什么
一开始最容易误判的是:
- 把
-l当成 label - 把
-l当成资源名 - 把
-l当成 level
但 freemote 已经把语义写死了:
-l是 key length
所以后面在 ELF 里要找的,不再是“某个 label 字符串”,而是:
- 一个 key
- 一个 key length
- 可能还有 seed
5. 第三轮:判断 ELF 是什么程序
这一步不是为了炫架构知识,而是为了决定后面是走静态优先,还是动态优先。
我先读了 ELF 头。
结论:
- ELF64
- little-endian
e_machine = 0xB7
0xB7 对应:
- AArch64
再结合字符串区里大量出现:
NintendoSDKnn::gfxnn::vi
可以进一步判断:
- 这基本是 Nintendo Switch 游戏程序
6. 这个判断有什么实际意义
它直接影响策略:
- 这不是一份适合本机直接跑的普通 Linux x64 ELF。
- 动态分析不是不能做,但成本比静态高。
- 优先级应当是:先利用已保留的符号、字符串、IDA 数据库把资源链扣出来。
换句话说,这题最短路不是先上 gdb,而是先找“谁设置了资源加密参数”。
7. 第四轮:从字符串和符号切资源加载链
这一步开始进入真正的样本相关分析。
我重点搜了这些词:
psbPSBObjectFetchResourceLoadResourceMountArchivebody.bininfo.psb.mkeyseed
命中的高价值结果有:
script_info.psb.mscript_body.binMFile::MountArchiveResourceManager::FetchResourceSQPSBFilePSBObject
7.1 为什么 script_info.psb.m / script_body.bin 非常关键
因为这不是我们根据文件名在外部猜出来的。
它们出现在程序自己的字符串区里,说明:
- 程序内部确实采用了
info.psb.m + body.bin配对归档的加载范式
这会让你对 image_info.psb.m + image_body.bin 的判断更有把握。
8. 第五轮:追交叉引用,不要泛追,要追主流程
我追了 script_info.psb.m 和 script_body.bin 的交叉引用,最后命中了:
M2Main- 地址
0x17960
这是全题最关键的一步。
因为一旦你在主流程里看到:
- 先设置 crypt
- 再挂载 archive
那基本就离答案只差一次验证了。
9. 核心证据:M2Main 里的初始化逻辑
反编译结果里最重要的伪代码片段是:
strcpy((char *)v136 + 1, "38757621acf82");
MFile::SetCryptSetting(v136, 131);
strcpy(..., "script_info.psb.m");
strcpy(..., "script_body.bin");
MFile::MountArchive(v136, v134, &v132, 1);
这段逻辑应该怎么读:
- 程序启动时先准备一个字符串
38757621acf82 - 调用
MFile::SetCryptSetting(..., 131) - 再去挂载
script_info.psb.m和script_body.bin
这就说明:
- 这组 crypt setting 是 archive 挂载前必须设置的
- 它不是某个后期资源临时派生值
- 它就是资源系统自己的初始化参数
10. 为什么我认为这就是 freemote 的答案
理由不是一个,而是三个同时成立:
10.1 语义对得上
freemote 需要:
- key
- key length
程序里正好有:
- 一个 key 样式的字符串
- 一个长度值
131
10.2 时机对得上
这个设置发生在:
MountArchive之前
也就是说它是资源系统基础配置,而不是某个无关字符串。
10.3 对象对得上
后面紧跟的就是:
script_info.psb.mscript_body.bin
这和你手头的:
image_info.psb.mimage_body.bin
属于同一类对象。
11. 最后一轮:必须回喂工具验证
逆向里最怕“看起来像答案”,所以必须实测。
我实际执行了:
.\tool\freemote\PsbDecompile.exe info-psb -k 38757621acf82 -l 131 .\压缩包\image_info.psb.m -o .\out_try
结果:
- 自动识别 body 文件:
image_body.bin - 成功提取
837个文件
这一步把整条推理链闭环了。
所以这题不是“推测大概如此”,而是:
- 已从 ELF 中定位参数来源
- 已用
freemote成功验证
12. 这题里我最看重的观察点
如果你以后自己做类似题,最值得优先盯住的是这些点。
12.1 文件头是不是已经说明“还有一层”
像这题:
mdf\0
这四个字节本身就告诉你:
- 先不要把它当裸 PSB
12.2 初始化函数里有没有“设 crypt 再 mount”
这类题最值钱的不是深处的解密循环,而是早期初始化代码。
因为真正的参数往往在这里直接落地。
12.3 info/body 成对文件名
一旦同时看到:
xxx_info.psb.mxxx_body.bin
就该马上联想到:
- archive 索引 + 资源正文
12.4 参数设置函数的形态
最像答案入口的函数通常长这样:
SetCryptSetting(key, len)SetKey(key, len)InitMdf(seed, len)MountArchive(info, body, ...)
12.5 数值 131
如果工具帮助里告诉你默认 -l = 131,而程序里又正好显式传 131,这个重合就非常值得重视。
13. 如果这次没这么顺,下一步应该怎么切
虽然这次已经成功,但你要知道卡住时怎么切线。
13.1 静态卡住
优先顺序:
- 先追
MountArchive - 再追
SetCryptSetting - 再追
FetchResource - 最后才去看具体解密循环
13.2 动态卡住
不要先断“解密循环”。
优先断:
SetCryptSettingMountArchive
因为这两个点更接近“参数生成”和“参数使用”的交界处。
13.3 样本结构反推
如果程序分析暂时做不下去,就先靠结构缩小范围:
.psb.m和body.bin是否配对- 两者是否同头
- 是否都为
mdf\0 freemote默认-l是否先尝试131
14. 这次题目的最终结论
从 main.elf 的主流程 M2Main 中,可以直接恢复出资源解密初始化参数:
key = 38757621acf82length = 131
对应到 freemote:
.\tool\freemote\PsbDecompile.exe info-psb -k 38757621acf82 -l 131 .\压缩包\image_info.psb.m -o .\out_try
并且已经成功提取。
15. 你下次自己做时的最短路线
如果你只记 5 步,记这 5 步:
- 先看
.m/.bin文件头 - 确认
freemote参数语义 - 在 ELF 里搜
MountArchive/SetCryptSetting - 追
info.psb.m/body.bin的交叉引用 - 拿到值后立刻回喂工具验证
这次样本就是按这条线打通的。