这么挖坟,快一年了你们没人用ida看看的吗。。。
游戏用的是LZ4ETC2,先lz4流式解压,然后正常etc2加载,实现大概是这样:
import texture2ddecoder
import lz4.block
import struct
import os
from PIL import Image
def decm(compressed_data: bytes) -> bytearray:
total_uncompressed_size = struct.unpack('<I', compressed_data[4:8])[0]
final_buffer = bytearray()
current_pos = 8
last_decompressed_block = b""
block_index = 0
while current_pos < len(compressed_data):
if current_pos + 4 > len(compressed_data):
break
compressed_block_size = struct.unpack('<I', compressed_data[current_pos : current_pos + 4])[0]
current_pos += 4
if compressed_block_size == 0:
break
compressed_block = compressed_data[current_pos : current_pos + compressed_block_size]
current_pos += compressed_block_size
decompressed_chunk = lz4.block.decompress(
compressed_block,
uncompressed_size=16 * 1024,
dict=last_decompressed_block
)
final_buffer.extend(decompressed_chunk)
last_decompressed_block = decompressed_chunk
block_index += 1
return final_buffer[:total_uncompressed_size]
def conv(pkm_data: bytes, output_path: str):
header_fields = struct.unpack_from('>HHHHH', pkm_data, 6)
etc_format_enum = header_fields[0]
width = header_fields[1]
height = header_fields[2]
if etc_format_enum in [2, 3, 4, 10, 11]:
mode = "RGBA"
decoder_func = texture2ddecoder.decode_etc2a8
elif etc_format_enum in [1, 9]:
mode = "RGB"
decoder_func = texture2ddecoder.decode_etc2
pixel_data = pkm_data[16:]
decoded_pixels = decoder_func(pixel_data, width, height)
image = Image.frombytes(mode, (width, height), decoded_pixels)
image.save(output_path, 'PNG')
if __name__ == "__main__":
with open("effect_zhuanshushenqi_lingxufuchen.png", "rb") as f:
comp = f.read()
conv(bytes(decm(comp)), "decompress.png")