Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

K0lb3/RustyAssetBundleEXtractor

Repository files navigation

⚠️ Project Notice: Maintenance & Ownership Transferred

Development on this repository has concluded. Due to limited time and shifting priorities, I am no longer maintaining this crate.

To ensure the project continues to thrive, full maintenance and ownership—including the crates.io package—have been transferred. Please redirect all future updates, issues, and pull requests to the active repository:

➡️ jakobhellermann/RustyAssetBundleEXtractor

RustyAssetBundleEXtractor (rabex) License_MIT License_APACHE

A work-in-progress extractor and patcher for Unity Engine asset files. Currently it can do about nothing, so please check back later.

Dependencies

This projects uses following dependencies:

Examples

parsing a normal BundleFile and dumping its objects

use std::{
    fs::{DirBuilder, File},
    io::{Seek, Write},
    path::Path,
};

use rabex::files::{BundleFile, SerializedFile};
use rabex::config::ExtractionConfig;

let mut reader = File::open(fp).unwrap();
let export_dir = Path::new("dump");

// parse the bundle file
let config = ExtractionConfig::new();
let mut bundle = BundleFile::from_reader(&mut reader, &config).unwrap();

// iterate over the files in the bundle
for directory in &bundle.m_DirectoryInfo {
    // generate export dir for cab
    let export_cab_dir = export_dir.join(&directory.path);
    // seek to the start of the file in the bundle
    bundle
        .m_BlockReader
        .seek(std::io::SeekFrom::Start(directory.offset as u64))
        .unwrap();

    // try to parse the file as a SerializedFile
    match SerializedFile::from_reader(&mut bundle.m_BlockReader, &config) {
        Ok(serialized) => {
            // iterate over objects
            for object in &serialized.m_Objects {
                // get a helper object to parse the object
                let mut handler =
                    serialized.get_object_handler(object, &mut bundle.m_BlockReader);

                // try to get the name
                let name = match handler.peak_name() {
                    Ok(name) => format!("{}_{}", object.m_PathID, name),
                    Err(_) => format!("{}", object.m_PathID),
                };

                // ensure that the parent directory exists
                let dst_path = export_cab_dir.join(name);
                DirBuilder::new()
                    .recursive(true)
                    .create(dst_path.parent().unwrap())
                    .unwrap_or_else(|_| panic!("Failed to create {:?}", dst_path.parent()));

                // parse the object as json
                let json = handler.parse_as_json().unwrap();
                // println!("{:?}", json);
                File::create(format!("{}.json", dst_path.to_string_lossy()))
                    .unwrap()
                    .write_all(json.to_string().as_bytes())
                    .unwrap();

                // parse the object as yaml
                let yaml = handler.parse_as_yaml().unwrap().unwrap();
                // println!("{:?}", yaml);
                File::create(format!("{}.yaml", dst_path.to_string_lossy()))
                    .unwrap()
                    .write_all(serde_yaml::to_string(&yaml).unwrap().as_bytes())
                    .unwrap();

                // parse the object as msgpack
                let msgpack = handler.parse_as_msgpack().unwrap();
                File::create(format!("{}.msgpack", dst_path.to_string_lossy()))
                    .unwrap()
                    .write_all(&msgpack)
                    .unwrap();

                // serialize as actual class
                // note: a small part of the object classes isn't implemented yet
                if object.m_ClassID == rabex::objects::map::AssetBundle {
                    let ab = handler
                        .parse::<rabex::objects::classes::AssetBundle>()
                        .unwrap();
                    println!("{:?}", ab);
                }
            }
        }
        Err(e) => {
            // TODO - try to filter out resource files
            println!(
                "Failed to parse {} as SerializedFile.",
                &directory.path.to_string()
            );
        }
    }
}

parsing a by UnityCN encrypted BundleFile and handling stripped Unity version

let mut reader = File::open(fp).unwrap();
let config = ExtractionConfig {
    unitycn_key: Some("Decryption Key".as_bytes().try_into().unwrap()),
    fallback_unity_version: "2020.3.0f1".to_owned(),
};
let bundle = crate::files::BundleFile::from_reader(&mut reader, &config).unwrap();

reading a UnityCN encrypted BundleFile

Notes

TODO

  • Parsers:

    • SerializedFile
    • BundleFile
    • WebFile
  • Object Classes:

    • Generator
    • Parser
    • Writer
    • Export Functions
  • Tests:

    • Normal Tests
    • Artificing Test Files
    • 100% Coverage
  • Other:

    • feature config

Getting Help

TODO:

  • Docs
  • GitHub Issues and Discussion
  • Discord server

Contributing

See CONTRIBUTING.md.

License

RustyAssetBundleEXtractor is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.

About

wip UnityRustExtractor and patcher

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages