def resolve_alpha_channel(buf, alpha_channel): result = bytearray() if len(alpha_channel) > 0: for i, chunk in enumerate(chunks(buf, 4)): chunk[3] = alpha_channel[i] result += chunk else: for chunk in chunks(buf, 4): chunk[3] = 0xFF result += chunk return result
def extract_file(filename, key): arc = Malie.from_file(filename) archive_file = open(filename, "rb") archive_file.seek(0x10) header = Malie.Header.from_bytes(decrypt(arc.header, 0, key)) size = (header.file_entries_count * 8 + header.unk2) * 4 print(header.magic, header.file_entries_count, header.unk2, header.unk3, hex(size)) file_data_offset = (( (header.file_entries_count * 8 + header.unk2) * 4 + 0x10) + 1023) >> 10 d = [ decrypt(chunk, (i + 1) * 0x10, key) for i, chunk in enumerate( chunks(archive_file.read(align_size(size)), 16)) ][:size] a = bytearray() for b in d: a += b file_entries_size = header.file_entries_count << 5 file_entries = { i: Malie.FileEntry.from_bytes(chunk) for i, chunk in enumerate(chunks(a[:file_entries_size], 32)) } file_offset_table = [ int.from_bytes(chunk, "little") for chunk in chunks(a[file_entries_size:], 4) ] dirs = [(k, v.name, range(v.file_offset, v.file_offset + v.file_size)) for k, v in file_entries.items() if v.type == 0] for i, f in filter(lambda f: f[1].type == 1, file_entries.items()): name = get_path(i, dirs) + f.name print( name, f.type, f.file_offset, f.file_size, file_offset_table[f.file_offset], hex((file_offset_table[f.file_offset] + file_data_offset) << 10), ) off = (file_offset_table[f.file_offset] + file_data_offset) << 10 archive_file.seek(off) d = decrypt_file(archive_file.read(align_size(f.file_size)), off, f.file_size, key) os.makedirs(os.path.dirname("ext/" + name), exist_ok=True) output_file = open( "ext/" + name, "wb", ) output_file.write(d) output_file.close() return
def remove_bitmap_padding(buf, width, padding): if padding == 0: return buf result = bytearray() for chunk in chunks(buf, width): result += chunk[:-padding] return result
def decrypt_entry(data, file_name, size, flags, xor_key): if flags == Acv1.AcvFlags.plain.value: return data if flags & Acv1.AcvFlags.compressed.value == 0: return_data = bytearray(data) result = size // len(file_name) index = 0 name_index = 0 while index <= size and name_index < (len(file_name) - 1): for i in range(0, result): return_data[index] ^= file_name[name_index] index += 1 name_index += 1 return return_data return_data = bytearray() for chunk in chunks(data, 4): if len(chunk) != 4: return_data += chunk else: return_data += (int.from_bytes(chunk, "little") ^ xor_key).to_bytes( 4, "little", signed=False ) return zlib.decompress(return_data)
def decrypt_data3(data: bytes, size: int, key: int): input_data = bytearray() dest = bytearray(size) for chunk in chunks(data, 4): input_data += (int.from_bytes(chunk, "little") ^ key).to_bytes(4, "little") global GLOBAL_NUM GLOBAL_NUM = 0x100 data1 = list(bytes(512)) data2 = list(bytes(512)) ptr_arr = [input_data, 0, 0, 0] result = recursive_data3_decrypt(ptr_arr, data1, data2) for i in range(size): inner_result = result if inner_result >= 0x100: while True: if ptr_arr[2] == 0: ptr_arr[3] = int.from_bytes(ptr_arr[0][0:4], "little") ptr_arr[2] = 32 ptr_arr[0] = ptr_arr[0][4:] ptr_arr[2] -= 1 x = ptr_arr[3] ptr_arr[3] >>= 1 if x & 1 == 0: inner_result = data1[inner_result] else: inner_result = data2[inner_result] if inner_result < 0x100: break dest[i] = inner_result return dest
def decrypt_using_password(data: bytearray, size: int, password: bytearray, key: int): xor_buf = bytearray() result = bytearray() for chunk in chunks(password, 4): v = wrapping_sub(int.from_bytes(chunk, "little"), key) xor_buf += (v).to_bytes(4, "little") k = key k >>= 8 k ^= key k >>= 8 k ^= key k >>= 8 k ^= key k ^= 0xFFFFFFFB k &= 0x0F k += 7 index = 5 for i in range(size >> 2): v = int.from_bytes(xor_buf[index * 4 : (index + 1) * 4], "little") v ^= int.from_bytes(data[i * 4 : (i + 1) * 4], "little") v = (v + 0x784C5062) & 0xFFFFFFFF v = ror(v, k & 0xFF, 32) v = (v + 0x01010101) & 0xFFFFFFFF result += v.to_bytes(4, "little") index = (index + 1) % 0x18 for i in range(size & 3, 0, -1): v = int.from_bytes(xor_buf[index * 4 : (index + 1) * 4], "little") v >>= i * 4 v ^= data[(size - i) * 4 : ((size - i) * 4) + 1] v -= 0x7D result += v.to_bytes(1, "little") index = (index + 1) % 0x18 return result
def bitmap_to_png_with_padding(buf, width, padding): if padding == 0: return bitmap_to_png(buf, width) result = bytearray() for chunk in chunks(buf, width): result = chunk[:-padding] + result return result
def abgr_to_rgba(buf): result = bytearray() for chunk in chunks(buf, 4): a = int.from_bytes(chunk, "little") chunk[3] = ~a & 0xFF # alpha chunk[2] = (a >> 8) & 0xFF # blue chunk[1] = (a >> 16) & 0xFF # green chunk[0] = (a >> 24) & 0xFF # red result += chunk return result
def encrypt_scripts(data, xor_key, script_key): result = bytes() for chunk in chunks(data, 4): if len(chunk) != 4: result += chunk else: result += (int.from_bytes(chunk, "little") ^ xor_key ^ script_key).to_bytes( 4, "little", signed=False ) return result
def bgr_to_rgb(buf): result = bytearray() for chunk in chunks(buf, 3): if len(chunk) != 3: break a = int.from_bytes(chunk, "little") chunk[2] = a & 0xFF chunk[1] = (a >> 8) & 0xFF chunk[0] = (a >> 16) & 0xFF result += chunk return result
def decrypt_file_entries(file_entries, file_entry_key, key): decrypted_file_entries = bytearray() for chunk in chunks(file_entries, 4): file_entry_key ^= key d = wrapping_add(file_entry_key, file_entry_key) d ^= file_entry_key c = file_entry_key c >>= 1 d = wrapping_add(d, d) c ^= file_entry_key d = wrapping_add(d, d) c >>= 3 d = wrapping_add(d, d) c ^= d file_entry_key ^= c decrypted_file_entries += (int.from_bytes(chunk, "little") ^ file_entry_key).to_bytes(4, "little") result = list() for chunk in chunks(decrypted_file_entries, 12): result.append(EscArc2.FileEntry.from_bytes(chunk)) return result
def rotate_buffer(buf, n): n >>= 4 n &= 0xF n += 0x10 result = bytearray() for i, chunk in enumerate(chunks(buf, 4)): if i % 2 == 0: result += rol(int.from_bytes(chunk, "little"), n, 32).to_bytes(4, "little") else: result += ror(int.from_bytes(chunk, "little"), n, 32).to_bytes(4, "little") return bytes(result)
def decrypt_file( file_contents: bytearray, file_size: int, md5_cpz7: bytearray, key: int, decrypt_table: bytearray, password: bytearray, ): contents_index = 0 result = bytearray() decrypt_buf = bytearray() # could need static size decrypt_buf2 = bytearray() v = int.from_bytes(md5_cpz7[4:8], "little") >> 2 for b in password: decrypt_buf += (decrypt_table[b] ^ (v & 0xFF)).to_bytes(1, "little") for chunk in chunks(decrypt_buf, 4): decrypt_buf2 += (int.from_bytes(chunk, "little") ^ key).to_bytes(4, "little") c = 0x2748C39E a = 0x0A dx = key for i in range(file_size >> 2): b = int.from_bytes(decrypt_buf2[a * 4 : (a * 4) + 4], "little") >> 1 d = (c >> 6) & 0xF b ^= int.from_bytes(decrypt_buf2[d * 4 : (d * 4) + 4], "little") b ^= int.from_bytes( file_contents[contents_index : contents_index + 4], "little" ) b = wrapping_sub(b, dx) dx = c & 3 b ^= int.from_bytes(md5_cpz7[dx * 4 : (dx * 4) + 4], "little") dx = key sys.exit(0) result += b.to_bytes(4, "little") c = wrapping_add(c, wrapping_add(key, b)) a += 1 a &= 0xF contents_index += 4 for i in range(file_size & 3): c = file_contents[contents_index] ^ 0xAE result += decrypt_table[c].to_bytes(1, "little") contents_index += 1 return result
def encrypt_resources(data, flags, file_name, xor_key): if flags == Acv1.AcvFlags.plain.value: return data return_data = bytearray(data) if flags & Acv1.AcvFlags.compressed.value: for chunk in chunks(data, 4): if len(chunk) != 4: return_data += chunk else: return_data += (int.from_bytes(chunk, "little") ^ xor_key).to_bytes( 4, "little" ) return zlib.decompress(return_data) result = len(data) // len(file_name) index = 0 name_index = 0 while index <= len(data) and name_index < (len(file_name) - 1): for i in range(0, result): return_data[index] ^= file_name[name_index] index += 1 name_index += 1 return return_data
def add_alpha_channel(buf): result = bytearray() for chunk in chunks(buf, 3): result += chunk + b"\xFF" return result
def resolve_color_table(buf, color_table): color_table = [c for c in chunks(color_table, 4)] result = bytearray() for b in buf: result += color_table[b] return result
def bitmap_to_png(buf, width): result = bytearray() for chunk in chunks(buf, width): result = chunk + result return result
def header_checksum(header): num = 0x923A564C for chunk in chunks(header, 4): x = int.from_bytes(chunk, "little") num = (num + x) & 0xFFFFFFFF return num
def resolve_color_table_without_alpha(color_index_table, color_table): color_table = [c for c in chunks(color_table, 3)] result = bytearray() for index in color_index_table: result += color_table[index] return result
def decrypt_file(buf, offset, size, key): result = bytearray() for i, chunk in enumerate(filter(lambda c: len(c) == 16, chunks(buf, 16))): result += decrypt(chunk, offset + i * 0x10, key) return result[:size]
def resolve_color_table(color_index_table, color_table): color_table = [c for c in chunks(color_table, 4)] result = bytearray() for index in color_index_table: result += color_table[index] return result