问题描述
LZMA解压失败
Traceback (most recent call last):
File "/data/data/com.termux/files/home/bin/python/unity/test.py", line 3, in <module>
ur = UnityRes.load("data.unity3d")
File "/data/data/com.termux/files/home/bin/python/unity/UnityRes/env.py", line 6, in load
return cls(path)
File "/data/data/com.termux/files/home/bin/python/unity/UnityRes/env.py", line 9, in __init__
AssetBundle.parse_header(path)
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/data/data/com.termux/files/home/bin/python/unity/UnityRes/AssetBundle/AssetBundle.py", line 48, in parse_header
self.parse_block()
~~~~~~~~~~~~~~~~^^
File "/data/data/com.termux/files/home/bin/python/unity/UnityRes/AssetBundle/AssetBundle.py", line 73, in parse_block
blockInfo_data = CompressionHelper.decompress_lz4(blockInfo_bytes, self.uncompressed_size)
File "/data/data/com.termux/files/usr/lib/python3.13/site-packages/UnityPy/helpers/CompressionHelper.py", line 94, in decompress_lz4
return lz4.block.decompress(data, uncompressed_size)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
_block.LZ4BlockError: Decompression failed: corrupt input or insufficient space in destination buffer. Error code: 5
推测
pos位置错了 当前位置不是压缩块数据的位置
报错代码
# TODO
from UnityPy.streams import EndianBinaryReader
from typing import Literal
from ..exception import UnknownHeaderMagicError
TYPE = Literal["UnityFS", "UnityWeb", "UnityRaw"]
BILOC = Literal["AtTheEnd", "Combined", "LZMA", "LZ4"]
class AssetBundle:
def __init__(self):
self.type: TYPE = None
self.flagType: BILOC = None
self.blocks_info = []
self.dirs_info = []
def parse_header(self, path):
self.reader = EndianBinaryReader(path, endian='>')
self.sig = self.reader.read(8)
if self.sig == b"UnityFS\x00":
self.type = "UnityFS"
elif self.sig == b"UnityWeb":
self.type = "UnityWeb"
elif self.sig == b"UnityRaw":
self.type = "UnityRaw"
else:
raise UnknownHeaderMagicError(str(self.sig))
self.format_version = self.reader.read_u_int()
self.unity_version = self.reader.read_string_to_null()
self.unity_revision = self.reader.read_string_to_null()
# WARNING: 去掉下面这行的注释的时候一定要把下面的seek删了!
# self.file_size = self.reader.read_long()
self.reader.seek(8, 1)
self.compressed_size = self.reader.read_u_int()
self.uncompressed_size = self.reader.read_u_int()
self.flag = self.reader.read_u_int()
self.compression_type = None
self.block_info_location = None
if self.flag & 0x01:
self.compression_type = "LZMA"
elif self.flag & 0x02 or self.flag & 0x03:
self.compression_type = "LZ4"
else:
self.compression_type = "None"
if self.flag & 0x40:
self.block_info_location = "AtTheEnd"
else:
self.block_info_location = "Combined"
self.parse_block()
def parse_block(self):
current_pos = self.reader.tell()
if self.block_info_location == "AtTheEnd":
self.reader.seek(self.reader.Length - self.compressed_size)
blockInfo_bytes = self.reader.read_bytes(self.compressed_size)
# 导入压缩辅助函数
from UnityPy.helpers import CompressionHelper
# 获取压缩类型标志 (低6位)
comp_flag = self.flag & 0x3F
print(f"comp_flag: {comp_flag}")
print(f"compressed_size: {self.compressed_size}")
print(f"uncompressed_size: {self.uncompressed_size}")
# 根据标志选择解压方法
if comp_flag == 0: # None
blockInfo_data = blockInfo_bytes
elif comp_flag == 1: # LZMA
blockInfo_data = CompressionHelper.decompress_lzma(blockInfo_bytes, self.uncompressed_size)
elif comp_flag in (2, 3): # LZ4 or LZ4HC
blockInfo_data = CompressionHelper.decompress_lz4(blockInfo_bytes, self.uncompressed_size)
else:
raise ValueError(f"Unknown compression flag: {comp_flag}")
print(f"Decompressed block info size: {len(blockInfo_data)}")
info_reader = EndianBinaryReader(blockInfo_data, endian=self.reader.endian)
# 读16字节hash
info_reader.read_bytes(16)
# block count
block_count = info_reader.read_int()
print(f"block_count: {block_count}")
self.blocks_info = []
for i in range(block_count):
uncompressed_size = info_reader.read_u_int()
compressed_size = info_reader.read_u_int()
flags = info_reader.read_u_short()
self.blocks_info.append((uncompressed_size, compressed_size, flags))
print(f" Block{i}: uncomp={uncompressed_size}, comp={compressed_size}, flags={hex(flags)}")
nodes_count = info_reader.read_int()
print(f"nodes_count: {nodes_count}")
self.dirs_info = []
for i in range(nodes_count):
offset = info_reader.read_long()
size = info_reader.read_long()
flags = info_reader.read_u_int()
path = info_reader.read_string_to_null()
self.dirs_info.append((offset, size, flags, path))
if i < 5:
print(f" Node{i}: {path}")
self.reader.seek(current_pos)