Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.
Zero Tolerance for Disrespect

[PC] Crazy Shooting Bubble Fighter .pkn / .bfz

Featured Replies

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 .

.pkn

  • used around 2016 and onwards for all clients; replacing .bfz file format

  • proprietary, so no existing game extractors for these archives work

  • someone 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

.bfz

  • used for earlier versions of the game until 2016

  • versions 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/keys

The 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

  • 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}")

image.png

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: 7aejsjajsauk94fjf8afasf9sefskd7f8aDj6fdsud8Lf8ya7odskos8flhps9sd

The 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 by Falkrian

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.