物华弥新的文件经常更新加密,大佬能否出个相关教程
前排提示:(转载请注明出处。)
本帖的核心方法是朴实无华的穷举法,需要费点功夫。
本帖基于公开资料整理而来,基本只有理论,无开箱即用工具。
不适合纯新手,有一定阅读门槛;不适合会逆向的人,因为穷举有点浪费。
能力有限,暂时没有更简明的方案,只具有理论正确性,欢迎指正。
0.后编
我看到您在另一篇帖子的回复,发现如果我在A.彩蛋的图A.1中所有的猜测准确的话,密钥的位置没有变,加密区的起始字节位置索引也没有变,只有加密区的终止字节的位置索引变化了,当然这一切基于我猜测的结果是准确的基础上。
1. 概述
目前,解只需确定位置索引,当前版本的任意一个文件得到的位置索引适配于当前版本的文件。整体难点就两个,一是确定密钥位置,二是确定加密区域位置。逆向肯定是更准确,此处只给出在不逆向的情况下的穷举思路。
2. 基本信息
2.1 关于文件
通过资料分析法,可以基本确定:
①文件的密钥可能就在该文件内且在所有文件的同一位置(因为公开的资料都指明一个版本的文件的密钥位置是固定的,而我猜密钥内容可能是变化的);
②文件只有部分内容加密,加密采用了异或算法;
③可能只需确定一次加密区起始和结束位置,就可以将该位置套用到当前版本的所有文件。
2.2 关于结构
Asset Bundle 是 LZ4/LZMA 压缩的二进制文件,包含Header(文件标识、版本、压缩类型等),Block List(数据块索引(大小、偏移量)),Data Blocks(实际压缩数据),Directory(资源路径和元数据)。
Asset Studio在导入未解密文件时,总是提示读写、解压相关的错误提示,可以认为加密区基本在Block List区域。
基于标准未加密Asset Bundle的结构特征分析:
①总有相对稳定能确定的明文(对于文件来说,这段明文只有头是完全稳定确定的,后续会反复提到,以后出现的明文都指该明文或该明文的部分),这是可以尝试枚举解密出该明文进而确定密钥的基础;
②待处理区域(Block List区域的子集)也可以大致确定。
3. 步骤拆解
3.1 确定密钥
基于前述信息,在待处理区域用字节枚举异或解密(我推测密钥大概率在该区域,可以分区域进行,先尝试该区域的字节),直到找到能解密出该稳定明文的字节,即正确的密钥。在待处理区域从前往后开始匹配,找到密钥在文件的位置,可以多试几个文件,观察相同的位置字节与实际枚举成功的结果比较是否相符,务必确保万无一失,这是后面确定加密区间的基础。
3.2 确定加密区
基于前述信息和公开资料,虽然可以缩小一些范围,但为了灵活,接下来还是采用枚举,每次固定一个起始位置,用密钥异或解密逐个字节解密并尝试用Asset Studio(或者其他支持LZ4/LZMA 解压测试的工具)打开,根据返回结果,遍历待处理区的字节,查找加密区终止位置,然后移动起始位置,重复操作,直至确定加密区(起始位置和终止位置),而待处理区的长度是有限的,故有限次内一定能确定加密区起始和终止位置。(必须要把加密区完全解密才行,不要只解密加密区首尾。)
当然,我推测加密区起始位置在确定密钥的明文前面,因为根据公开资料不可直接观察到该明文。而除去这部分明文,待处理区留待测试的位置其实没多少,而且由于至少要让该明文完整暴露,加密区的终止位置也在一个相对更小的范围内,甚至部分文件的明文在文件中会完整出现。
4. 总结
感觉人工推理密钥和加密区也行,因为密钥不会是空字符0x00(这是因为与空字符异或后还是原值,相当于没加密,这篇帖子就没必要存在),而空字符在待解密区还是比较多的,通过分析字节字符出现的频率都能大概确定一个或几个备选密钥,故只需要会对字节异或运算就行。但要解密所有文件最好要会写脚本工具(当然,不是必需要您本人会)。
多费些功夫和AI辅助应该都能解决,实际上本帖就是在分析文件压缩结构后,穷举解出结果。
如果加密逻辑没有翻天覆地的变化,应该都是能解出来的。如果有那么一天,再重新分析样本吧。
先感谢提供公开资料的各位,也留一个我推理的结果作为彩蛋。
A. 彩蛋
图A.1所示结果仅为推测,由于加解密文件的方式随版本略有变化,请注意时效性,目前只需要套用位置异或解密即可,但我觉得我猜的也符合公开资料的解密加密区位置变化的大致规律,应该没啥大问题,最多移动前后几个字节位置,可以自行检验,如有错误,概不负责。
根据我的推理,红色标注为该样本文件的密钥0x6D(对应字符为m)。若要使用,需要转换为对应位置的索引或次序。给到我的样本文件应该是最近最新的,这个推测结果对应的位置目前应该还是可用可验证的。
关于明文,我没有直接透露
请见A. 彩蛋,从图A.1 中推理,或者请见2.2 关于结构,从与标准未加密Asset Bundle比较中得出。
关于待处理区,我没有直接透露
请见A. 彩蛋,从图A.1 中推理,或者请见2.2 关于结构,从与标准未加密Asset Bundle比较中得出。不强求因为这个可以宽泛一点。
感谢您的指点,我目前基本掌握了 ![]()
根据 物华弥新解包求助 - #57,来自 AXiX_Official 大佬发的
import sys
if name == ‘main’:
inPath = sys.argv[1]
outPath = sys.argv[2]
with open(inPath, ‘rb’) as f:
data = bytearray(f.read())
key = data[51]
for i in range(50, 115):
data[i] ^= key
with open(outPath, ‘wb’) as f:
f.write(data)
并结合VivaLaze大佬的指点
本人实际操作后大致总结:
官方的加密大概是每次多加密一个字节,密钥和加密位置的首字节不变,也就是
key = data[51]
for i in range(50, 115):
里面的51和50两个值不变,只需要修改"115"的数值,具体改成多少可以通过二进制查看游戏文件


