diff options
Diffstat (limited to 'python/typelibrary.py')
| -rw-r--r-- | python/typelibrary.py | 441 |
1 files changed, 301 insertions, 140 deletions
diff --git a/python/typelibrary.py b/python/typelibrary.py index 8a340928..d4e5b0a2 100644 --- a/python/typelibrary.py +++ b/python/typelibrary.py @@ -38,173 +38,334 @@ from binaryninja import range from binaryninja import with_metaclass class TypeLibrary(object): - def __init__(self, handle): - self.handle = core.handle_of_type(handle, core.BNTypeLibrary) + def __init__(self, handle): + self.handle = core.handle_of_type(handle, core.BNTypeLibrary) - def __del__(self): - core.BNFreeTypeLibrary(self.handle) + def __del__(self): + core.BNFreeTypeLibrary(self.handle) - def __repr__(self): - return "<typelib '{}':{}>".format(self.name, self.arch.name) + def __repr__(self): + return "<typelib '{}':{}>".format(self.name, self.arch.name) - @classmethod - def new(cls, arch, name): - handle = core.BNNewTypeLibrary(arch.handle, name) - return TypeLibrary(handle) + @classmethod + def new(cls, arch, name): + """ + Creates an empty type library object with a random GUID and + the provided name. - @classmethod - def load_from_file(cls, path): - handle = core.BNLoadTypeLibraryFromFile(path) - if handle is None: - return None - return TypeLibrary(handle) + :param Architecture arch + :param str name + :rtype: TypeLibrary + """ + handle = core.BNNewTypeLibrary(arch.handle, name) + return TypeLibrary(handle) - def write_to_file(self, path): - core.BNWriteTypeLibraryToFile(self.handle, path) + @classmethod + def load_from_file(cls, path): + """ + Loads a finalized type library instance from file - @classmethod - def from_name(cls, arch, name): - handle = core.BNLookupTypeLibraryByName(arch.handle, name) - if handle is None: - return None - return TypeLibrary(handle) + :param str path + :rtype: TypeLibrary + """ + handle = core.BNLoadTypeLibraryFromFile(path) + if handle is None: + return None + return TypeLibrary(handle) - @classmethod - def from_guid(cls, arch, guid): - handle = core.BNLookupTypeLibraryByGuid(arch.handle, guid) - if handle is None: - return None - return TypeLibrary(handle) + def write_to_file(self, path): + """ + Saves a finalized type library instance to file - @property - def arch(self): - arch = core.BNGetTypeLibraryArchitecture(self.handle) - if arch is None: - return None - return binaryninja.architecture.CoreArchitecture._from_cache(handle=arch) + :param str path + :rtype: None + """ + core.BNWriteTypeLibraryToFile(self.handle, path) - @property - def name(self): - name = core.BNGetTypeLibraryName(self.handle) - return name + @classmethod + def from_name(cls, arch, name): + """ + `from_name` looks up the first type library found with a matching name. Keep + in mind that names are not necessarily unique. - @name.setter - def name(self, value): - core.BNSetTypeLibraryName(self.handle, value) + :param Architecture arch + :param str name + :rtype: TypeLibrary + """ + handle = core.BNLookupTypeLibraryByName(arch.handle, name) + if handle is None: + return None + return TypeLibrary(handle) - @property - def dependency_name(self): - return core.BNGetTypeLibraryDependencyName(self.handle) + @classmethod + def from_guid(cls, arch, guid): + """ + `from_guid` attempts to grab a type library associated with the provided + Architecture and GUID pair - @dependency_name.setter - def dependency_name(self, value): - core.BNSetTypeLibraryDependencyName(self.handle, value) + :param Architecture arch + :param str guid + :rtype: TypeLibrary + """ + handle = core.BNLookupTypeLibraryByGuid(arch.handle, guid) + if handle is None: + return None + return TypeLibrary(handle) - @property - def guid(self): - return core.BNGetTypeLibraryGuid(self.handle) + @property + def arch(self): + """The Architecture this type library is associated with""" + arch = core.BNGetTypeLibraryArchitecture(self.handle) + if arch is None: + return None + return binaryninja.architecture.CoreArchitecture._from_cache(handle=arch) - @guid.setter - def guid(self, value): - core.BNSetTypeLibraryGuid(self.handle, value) + @property + def name(self): + """The primary name associated with this type library""" + name = core.BNGetTypeLibraryName(self.handle) + return name - @property - def alternate_names(self): - count = ctypes.c_ulonglong(0) - result = [] - names = core.BNGetTypeLibraryAlternateNames(self.handle, count) - for i in range(0, count.value): - result.append(names[i]) - core.BNFreeStringList(names, count.value) - return result + @name.setter + def name(self, value): + """Sets the name of a type library instance that has not been finalized""" + core.BNSetTypeLibraryName(self.handle, value) - def add_alternate_name(self, name): - core.BNAddTypeLibraryAlternateName(self.handle, name) + @property + def dependency_name(self): + """ + The `dependency_name` of a library is the name used to record dependencies across + type libraries. This allows, for example, a library with the name "musl_libc" to have + dependencies on it recorded as "libc_generic", allowing a type library to be used across + multiple platforms where each has a specific libc that also provides the name "libc_generic" + as an `alternate_name`. + """ + return core.BNGetTypeLibraryDependencyName(self.handle) - @property - def platform_names(self): - count = ctypes.c_ulonglong(0) - result = [] - platforms = core.BNGetTypeLibraryPlatforms(self.handle, count) - for i in range(0, count.value): - result.append(platforms[i]) - core.BNFreeStringList(platforms, count.value) - return result + @dependency_name.setter + def dependency_name(self, value): + """Sets the dependency name of a type library instance that has not been finalized""" + core.BNSetTypeLibraryDependencyName(self.handle, value) - def add_platform(self, plat): - if not isinstance(plat, platform.Platform): - raise ValueError("plat must be a Platform object") - core.BNAddTypeLibraryPlatform(self.handle, plat.handle) + @property + def guid(self): + """Returns the GUID associated with the type library""" + return core.BNGetTypeLibraryGuid(self.handle) - def clear_platforms(self): - core.BNClearTypeLibraryPlatforms(self.handle) + @guid.setter + def guid(self, value): + """Sets the GUID of a type library instance that has not been finalized""" + core.BNSetTypeLibraryGuid(self.handle, value) - def finalize(self): - core.BNFinalizeTypeLibrary(self.handle) + @property + def alternate_names(self): + """ + A list of extra names that will be considered a match by ``Platform.get_type_libraries_by_name`` + """ + count = ctypes.c_ulonglong(0) + result = [] + names = core.BNGetTypeLibraryAlternateNames(self.handle, count) + for i in range(0, count.value): + result.append(names[i]) + core.BNFreeStringList(names, count.value) + return result - def query_metadata(self, key): - md_handle = core.BNTypeLibraryQueryMetadata(self.handle, key) - if md_handle is None: - return None - return metadata.Metadata(handle=md_handle).value + def add_alternate_name(self, name): + """Adds an extra name to this type library used during library lookups and dependency resolution""" + core.BNAddTypeLibraryAlternateName(self.handle, name) - def store_metadata(self, key, md): - if not isinstance(md, metadata.Metadata): - md = metadata.Metadata(md) - core.BNTypeLibraryStoreMetadata(self.handle, key, md.handle) + @property + def platform_names(self): + """ + Returns a list of all platform names that this type library will register with during platform + type registration. - def remove_metadata(self, key): - core.BNTypeLibraryRemoveMetadata(self.handle, key) + This returns strings, not Platform objects, as type libraries can be distributed with support for + Platforms that may not be present. + """ + count = ctypes.c_ulonglong(0) + result = [] + platforms = core.BNGetTypeLibraryPlatforms(self.handle, count) + for i in range(0, count.value): + result.append(platforms[i]) + core.BNFreeStringList(platforms, count.value) + return result - def add_named_object(self, name, t): - if not isinstance(name, types.QualifiedName): - name = types.QualifiedName(name) - if not isinstance(t, types.Type): - raise ValueError("t must be a Type") - core.BNAddTypeLibraryNamedObject(self.handle, name._get_core_struct(), t.handle) + def add_platform(self, plat): + """ + Associate a platform with a type library instance that has not been finalized. - def add_named_type(self, name, t): - if not isinstance(name, types.QualifiedName): - name = types.QualifiedName(name) - if not isinstance(t, types.Type): - raise ValueError("t must be a Type") - core.BNAddTypeLibraryNamedType(self.handle, name._get_core_struct(), t.handle) + This will cause the library to be searchable by ``Platform.get_type_libraries_by_name`` + when loaded. - def get_named_object(self, name): - if not isinstance(name, types.QualifiedName): - name = types.QualifiedName(name) - t = core.BNGetTypeLibraryNamedObject(self.handle, name._get_core_struct()) - if t is None: - return None - return types.Type(t) + This does not have side affects until finalization of the type library. + """ + if not isinstance(plat, platform.Platform): + raise ValueError("plat must be a Platform object") + core.BNAddTypeLibraryPlatform(self.handle, plat.handle) - def get_named_type(self, name): - if not isinstance(name, types.QualifiedName): - name = types.QualifiedName(name) - t = core.BNGetTypeLibraryNamedType(self.handle, name._get_core_struct()) - if t is None: - return None - return types.Type(t) + def clear_platforms(self): + """Clears the list of platforms associated with a type library instance that has not been finalized""" + core.BNClearTypeLibraryPlatforms(self.handle) - @property - def named_objects(self): - count = ctypes.c_ulonglong(0) - result = {} - named_types = core.BNGetTypeLibraryNamedObjects(self.handle, count) - for i in range(0, count.value): - name = types.QualifiedName._from_core_struct(named_types[i].name) - result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) - core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) - return result + def finalize(self): + """ + Flags a newly created type library instance as finalized and makes it available for Platform and Architecture + type library searches + """ + core.BNFinalizeTypeLibrary(self.handle) - @property - def named_types(self): - count = ctypes.c_ulonglong(0) - result = {} - named_types = core.BNGetTypeLibraryNamedTypes(self.handle, count) - for i in range(0, count.value): - name = types.QualifiedName._from_core_struct(named_types[i].name) - result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) - core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) - return result + def query_metadata(self, key): + """ + `query_metadata` retrieves a metadata associated with the given key stored in the type library + + :param string key: key to query + :rtype: metadata associated with the key + :Example: + + >>> lib.store_metadata("ordinals", {"9": "htons"}) + >>> lib.query_metadata("ordinals")["9"] + "htons" + """ + md_handle = core.BNTypeLibraryQueryMetadata(self.handle, key) + if md_handle is None: + return None + return metadata.Metadata(handle=md_handle).value + + def store_metadata(self, key, md): + """ + `store_metadata` stores an object for the given key in the current type library. Objects stored using + `store_metadata` can be retrieved from any reference to the library. Objects stored are not arbitrary python + objects! The values stored must be able to be held in a Metadata object. See :py:class:`Metadata` + for more information. Python objects could obviously be serialized using pickle but this intentionally + a task left to the user since there is the potential security issues. + + This is primarily intended as a way to store Platform specific information relevant to BinaryView implementations; + for example the PE BinaryViewType uses type library metadata to retrieve ordinal information, when available. + + :param string key: key value to associate the Metadata object with + :param Varies md: object to store. + :rtype: None + :Example: + + >>> lib.store_metadata("ordinals", {"9": "htons"}) + >>> lib.query_metadata("ordinals")["9"] + "htons" + """ + if not isinstance(md, metadata.Metadata): + md = metadata.Metadata(md) + core.BNTypeLibraryStoreMetadata(self.handle, key, md.handle) + + def remove_metadata(self, key): + """ + `remove_metadata` removes the metadata associated with key from the current type library. + + :param string key: key associated with metadata + :rtype: None + :Example: + + >>> lib.store_metadata("integer", 1337) + >>> lib.remove_metadata("integer") + """ + core.BNTypeLibraryRemoveMetadata(self.handle, key) + + def add_named_object(self, name, t): + """ + `add_named_object` directly inserts a named object into the type library's object store. + This is not done recursively, so care should be taken that types referring to other types + through NamedTypeReferences are already appropriately prepared. + + To add types and objects from an existing BinaryView, it is recommended to use + :py:meth:`BinaryView.export_object_to_library`, which will automatically pull in + all referenced types and record additional dependencies as needed. + + :param QualifiedName name + :param Type t + :rtype: None + """ + if not isinstance(name, types.QualifiedName): + name = types.QualifiedName(name) + if not isinstance(t, types.Type): + raise ValueError("t must be a Type") + core.BNAddTypeLibraryNamedObject(self.handle, name._get_core_struct(), t.handle) + + def add_named_type(self, name, t): + """ + `add_named_type` directly inserts a named object into the type library's object store. + This is not done recursively, so care should be taken that types referring to other types + through NamedTypeReferences are already appropriately prepared. + + To add types and objects from an existing BinaryView, it is recommended to use + :py:meth:`BinaryView.export_type_to_library`, which will automatically pull in + all referenced types and record additional dependencies as needed. + + :param QualifiedName name + :param Type t + :rtype: None + """ + if not isinstance(name, types.QualifiedName): + name = types.QualifiedName(name) + if not isinstance(t, types.Type): + raise ValueError("t must be a Type") + core.BNAddTypeLibraryNamedType(self.handle, name._get_core_struct(), t.handle) + + def get_named_object(self, name): + """ + `get_named_object` direct extracts a reference to a contained object -- when + attempting to extract types from a library into a BinaryView, consider using + :py:meth:`BinaryView.import_library_object` instead. + + :param QualifiedName name + :rtype: Type + """ + if not isinstance(name, types.QualifiedName): + name = types.QualifiedName(name) + t = core.BNGetTypeLibraryNamedObject(self.handle, name._get_core_struct()) + if t is None: + return None + return types.Type(t) + + def get_named_type(self, name): + """ + `get_named_type` direct extracts a reference to a contained type -- when + attempting to extract types from a library into a BinaryView, consider using + :py:meth:`BinaryView.import_library_type` instead. + + :param QualifiedName name + :rtype: Type + """ + if not isinstance(name, types.QualifiedName): + name = types.QualifiedName(name) + t = core.BNGetTypeLibraryNamedType(self.handle, name._get_core_struct()) + if t is None: + return None + return types.Type(t) + + @property + def named_objects(self): + """ + A dict containing all named objects (functions, exported variables) provided by a type library (read-only) + """ + count = ctypes.c_ulonglong(0) + result = {} + named_types = core.BNGetTypeLibraryNamedObjects(self.handle, count) + for i in range(0, count.value): + name = types.QualifiedName._from_core_struct(named_types[i].name) + result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) + core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) + return result + + @property + def named_types(self): + """ + A dict containing all named types provided by a type library (read-only) + """ + count = ctypes.c_ulonglong(0) + result = {} + named_types = core.BNGetTypeLibraryNamedTypes(self.handle, count) + for i in range(0, count.value): + name = types.QualifiedName._from_core_struct(named_types[i].name) + result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) + core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) + return result |
