def main(): import argparse, sys arguments = argparse.ArgumentParser() arguments.add_argument('--file', '-f', required=True) arguments.add_argument('--output', '-o', default='__types') options = arguments.parse_args(sys.argv[1:]) output = p.abspath(options.output) if not p.exists(output): os.makedirs(output) MONO_BEHAVIOUR_PERSISTENT_ID = 114 stream = FileStream(file_path=options.file) stream.endian = '<' while stream.bytes_available: persistent_id = stream.read_uint32() script_hash = b'0' * 16 if persistent_id == MONO_BEHAVIOUR_PERSISTENT_ID: script_hash = stream.read(16) type_hash = stream.read(16) size = stream.read_uint32() offset = stream.position print(persistent_id, uuid.UUID(bytes=script_hash), uuid.UUID(bytes=type_hash), size) type_tree = MetadataTypeTree(True) type_tree.persistent_type_id = persistent_id type_tree.type_hash = type_hash type_tree.mono_hash = script_hash type_tree.decode_type_tree(fs=stream) print(type_tree) assert stream.position == offset + size
def decode(self, fs: FileStream): self.version = fs.read_sint16() self.level = fs.read_uint8() self.is_array = fs.read_boolean() self.type_str_offset = fs.read_uint32() self.name_str_offset = fs.read_uint32() self.byte_size = fs.read_sint32() self.index = fs.read_sint32() self.meta_flags = fs.read_uint32()
def decode(self, fs: FileStream): offset = fs.position self.signature = fs.read_string() assert self.signature == UnitySignature.UnityFS self.version = fs.read_sint32() assert self.version != 5 self.unity_web_bundle_version = fs.read_string() self.unity_web_minimum_revision = fs.read_string() self.size = fs.read_uint64() self.compressed_blocks_info_size = fs.read_uint32() self.uncompressed_blocks_info_size = fs.read_uint32() assert self.compressed_blocks_info_size < self.uncompressed_blocks_info_size, vars( self) self.flags = fs.read_uint32() self.header_size = fs.position - offset
def decode_type_tree(self, fs: FileStream): type_index = -1 node_count = fs.read_uint32() char_count = fs.read_uint32() for _ in range(node_count): node = TypeField() node.decode(fs) if type_index >= 0: assert node.index == type_index + 1 self.nodes.append(node) type_index += 1 if char_count > 0: string_offset = fs.position string_size = 0 while string_size + 1 < char_count: offset = fs.position - string_offset position = fs.position self.strings[offset] = fs.read_string() string_size += fs.position - position assert fs.position - string_offset == char_count for node in self.nodes: # type: TypeField node.name = get_caculate_string(offset=node.name_str_offset, strings=self.strings) node.type = get_caculate_string(offset=node.type_str_offset, strings=self.strings) self.name = self.nodes[0].type
def decode(self, fs: FileStream): fs.seek(self.node.offset) header = self.header header.metadata_size = fs.read_sint32() header.file_size = fs.read_sint32() assert self.node.size == header.file_size, '{} != {}'.format( self.node.size, header.file_size) header.version = fs.read_sint32() header.data_offset = fs.read_sint32() header.endianess = fs.read_boolean() fs.read(3) # reserved bytes fs.endian = '>' if header.endianess else '<' self.print(vars(header)) self.version = fs.read_string() self.platform = fs.read_uint32() self.type_tree_enabled = fs.read_boolean() self.print('version={} platform={} type_tree_enabled={}'.format( self.version, self.platform, self.type_tree_enabled)) self.type_trees = [] type_count = fs.read_uint32() self.print('type', type_count) for _ in range(type_count): offset = fs.position type_tree = MetadataTypeTree( type_tree_enabled=self.type_tree_enabled) type_tree.decode(fs) if self.type_tree_enabled: position = fs.position fs.seek(offset) type_data = fs.read(position - offset) with open(type_tree.get_cache_path(auto_create=True), 'wb') as fp: fp.write(type_data) self.type_trees.append(type_tree) self.register_type_tree(type_tree=type_tree) self.print(type_tree) object_count = fs.read_sint32() self.print('object', object_count) for _ in range(object_count): fs.align(4) obj = ObjectInfo() obj.decode(fs) type_tree = self.type_trees[obj.type_id] obj.name = type_tree.name self.objects.append(obj) self.print(vars(obj)) script_type_count = fs.read_sint32() self.print('typeinfo', script_type_count) for _ in range(script_type_count): st = ScriptTypeInfo() st.decode(fs) self.typeinfos.append(st) self.print(vars(st)) external_count = fs.read_sint32() self.print('external', external_count) for _ in range(external_count): ext = ExternalInfo() ext.decode(fs) self.externals.append(ext) self.print(ext) fs.read_string()
def decode(self, fs: FileStream): self.local_identifier_in_file = fs.read_sint64() self.byte_start = fs.read_uint32() self.byte_size = fs.read_uint32() self.type_id = fs.read_uint32()
def decode(self, fs: FileStream): for n in range(fs.read_uint32()): node = FileNode() node.decode(fs) node.index = n self.nodes.append(node)
def decode(self, fs: FileStream): self.offset = fs.read_uint64() self.size = fs.read_uint64() self.flags = fs.read_uint32() self.path = fs.read_string()
def decode(self, fs: FileStream): self.uncompressed_data_hash = fs.read(16) for _ in range(fs.read_uint32()): block = StorageBlock() block.decode(fs) self.blocks.append(block)
def decode(self, fs: FileStream): self.uncompressed_size = fs.read_uint32() self.compressed_size = fs.read_uint32() self.flags = fs.read_uint16()