Unity的Random使用的XORShift128
usm的前8字节是标识(Signature), 后面4字节是加密长度(小端序)
将文件名(包括后缀)转换bytes然后相加得到seed
根据加密长度生成对应的随机数 然后和文件 xor
实现就是这样
from pathlib import Path
class XORShift128:
__slots__ = ['x', 'y', 'z', 'w']
MT19937 = 1812433253
def __init__(self, seed: int = 0):
self.init_seed(seed)
def init_seed(self, seed: int):
self.x = seed & 0xFFFFFFFF
self.y = (self.MT19937 * self.x + 1) & 0xFFFFFFFF
self.z = (self.MT19937 * self.y + 1) & 0xFFFFFFFF
self.w = (self.MT19937 * self.z + 1) & 0xFFFFFFFF
def xorshift(self) -> int:
t = self.x ^ ((self.x << 11) & 0xFFFFFFFF)
self.x = self.y
self.y = self.z
self.z = self.w
self.w = (self.w ^ ((self.w >> 19) & 0xFFFFFFFF) ^ t ^ ((t >> 8) & 0xFFFFFFFF)) & 0xFFFFFFFF
return self.w
def next_uint_range(self, umin: int = 0, umax: int = 256) -> int:
if (umax - umin) == 0: return umin
return (umin - self.xorshift() % (umax + umin)) if umax < umin else (umin + self.xorshift() % (umax - umin))
def batch(usm_path: str = '', ext: str = '*.usm', subfolder: bool = False):
path = Path(usm_path) if usm_path else Path.cwd()
need = [i for i in (path.rglob(ext) if subfolder else path.glob(ext))]
for i in need:
with open(i, 'rb') as f:
if f.read(8) != b'GC\x20Movie':
continue
elen = int.from_bytes(f.read(4), 'little')
data = bytearray(f.read())
rnd = XORShift128(sum(i.name.encode()) & 0xFFFFFFFF)
data[:elen] = bytes(j ^ rnd.next_uint_range(0, 255) for j in data[:elen])
if not data.startswith(b'CRID'):
print(f'解密错误 ---- {i.as_posix()}')
continue
with open(f'{i}.dec', 'wb') as w:
w.write(data)
if __name__ == '__main__':
path = r'' # 指定游戏文件所在文件夹
ext = '*.usm' # 指定要解密的文件类型后缀
subfolder = False # 是否查找子文件夹内的文件
batch(path, ext, subfolder)