1 unstable release

0.0.3 Jul 25, 2023

#1858 in Game dev

MIT/Apache

1MB
12K SLoC

RustyAssetBundleEXtractor (rabex) Build Status Latest Version Docs 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.

Dependencies

~13MB
~393K SLoC