Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for UnityWebData1.0 files #74

Open
andyearnshaw opened this issue May 1, 2018 · 3 comments
Open

Support for UnityWebData1.0 files #74

andyearnshaw opened this issue May 1, 2018 · 3 comments

Comments

@andyearnshaw
Copy link
Contributor

Example UnityWebData1.0 File

The signature on these files is UnityWebData1.0.

These files just appear to contain one or more .unity3d files, so it would be great to cut out the middle-man of extracting them and then extracting the .unity3d files.

@einstein95
Copy link

QuickBMS script for these files:

idstring "UnityWebData1.0\0"
get HEADLEN long
do
	get OFF long
	get SIZE long
	get NAMEZ long
	getdstring NAME NAMEZ
	log NAME OFF SIZE
	savepos i
while i < HEADLEN

@mildsunrise
Copy link

mildsunrise commented Dec 1, 2019

python code

from unitypack.utils import BinaryReader

SIGNATURE = 'UnityWebData1.0'

class DataFile:
    def load(self, file):
        buf = BinaryReader(file, endian="<")
        self.path = file.name

        self.signature = buf.read_string()
        header_length = buf.read_int()
        if self.signature != SIGNATURE:
            raise NotImplementedError('Invalid signature {}'.format(repr(self.signature)))

        self.blobs = []
        while buf.tell() < header_length:
            offset = buf.read_int()
            size = buf.read_int()
            namez = buf.read_int()
            name = buf.read_string(namez)
            self.blobs.append({ 'name': name, 'offset': offset, 'size': size })
        if buf.tell() > header_length:
            raise NotImplementedError('Read past header length, invalid header')

        for blob in self.blobs:
            buf.seek(blob['offset'])
            blob['data'] = buf.read(blob['size'])
            if len(blob['data']) < blob['size']:
                raise NotImplementedError('Invalid size or offset, reading past file')

usage:

import os
f = open('data', 'rb')
df = DataFile()
df.load(f)
EXTRACTION_DIR = 'extracted'
for blob in df.blobs:
    print('extracting @ {}:\t{} ({})'.format(blob['offset'], blob['name'], blob['size']))
    dest = os.path.join(EXTRACTION_DIR, blob['name'])
    os.makedirs(os.path.dirname(dest), exist_ok=True)
    with open(dest, 'wb') as f:
        f.write(blob['data'])

@mildsunrise
Copy link

Maybe this is obvious, but once it's extracted, remember to set base_path to the extracted dir:

file = open(os.path.join(EXTRACTION_DIR, 'data.unity3d'), 'rb')
env = unitypack.environment.UnityEnvironment(base_path=EXTRACTION_DIR)
bundle = unitypack.load(file, env)

Or start python from the extracted directory, because base_path defaults to the current directory.
This should be documented, IMO.

Otherwise it won't find the assets referenced from the bundle, i.e.:

KeyError: "No such asset: 'sharedassets0.resource'"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants