They looks like encrypted by the same key.
Unity bundles have large, mostly static header and this very helpful in our case:
So, if simple XOR is used for encryption, we can try to get key using marked ^ part of header, adapted for Unity version used in game:
(not sure in highlighted byte and too lazy to check, but it's better to note and change, if errors occurs)
XOR have some interesting features:
If you XOR 00 byte with any byte, you get this byte value in place of 00 - so, short keys can be visible with bare eyes if encrypted file have a lots of 00-bytes.
If you XOR encrypted file with original one - you'll get <key><key><key> sequence on whole file content.
We don't have original file, but we recreated first 35 bytes of it.
So, i renamed a copy of game bundle to "s1" and XOR it as new "s1x" file using reconstructed header bytes as key, with XOR tool from Luigi Auriemma:
xor s1 s1x 0x556E69747946530000000008352E782E7800323032312E332E39663100000000000000
And got partial <key><key> sequence:
So, XOR key is: EA7B2B092B59433996F0B470B7B3FEA7BC0AA57B0208A7314420
Decoding test bundle as "s1t" file with this key:
xor s1 s1t 0xEA7B2B092B59433996F0B470B7B3FEA7BC0AA57B0208A7314420
Looks very good )
Drag-and-drop "s1t" file to AssetStudioModGUI, and it loads without issues, so key is valid:
Dealing with 36K files in cache isn't easy task, so i done a python script for mass decrypt and save to separate folder:
# Mobile Suit Gundam - Iron-Blooded Orphans G bundles unxor
import os
xor_magic = b"\xBF\x15\x42\x7D"
# xor key: EA7B2B092B59433996F0B470B7B3FEA7BC0AA57B0208A7314420
xor_key = bytearray(b"\xea\x7b\x2b\x09\x2b\x59\x43\x39\x96\xf0\xb4\x70\xb7\xb3\xfe\xa7\xbc\x0a\xa5\x7b\x02\x08\xa7\x31\x44\x20")
output_path = R"C:\tmp\Cache"
with os.scandir('.') as file_paths:
for file_path in file_paths:
if file_path.is_dir(follow_symlinks=False):
pass
else:
with open(file_path, "rb") as work_file:
file_magic = work_file.read(4)
if file_magic == xor_magic:
print("Processing file:", file_path.name)
work_file.seek(0)
encrypted_content = work_file.read()
encrypted_content_size = len(encrypted_content)
decrypted_content = bytearray(encrypted_content_size)
xor_key_multiplier = int(encrypted_content_size / 26) + 1
xor_key_array = xor_key * xor_key_multiplier
for byte in range(encrypted_content_size):
decrypted_content[byte] = encrypted_content[byte] ^ xor_key_array[byte]
out_file_name = str(file_path.name) + ".unity3d"
write_path = output_path + "\\" + out_file_name
os.makedirs(os.path.dirname(write_path), exist_ok=True)
open(write_path, "wb").write(decrypted_content)
print("Decrypted file saved:", write_path)
work_file.close()
Must be run inside of "Cache\assets\asset\" folder, and output to temporary folder on disk C (it's SSD usualy, to speed up things).
But there's other problem occur - that cache folder taken from a game which survived many updates, so a lots of older copies of same file present here, they have same name in first part (before "_") and version code as second name part.
So, i done another python script to separate latest file versions to another folder:
# Mobile Suit Gundam - Iron-Blooded Orphans G cache sort
import os
import shutil
work_dictionary = {}
output_path = R"C:\tmp\Cache\Assets"
with os.scandir('.') as file_paths:
for file_path in file_paths:
if file_path.is_dir(follow_symlinks=False):
pass
elif len(os.path.splitext(file_path)[0]) - 2 != 52:
pass
else:
bundle_name = file_path.name[0:33]
bundle_version = int(file_path.name[34:52])
if bundle_name in work_dictionary:
if work_dictionary[bundle_name] >= bundle_version:
pass
else:
work_dictionary[bundle_name] = bundle_version
else:
work_dictionary[bundle_name] = bundle_version
for item in work_dictionary:
file_name = item + "_" + str(work_dictionary[item]) + ".unity3d"
destination = output_path + "\\" + file_name
os.makedirs(os.path.dirname(destination), exist_ok=True)
if os.path.isfile(file_name) == True:
shutil.move(file_name, destination)
print("Latest version file moved to:", destination)
Must be run in folder with decoded bundles, it moves latest version files to Assets subfolder.
Then you can move this folder to main game folder "G_2.0.2_apkcombo\assets\bin\Data\" and load game folder to AssetStudioModGUI (took 16+ Gb of RAM):
Model export works fine, with animations:
Files with names starting with "r" is not encrypted or encrypted using more secure algorithms - no luck here.
Mobile_Suit_Gundam_cache_scripts.7z