2.8 KiB
Bundle Decryption & Extraction
Overview
Holo's Hanafuda (Unity 6000.0.25f1, IL2CPP) encrypts its 559 addressable asset bundles using a custom AES-256-ECB stream cipher implementation. This document outlines the encryption scheme, the discovery process, and how to use the extract_bundles.py script to decrypt and extract the assets.
Encryption Scheme
The game implements a custom stream cipher by leveraging AES-256-ECB as a keystream generator. The encryption keys were found by developing a custom EOSSDK proxy DLL that dumps keys at runtime.
| Property | Value |
|---|---|
| Cipher | AES-256-ECB, PaddingMode.None |
| Key | 32 ASCII bytes: rK7CcATuZk7LAmhqqU4iBLNmAq8QbK3s |
| Keystream | AES_ECB(key, counter_block) |
| Counter block | [le64(counter) | 8 zero bytes] (16 bytes) |
| Counter start | pos/16 + 1 (first block = counter 1) |
Decryption Logic
Files are encrypted using a block-by-block XOR operation against an AES-generated keystream. To decrypt these bundles, you can use the extract_bundles.py script, which calculates the counter for each 16-byte block and reverses the XOR encryption.
# The process is something like this:
counter_block = struct.pack('<q', pos // 16 + 1) + b'\x00' * 8
keystream = AES_ECB(key, counter_block)
plaintext[i] = ciphertext[i] XOR keystream[i]
Discovery & Key Extraction
The encryption keys and metadata were recovered using a custom EOSSDK proxy DLL (main.c). By replacing the legitimate EOSSDK-Win64-Shipping.dll with this proxy, we successfully:
- Intercepted Key Derivation: Hooked
GenerateKeyandGenerateIVto capture the 32-byte AES key and bundle naming patterns. - Memory Scanning: Implemented a background thread to scan process memory for UnityFS headers and key string patterns.
- Asset Loading Hooks: Hooked
EncryptAssetBundleResource.LoadLocalto map encrypted bundles to their file paths.
Extraction Process
Prerequisites
Ensure you have the necessary Python libraries installed:
pip install pycryptodome UnityPy
Script: extract_bundles.py
This script performs a two-phase extraction:
- Decryption: Reads encrypted
.bundlefiles from the game directory and writes decrypted.unity3dfiles to the output folder using the discovered AES key. - Asset Parsing: Uses
UnityPyto iterate through the decrypted bundles to extract Textures, Sprites, Meshes, and Audio.
Asset Breakdown
| Type | Count | Notes |
|---|---|---|
| AudioClip | 3149 | FSB5 format |
| Texture2D | 1312 | Backgrounds/UI |
| Sprite | 1298 | Atlas-sliced character art |
| TextAsset | 71 | Dialogue/Config |
Note: The asset extraction done by the script is purely a example, to actually extract all the possible files correctly, you should use a software like AssetRipper