def decrypt_data1_with_decrypt_buf( decrypt_buf: bytearray, data: bytearray, game_key1=0 ): result = bytearray() e = 0x76548AEF decrypt_index = 0 for i in range(len(data) >> 2): b = int.from_bytes( decrypt_buf[decrypt_index * 4 : (decrypt_index * 4) + 4], "little" ) b ^= int.from_bytes(data[i * 4 : (i * 4) + 4], "little") b = wrapping_sub(b, 0x4A91C262) b = rol(b, 3, 32) b = wrapping_sub(b, e) result += b.to_bytes(4, "little") decrypt_index += 1 decrypt_index &= 3 a = game_key1 ^ 0x10FB562A # If game_key is 0 a is just constant e = wrapping_add(e, a) for i in range(len(data) & 3, 0, -1): index = len(data) - i b = int.from_bytes( decrypt_buf[decrypt_index * 4 : (decrypt_index * 4) + 4], "little" ) b >>= 6 b = (b & 0xFF) ^ data[index] b = wrapping_add(b, 0x37) result += b.to_bytes(1, "little") decrypt_index += 1 decrypt_index &= 3 return result
def decrypt_data2_with_decrypt_buf( decrypt_buf: bytearray, data: bytearray, game_key2=0 ): result = bytearray() e = 0x2A65CB4F decrypt_index = 0 for i in range(len(data) >> 2): b = int.from_bytes( decrypt_buf[decrypt_index * 4 : (decrypt_index * 4) + 4], "little" ) b ^= int.from_bytes(data[i * 4 : (i * 4) + 4], "little") b = wrapping_sub(b, e) b = rol(b, 2, 32) b = wrapping_add(b, 0x37A19E8B) result += b.to_bytes(4, "little") decrypt_index += 1 decrypt_index &= 3 a = game_key2 ^ 0x139FA9B # If game_key is 0 a is just constant e = wrapping_sub(e, a) for i in range(len(data) & 3, 0, -1): index = len(data) - i b = int.from_bytes( decrypt_buf[decrypt_index * 4 : (decrypt_index * 4) + 4], "little" ) b >>= 4 b = (b & 0xFF) ^ data[index] b = wrapping_add(b, 0x3) result += b.to_bytes(1, "little") decrypt_index += 1 decrypt_index &= 3 return result
def __set_buffers(self): return [ self.__C ^ 0x53A76D2E, wrapping_add(self.__B, 0x5BB17FDA), wrapping_add(self.__A, 0x6853E14D), self.__D ^ 0xF5C6A9A3, ]
def get_file_key(file, archive_data, header, game_key3=0, game_key4=0): file_key = file.file_decrypt_key file_key = wrapping_add(file_key, archive_data.file_decrypt_key) file_key ^= header.archive_data_key_decrypted file_key = wrapping_add(file_key, header.archive_data_entry_count_decrypted) file_key ^= game_key4 file_key = wrapping_sub(file_key, 0x5C39E87B) file_key ^= wrapping_add( wrapping_add( (ror(header.file_decrypt_key_decrypted, 5, 32) * 0x7DA8F173), 0x13712765, ), game_key3, ) return file_key
def init_decrypt_table(key1: int, key2: int): table = bytearray() for i in range(0x100): table += i.to_bytes(1, "little") v = key1 for i in range(0x100): x = v x >>= 0x10 x &= 0xFF y = table[x] z = table[v & 0xFF] table[v & 0xFF] = y table[x] = z z = v z >>= 8 z &= 0xFF x = v x >>= 0x18 y = table[x] v = ror(v, 2, 32) v = (v * 0x1A74F195) & 0xFFFFFFFF v = wrapping_add(v, key2) a = table[z] table[z] = y table[x] = a return table
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 decrypt_data2( data1: bytearray, data2: bytearray, count: int, decrypt_table: bytearray, data2_size: int, md5_cpz7: bytearray, game_key2=0, ): result = bytearray() previous_data = data1 for i in range(count): offset = int.from_bytes(previous_data[8:12], "little") size = data2_size next_data = previous_data[int.from_bytes(previous_data[0:4], "little") :] if i < count - 1: size = int.from_bytes(next_data[8:12], "little") size -= offset internal_data2 = decrypt_data_with_decrypt_table( decrypt_table, data2[offset:], size, 0x7E ) key = int.from_bytes(previous_data[12:16], "little") decrypt_buf2 = ( (int.from_bytes(md5_cpz7[0:4], "little") ^ key).to_bytes(4, "little") + ( int.from_bytes(md5_cpz7[4:8], "little") ^ wrapping_add(key, 0x11003322) ).to_bytes(4, "little") + (int.from_bytes(md5_cpz7[8:12], "little") ^ key).to_bytes(4, "little") + ( int.from_bytes(md5_cpz7[12:16], "little") ^ wrapping_add(key, 0x34216785) ).to_bytes(4, "little") ) internal_data2 = decrypt_data2_with_decrypt_buf( decrypt_buf2, internal_data2, game_key2 ) previous_data = next_data result += internal_data2 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 extract_file(filename): arc = EscArc2.from_file(filename) archive_file = open(filename, "rb") unk1 = arc.unk1 file_count = arc.file_count unk1 ^= arc.key file_name_table_size = ((unk1 >> 1) ^ unk1) >> 3 d = wrapping_add(unk1, unk1) ^ unk1 d = wrapping_add(d, d) d = wrapping_add(d, d) d = wrapping_add(d, d) file_name_table_size ^= d ^ unk1 file_count ^= file_name_table_size file_name_table_size ^= arc.key unk1 = (wrapping_add(file_name_table_size, file_name_table_size) ^ file_name_table_size) unk1 = wrapping_add(unk1, unk1) unk1 = wrapping_add(unk1, unk1) unk1 = wrapping_add(unk1, unk1) file_entry_key = ((file_name_table_size >> 1) ^ file_name_table_size) >> 3 file_entry_key ^= unk1 ^ file_name_table_size file_name_table_size = arc.unk2 ^ file_entry_key file_count_in_bytes = file_count * arc.file_entry_size archive_file.seek(20) file_entries = decrypt_file_entries(archive_file.read(file_count_in_bytes), file_entry_key, arc.key) file_names = archive_file.read(file_name_table_size) for file in file_entries: name = str(file_names[file.file_name_table_offset:].split(b"\x00")[0], "sjis").replace("\\", "/") print( name, file.file_name_table_offset, file.file_offset, file.file_size, ) archive_file.seek(file.file_offset) d = archive_file.read(file.file_size) 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 extract_file(filename, game_data): cpz = Cpz7.from_file(filename) data3 = decrypt_data3( cpz.encryption_data.data, cpz.encryption_data.data_size, cpz.encryption_data.key ) data = xor_with_data3( cpz.raw_data[ : cpz.header.archive_data_size_decrypted + cpz.header.file_data_size_decrypted ], data3, ) data = decrypt_using_password( data, cpz.header.archive_data_size_decrypted + cpz.header.file_data_size_decrypted, PASSWORD, cpz.header.archive_data_key_decrypted ^ 0x3795B39A, ) md5_cpz7 = md5cpz7.md5(cpz.header.cpz7_md5).digest() decrypt_table = init_decrypt_table( cpz.header.archive_data_key_decrypted, int.from_bytes(md5_cpz7[4:8], "little") ) data1 = decrypt_data_with_decrypt_table( decrypt_table, data[: cpz.header.archive_data_size_decrypted], cpz.header.archive_data_size_decrypted, 0x3A, ) decrypt_buf = ( ( wrapping_add(cpz.header.archive_data_key_decrypted, 0x76A3BF29) ^ int.from_bytes(md5_cpz7[0:4], "little") ).to_bytes(4, "little") + ( cpz.header.archive_data_key_decrypted ^ int.from_bytes(md5_cpz7[4:8], "little") ).to_bytes(4, "little") + ( wrapping_add(cpz.header.archive_data_key_decrypted, 0x1000_0000) ^ int.from_bytes(md5_cpz7[8:12], "little") ).to_bytes(4, "little") + ( cpz.header.archive_data_key_decrypted ^ int.from_bytes(md5_cpz7[12:16], "little") ).to_bytes(4, "little") ) data1 = decrypt_data1_with_decrypt_buf(decrypt_buf, data1, game_data[0]) data2 = data[ cpz.header.archive_data_size_decrypted : cpz.header.archive_data_size_decrypted + cpz.header.file_data_size_decrypted ] decrypt_table2 = init_decrypt_table( cpz.header.archive_data_key_decrypted, int.from_bytes(md5_cpz7[8:12], "little") ) data2 = decrypt_data2( data1, data2, cpz.header.archive_data_entry_count_decrypted, decrypt_table2, cpz.header.file_data_size_decrypted, md5_cpz7, game_data[1], ) decrypt_table3 = init_decrypt_table( int.from_bytes(md5_cpz7[12:16], "little"), cpz.header.archive_data_key_decrypted ) archive_data = [] index = 0 for i in range(cpz.header.archive_data_entry_count_decrypted): entry = cpz.ArchiveDataEntry.from_bytes(data1[index:]) index += entry.entry_size archive_data.append(entry) files = {} index = 0 for d in archive_data: files[d] = list() for i in range(d.file_count): file = cpz.FileEntry.from_bytes(data2[index:]) index += file.entry_size files[d].append(file) for archive_data, file_list in files.items(): for file in file_list: print(file.file_name) contents = cpz.raw_file_data[file.offset : file.offset + file.file_size] file_key = get_file_key( file, archive_data, cpz.header, game_data[2], game_data[3], ) f_decrypted = decrypt_file( contents, file.file_size, md5_cpz7, file_key, decrypt_table3, PASSWORD, ) f = open("ext/" + str(file.file_name.split(b"\x00")[0], "ascii"), "wb") f.write(f_decrypted) f.close()
def decompress(src, dest_len): src_index = 0 dest_index = 0 dest = bytearray(dest_len) b = 0 c = 0 s = 0 var_4 = 0 var_8 = 0 var_c = 0 while True: while True: c >>= 1 if c <= 0xFFFF: c = src[src_index] | (wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8)) src_index += 2 if c & 1 == 0: break dest[dest_index] = src[src_index] src_index += 1 dest_index += 1 c >>= 1 if c <= 0xFFFF: c = src[src_index] | (wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8)) src_index += 2 if c & 1 == 0: c >>= 1 b = 2 var_c = b if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += b if c & 1 == 0: s = src[src_index] + 1 src_index += 1 if s == 256: return dest else: c >>= 1 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 d = wrapping_shl((c & 1), 10) c >>= 1 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 a = wrapping_shl((c & 1), 9) c >>= 1 d |= a if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 s = wrapping_add(((wrapping_shl( (c & 1), 8) | src[src_index]) | d), 256) src_index += 1 else: c >>= 1 d = 1 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 s = c c >>= 1 s &= d if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 if c & 1 == 0: c >>= 1 d = 513 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 if c & 1 == 0: c >>= 1 d = 1025 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 a = c & 1 c >>= 1 s = wrapping_add(s, s) s |= a if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 if c & 1 == 0: c >>= 1 d = 2049 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 a = c & 1 c >>= 1 s = wrapping_add(s, s) s |= a if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 if c & 1 == 0: c >>= 1 d = 4097 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 s = wrapping_add(s, s) s |= c & 1 s = wrapping_shl(s, 8) | src[src_index] src_index += 1 c >>= 1 s = wrapping_add(s, d) var_4 = src_index if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 var_4 = src_index b = 3 if c & 1 == 0: c >>= 1 if c <= 0xFFFF: c = src[src_index] | (wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8)) src_index += 2 var_4 = src_index b = 4 if c & 1 == 0: c >>= 1 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 var_4 = src_index b = 5 if c & 1 == 0: c >>= 1 if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 var_4 = src_index b = 6 if c & 1 == 0: c >>= 1 var_8 = c if c <= 0xFFFF: c = src[src_index] | wrapping_shl( (src[src_index + 1] | 0xFFFF_FF00), 8) src_index += 2 var_8 = c var_4 = src_index if c & 1 == 0: a, var_4, var_8 = some_fn(var_4, var_8, src) if a == 0: d, var_4, var_8 = some_fn( var_4, var_8, src) d = wrapping_shl(d, 2) a, var_4, var_8 = some_fn( var_4, var_8, src) a = wrapping_add(a, a) d |= a a, var_4, var_8 = some_fn( var_4, var_8, src) src_index = var_4 b = a | d b = wrapping_add(b, 9) else: src_index = var_4 + 1 b = src[src_index - 1] + 17 else: a, var_4, var_8 = some_fn(var_4, var_8, src) src_index = var_4 if a == 0: b = 7 else: b = 8 c = var_8 var_c = b d = dest_index d -= s var_8 = b for _ in range(b): dest[d + s] = dest[d] d += 1 if b != 0: b = var_c dest_index += b