forked from K0lb3/UnityPy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArchiveStorageManager.py
More file actions
117 lines (91 loc) · 3.77 KB
/
Copy pathArchiveStorageManager.py
File metadata and controls
117 lines (91 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# based on: https://github.com/Razmoth/PGRStudio/blob/master/AssetStudio/PGR/PGR.cs
from typing import Tuple, Union
from ..streams import EndianBinaryReader
UNITY3D_SIGNATURE = b"#$unity3dchina!@"
DECRYPT_KEY: bytes = None
def set_assetbundle_decrypt_key(key: Union[bytes, str]):
if isinstance(key, str):
key = key.encode("utf-8", "surrogateescape")
if len(key) != 16:
raise ValueError(
f"AssetBundle Key length is wrong. It should be 16 bytes and now is {len(key)} bytes."
)
global DECRYPT_KEY
DECRYPT_KEY = key
def read_vector(reader: EndianBinaryReader) -> Tuple[bytes, bytes]:
data = reader.read_bytes(0x10)
key = reader.read_string_to_null().encode("utf-8", "surrogateescape")
return data, key
def decrypt_key(key: bytes, data: bytes, keybytes: bytes):
from Crypto.Cipher import AES
key = AES.new(keybytes, AES.MODE_ECB).encrypt(key)
return bytes(x ^ y for x, y in zip(data, key))
def to_uint4_array(source: bytes, offset: int = 0):
buffer = bytearray(len(source) * 2)
for j in range(len(source)):
buffer[j * 2] = source[offset + j] >> 4
buffer[j * 2 + 1] = source[offset + j] & 15
return buffer
class ArchiveStorageDecryptor:
unknown_1: int
index: bytes
substitute: bytes = bytes(0x10)
def __init__(self, reader: EndianBinaryReader) -> None:
if DECRYPT_KEY is None:
raise LookupError(
"The BundleFile is encrypted, but no key was provided!\nYou can set the key via UnityPy.set_assetbundle_decrypt_key(key)"
)
self.unknown_1 = reader.read_u_int()
# read vector data/key vectors
self.data, self.key = read_vector(reader)
self.data_sig, self.key_sig = read_vector(reader)
signature = decrypt_key(self.key_sig, self.data_sig, DECRYPT_KEY)
if signature != UNITY3D_SIGNATURE:
raise Exception(f"Invalid signature {signature} != {UNITY3D_SIGNATURE}")
data = decrypt_key(self.key, self.data, DECRYPT_KEY)
data = to_uint4_array(data)
self.index = data[:0x10]
self.substitute = bytes(
data[0x10 + i * 4 + j] for j in range(4) for i in range(4)
)
def decrypt_block(self, data: bytes, index: int):
offset = 0
size = len(data)
data = bytearray(data)
view = memoryview(data)
while offset < len(data):
offset += self.decrypt(view[offset:], index, size - offset)
index += 1
return data
def decrypt_byte(self, view: bytearray, offset: int, index: int):
b = (
self.substitute[((index >> 2) & 3) + 4]
+ self.substitute[index & 3]
+ self.substitute[((index >> 4) & 3) + 8]
+ self.substitute[(index % 256 >> 6) + 12]
)
view[offset] = (
(self.index[view[offset] & 0xF] - b) & 0xF
| 0x10 * (self.index[view[offset] >> 4] - b)
) % 256
b = view[offset]
return b, offset + 1, index + 1
def decrypt(self, data: bytearray, index: int, remaining: int):
offset = 0
curByte, offset, index = self.decrypt_byte(data, offset, index)
byteHigh = curByte >> 4
byteLow = curByte & 0xF
if byteHigh == 0xF:
b = 0xFF
while b == 0xFF:
b, offset, index = self.decrypt_byte(data, offset, index)
byteHigh += b
offset += byteHigh
if offset < remaining:
_, offset, index = self.decrypt_byte(data, offset, index)
_, offset, index = self.decrypt_byte(data, offset, index)
if byteLow == 0xF:
b = 0xFF
while b == 0xFF:
b, offset, index = self.decrypt_byte(data, offset, index)
return offset