unity bundle
/ 4 min read
当我们运行examine_texture2d.py
脚本时,我们发现了一个重要的发现:虽然我们最初认为目标角色代码可能存储在Texture2D对象中,但实际上它们存储在各种不同类型的对象中,包括TextAsset、MonoBehaviour等。
具体来说,我们发现角色代码主要出现在对象的m_Name
属性中。例如,在输出中我们看到:
Copy
Found character codes ['c032_01'] in 49 m_Name: c032_01.atlas
Found character codes ['c032_01'] in 49 m_Name: c032_01.skel
Found character codes ['c032_01'] in 114 m_Name: c032_01_Atlas
Found character codes ['c032_01'] in 28 m_Name: c032_01
Found character codes ['c032_01'] in 114 m_Name: c032_01_SkeletonData_ExtraDataAsset
Found character codes ['c032_01'] in 114 m_Name: c032_01_SkeletonData
Found character codes ['c032_01'] in 114 m_Name: c032_01_SkeletonData_SoundEvents
Found character codes ['c032_01'] in 21 m_Name: c032_01_Material
这表明目标角色代码c032_01
在bundle文件中多次出现,主要是在各种资源的名称中。
实现方法
在extract_target_code_from_bundle
函数中,我们采用了以下方法来提取目标角色代码:
加载bundle文件:使用UnityPy库加载bundle文件
Copy
bundle = UnityPy.load(bundle_path)
检查所有对象:遍历bundle中的所有对象
Copy
for obj in bundle.objects:
try:
data = obj.read()
# 检查各种属性…
检查多个属性:对于每个对象,我们检查多个可能包含角色代码的属性:
name
属性m_Name
属性- 容器路径(
container.path
) - 对于MonoBehaviour对象,还检查其脚本数据字典中的字符串值
使用正则表达式提取角色代码:使用正则表达式
r'(c\d+_\d+)'
从这些属性中提取形如c032_01
的角色代码Copy
char_codes = re.findall(r'(c\d+_\d+)', data.name)
统计出现频率:统计每个角色代码的出现次数,排除源角色代码
Copy
if code != source_code:
char_code_counts[code] = char_code_counts.get(code, 0) + 1
选择最频繁的代码:选择出现次数最多的角色代码作为目标角色代码
Copy
most_common_code = max(char_code_counts.items(), key=lambda x: x[1])[0]
关键发现
- 资源命名模式:Unity bundle文件中的资源(如纹理、骨骼数据、材质等)通常以目标角色代码命名。
- 多次出现:目标角色代码在bundle文件中多次出现(在我们的例子中是8次),这使得我们可以通过统计出现频率来确定正确的目标代码。
- 不同对象类型:目标角色代码出现在不同类型的对象中,包括TextAsset(类型49)、MonoBehaviour(类型114)、Texture2D(类型28)和Material(类型21)。
- m_Name属性:
m_Name
属性是最常包含角色代码的属性,几乎所有包含目标角色代码的对象都在这个属性中有它。
为什么这种方法有效
这种方法之所以有效,是因为角色交换mod的工作原理是将一个角色的资源(如纹理、骨骼数据等)替换为另一个角色的资源。因此,bundle文件中必然包含目标角色的信息,特别是在资源的名称中。
通过统计不同角色代码的出现频率,我们可以可靠地确定目标角色代码,而不需要依赖猜测或启发式方法。这确保了结果的准确性和可靠性。
总结来说,我们通过深入分析Unity bundle文件的结构,发现了一种可靠的方法来提取目标角色代码,这种方法基于实际的数据而非猜测,因此能够确保信息的准确性。