23 hours ago23 hr Hi, I'm looking for tools/scripts capable of unpacking (preferably, both) the .pkn and .bfz archive types used by the PC game Bubble Fighter / 버블파이터. Below are some notes I've compiled on the two formats so people can get a quick and rough idea of what they are ..pknused around 2016 and onwards for all clients; replacing .bfz file formatproprietary, so no existing game extractors for these archives worksomeone who's developing an offline version of the game claimed he was able to unpack the .pkn files; however, he didn't elaborate on how he managed to do so.bfzused for earlier versions of the game until 2016versions of the game released before it released in Korea may have used different file however none of those versions have resurfaced yet so its hard to tell unlike .pkn archives which are proprietary, bfz files are just zip files under a dif. suffix (.bfz = "Bubble Fighter Zip"?)because .bfz files are just zip files in disguise they should be easier to open than pkn; however, not only are most of the files (minus a good amount of .png files) in these archives stored in deflate format, but seemingly each archive for every different version (this includes updates and not just regional releases) of the game also uses different passwords/keysThe sample files are in the 3 links below. The first one is a .config bfz archive from a 2013 Indonesian client, and the last 2 are config .pkn archives from the latest version of the game before it shut down. If you need me to upload the .exe for the game itself and/or attach the sample files directly to my post than I gladly will.https://files.catbox.moe/pl6ayl.bfz https://files.catbox.moe/df7fiw.pkn https://files.catbox.moe/w9ydwu.pkn
5 hours ago5 hr Localization Inspecting the Pet_Snake.bfz file shows that it indeed is a protected ZIP file with legacy ZipCrypto. The game executable is protected by Themida (😒) so I had to dump the running process to perform some analysis.The ZIP password is derived from the archive's resource path. The loader normalizes the separators, gets rid of the filename, takes the final directory component, and finally converts it all to uppercase. The string is then ran through an embedded lookup table and finally the results are all concatenated resulting in the valid password for this particular BFP file.Here is a script I wrote that will automatically generate the proper ZIP password for the given BFP file:TABLES = [ "as89f7d6af98e7f6a9s87f6as98f76asdf8yasuefyae8f7as6ef9ase87fa6se9", "alkjdfLKDFJeofias4894ewfadfklDFJfsafjlasff89a4fhJLKDSfHdf98daf9s", "afoiefajsfiasdf87ysda987dsfvhsdkvhs8dr7vhsdkfghsie4g8hsdfukzDFDf", "faklsjdfiod9f8asdfjKLDFjds9f8jasdklfjsdf9asd8fuseijkasdkHDFKJDf8", "dflkjasdf98asfuyaiufhaos8efhLHFDJSFhasod8fsdfkLDfd9f8aslkejfDLkf", "dkfjapsdoifjas9d8fajsdfiashdJKFSHdfdfaskdljf9sd8fasd89f7asieufa9", ] def bfz_password(package_path): path = package_path.encode("ascii") return "".join( TABLES[i % 6][path[i % len(path)] % 64] for i in range(64) ) def reconstruct_bfz_path(resource_path: str) -> str: normalized_path = resource_path.replace("\\", "/") separator_index = normalized_path.rfind("/") resource_directory = normalized_path[:separator_index] directory_separator = resource_directory.rfind("/") archive_name = resource_directory[directory_separator + 1:] return f"{resource_directory}/{archive_name}.bfz" def derive_bfz_kdf_input(resource_path: str) -> str: archive_path = reconstruct_bfz_path(resource_path) return archive_path.upper() if __name__ == "__main__": resource = "<FILENAME>" logical_archive_path = reconstruct_bfz_path(resource) password_generator_input = derive_bfz_kdf_input(resource) encrypted_password = bfz_password(password_generator_input) print(f"Resource path: {resource}") print(f"Logical archive path: {logical_archive_path}") print(f"KDF input: {password_generator_input}") print(f"Encrypted password: {encrypted_password}")I am taking the Pet_Snake.bfz file as example and I have opened in my tool. You can also open it in any other tool like 7zip, NotePad++, etc... as long as you can get the names of the files inside of the ZIP archive.You simply take any of the names, in this case we take Models/Characters/Pet_Snake/common/pis-basic-jump.face, and paste it in the <FILENAME> placeholder inside of the python script and run it.Resource path: Models/Characters/Pet_Snake/common/pis-basic-jump.face Logical archive path: Models/Characters/Pet_Snake/common/common.bfz KDF input: MODELS/CHARACTERS/PET_SNAKE/COMMON/COMMON.BFZ Encrypted password: 7aejsjajsauk94fjf8afasf9sefskd7f8aDj6fdsud8Lf8ya7odskos8flhps9sdThe encrypted password can then be used as password to extract the data from the ZIP file.I did not yet take a look at the PKN files you've supplied. I am planning on doing this soon. Edited 4 hours ago4 hr by Falkrian
Create an account or sign in to comment