diff options
| author | Rubens Brandao <git@rubens.io> | 2024-06-13 13:35:19 -0300 |
|---|---|---|
| committer | Kyle Martin <krm504@nyu.edu> | 2024-07-09 18:45:30 -0400 |
| commit | 66cb34c9b6fc3620cc60faf8ce964b255608b69e (patch) | |
| tree | 0a3f73c7383753ab26947433e46ca5c56d3d2bf7 /rust/src/typelibrary.rs | |
| parent | 273fa764cee0e0b972546bbc460e802879b109f8 (diff) | |
implement rust TypeLibrary
Diffstat (limited to 'rust/src/typelibrary.rs')
| -rw-r--r-- | rust/src/typelibrary.rs | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/rust/src/typelibrary.rs b/rust/src/typelibrary.rs new file mode 100644 index 00000000..79cb6569 --- /dev/null +++ b/rust/src/typelibrary.rs @@ -0,0 +1,362 @@ +use binaryninjacore_sys::*; + +use core::{ffi, mem, ptr}; + +use crate::{ + architecture::CoreArchitecture, + metadata::Metadata, + platform::Platform, + rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}, + string::{BnStrCompatible, BnString}, + types::{QualifiedName, QualifiedNameAndType, Type}, +}; + +pub struct TypeLibrary { + handle: ptr::NonNull<BNTypeLibrary>, +} + +impl TypeLibrary { + pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNTypeLibrary>) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: &*mut BNTypeLibrary) -> &Self { + assert!(!handle.is_null()); + mem::transmute(handle) + } + + #[allow(clippy::mut_from_ref)] + pub(crate) unsafe fn as_raw(&self) -> &mut BNTypeLibrary { + &mut *self.handle.as_ptr() + } + + pub fn new_reference(&self) -> Self { + unsafe { + Self::from_raw(ptr::NonNull::new(BNNewTypeLibraryReference(self.as_raw())).unwrap()) + } + } + + pub fn new_duplicated(&self) -> Self { + unsafe { Self::from_raw(ptr::NonNull::new(BNDuplicateTypeLibrary(self.as_raw())).unwrap()) } + } + + /// Creates an empty type library object with a random GUID and the provided name. + pub fn new<S: BnStrCompatible>(arch: CoreArchitecture, name: S) -> TypeLibrary { + let name = name.into_bytes_with_nul(); + let new_lib = + unsafe { BNNewTypeLibrary(arch.0, name.as_ref().as_ptr() as *const ffi::c_char) }; + unsafe { TypeLibrary::from_raw(ptr::NonNull::new(new_lib).unwrap()) } + } + + pub fn all(arch: CoreArchitecture) -> Array<TypeLibrary> { + let mut count = 0; + let result = unsafe { BNGetArchitectureTypeLibraries(arch.0, &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Decompresses a type library file to a file on disk. + pub fn decompress_to_file<P: BnStrCompatible, O: BnStrCompatible>(path: P, output: O) -> bool { + let path = path.into_bytes_with_nul(); + let output = output.into_bytes_with_nul(); + unsafe { + BNTypeLibraryDecompressToFile( + path.as_ref().as_ptr() as *const ffi::c_char, + output.as_ref().as_ptr() as *const ffi::c_char, + ) + } + } + + /// Loads a finalized type library instance from file + pub fn load_from_file<S: BnStrCompatible>(path: S) -> Option<TypeLibrary> { + let path = path.into_bytes_with_nul(); + let handle = + unsafe { BNLoadTypeLibraryFromFile(path.as_ref().as_ptr() as *const ffi::c_char) }; + ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) + } + + /// Saves a finalized type library instance to file + pub fn write_to_file<S: BnStrCompatible>(&self, path: S) { + let path = path.into_bytes_with_nul(); + unsafe { + BNWriteTypeLibraryToFile(self.as_raw(), path.as_ref().as_ptr() as *const ffi::c_char) + } + } + + /// Looks up the first type library found with a matching name. Keep in mind that names are not + /// necessarily unique. + pub fn from_name<S: BnStrCompatible>(arch: CoreArchitecture, name: S) -> Option<TypeLibrary> { + let name = name.into_bytes_with_nul(); + let handle = unsafe { + BNLookupTypeLibraryByName(arch.0, name.as_ref().as_ptr() as *const ffi::c_char) + }; + ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) + } + + /// Attempts to grab a type library associated with the provided Architecture and GUID pair + pub fn from_guid<S: BnStrCompatible>(arch: CoreArchitecture, guid: S) -> Option<TypeLibrary> { + let guid = guid.into_bytes_with_nul(); + let handle = unsafe { + BNLookupTypeLibraryByGuid(arch.0, guid.as_ref().as_ptr() as *const ffi::c_char) + }; + ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) + } + + /// The Architecture this type library is associated with + pub fn arch(&self) -> CoreArchitecture { + let arch = unsafe { BNGetTypeLibraryArchitecture(self.as_raw()) }; + assert!(!arch.is_null()); + CoreArchitecture(arch) + } + + /// The primary name associated with this type library + pub fn name(&self) -> Option<BnString> { + let result = unsafe { BNGetTypeLibraryName(self.as_raw()) }; + (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + } + + /// Sets the name of a type library instance that has not been finalized + pub fn set_name<S: BnStrCompatible>(&self, value: S) { + let value = value.into_bytes_with_nul(); + unsafe { + BNSetTypeLibraryName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) + } + } + + /// 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`. + pub fn dependency_name(&self) -> Option<BnString> { + let result = unsafe { BNGetTypeLibraryDependencyName(self.as_raw()) }; + (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + } + + /// Sets the dependency name of a type library instance that has not been finalized + pub fn set_dependency_name<S: BnStrCompatible>(&self, value: S) { + let value = value.into_bytes_with_nul(); + unsafe { + BNSetTypeLibraryDependencyName( + self.as_raw(), + value.as_ref().as_ptr() as *const ffi::c_char, + ) + } + } + + /// Returns the GUID associated with the type library + pub fn guid(&self) -> Option<BnString> { + let result = unsafe { BNGetTypeLibraryGuid(self.as_raw()) }; + (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + } + + /// Sets the GUID of a type library instance that has not been finalized + pub fn set_guid<S: BnStrCompatible>(&self, value: S) { + let value = value.into_bytes_with_nul(); + unsafe { + BNSetTypeLibraryGuid(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) + } + } + + /// A list of extra names that will be considered a match by [Platform::get_type_libraries_by_name] + pub fn alternate_names(&self) -> Array<BnString> { + let mut count = 0; + let result = unsafe { BNGetTypeLibraryAlternateNames(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Adds an extra name to this type library used during library lookups and dependency resolution + pub fn add_alternate_name<S: BnStrCompatible>(&self, value: S) { + let value = value.into_bytes_with_nul(); + unsafe { + BNAddTypeLibraryAlternateName( + self.as_raw(), + value.as_ref().as_ptr() as *const ffi::c_char, + ) + } + } + + /// Returns a list of all platform names that this type library will register with during platform + /// type registration. + /// + /// This returns strings, not Platform objects, as type libraries can be distributed with support for + /// Platforms that may not be present. + pub fn platform_names(&self) -> Array<BnString> { + let mut count = 0; + let result = unsafe { BNGetTypeLibraryPlatforms(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Associate a platform with a type library instance that has not been finalized. + /// + /// This will cause the library to be searchable by [Platform::get_type_libraries_by_name] + /// when loaded. + /// + /// This does not have side affects until finalization of the type library. + pub fn add_platform(&self, plat: &Platform) { + unsafe { BNAddTypeLibraryPlatform(self.as_raw(), plat.handle) } + } + + /// Clears the list of platforms associated with a type library instance that has not been finalized + pub fn clear_platforms(&self) { + unsafe { BNClearTypeLibraryPlatforms(self.as_raw()) } + } + + /// Flags a newly created type library instance as finalized and makes it available for Platform and Architecture + /// type library searches + pub fn finalize(&self) -> bool { + unsafe { BNFinalizeTypeLibrary(self.as_raw()) } + } + + /// Retrieves a metadata associated with the given key stored in the type library + pub fn query_metadata<S: BnStrCompatible>(&self, key: S) -> Option<Metadata> { + let key = key.into_bytes_with_nul(); + let result = unsafe { + BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) + }; + (!result.is_null()).then(|| unsafe { Metadata::from_raw(result) }) + } + + /// 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 [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. + /// + /// * `key` - key value to associate the Metadata object with + /// * `md` - object to store. + pub fn store_metadata<S: BnStrCompatible>(&self, key: S, md: &Metadata) { + let key = key.into_bytes_with_nul(); + unsafe { + BNTypeLibraryStoreMetadata( + self.as_raw(), + key.as_ref().as_ptr() as *const ffi::c_char, + md.handle, + ) + } + } + + /// Removes the metadata associated with key from the current type library. + pub fn remove_metadata<S: BnStrCompatible>(&self, key: S) { + let key = key.into_bytes_with_nul(); + unsafe { + BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) + } + } + + /// Retrieves the metadata associated with the current type library. + pub fn metadata(&self) -> Metadata { + let md_handle = unsafe { BNTypeLibraryGetMetadata(self.as_raw()) }; + assert!(!md_handle.is_null()); + unsafe { Metadata::from_raw(md_handle) } + } + + // TODO: implement TypeContainer + // /// Type Container for all TYPES within the Type Library. Objects are not included. + // /// The Type Container's Platform will be the first platform associated with the Type Library. + // pub fn type_container(&self) -> TypeContainer { + // let result = unsafe{ BNGetTypeLibraryTypeContainer(self.as_raw())}; + // unsafe{TypeContainer::from_raw(ptr::NonNull::new(result).unwrap())} + // } + + /// 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 + /// `export_object_to_library <binaryview.BinaryView.export_object_to_library>`, which will automatically pull in + /// all referenced types and record additional dependencies as needed. + pub fn add_named_object(&self, name: &QualifiedName, type_: &Type) { + unsafe { + BNAddTypeLibraryNamedObject(self.as_raw(), &name.0 as *const _ as *mut _, type_.handle) + } + } + + /// 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 + /// `export_type_to_library <binaryview.BinaryView.export_type_to_library>`, which will automatically pull in + /// all referenced types and record additional dependencies as needed. + pub fn add_named_type(&self, name: &QualifiedNameAndType, type_: &Type) { + unsafe { + BNAddTypeLibraryNamedType(self.as_raw(), &name.0 as *const _ as *mut _, type_.handle) + } + } + + /// Manually flag NamedTypeReferences to the given QualifiedName as originating from another source + /// TypeLibrary with the given dependency name. + /// + /// .. warning:: Use this api with extreme caution. + pub fn add_type_source<S: BnStrCompatible>(&self, name: &QualifiedName, source: S) { + let source = source.into_bytes_with_nul(); + unsafe { + BNAddTypeLibraryNamedTypeSource( + self.as_raw(), + &name.0 as *const _ as *mut _, + source.as_ref().as_ptr() as *const ffi::c_char, + ) + } + } + + /// Direct extracts a reference to a contained object -- when + /// attempting to extract types from a library into a BinaryView, consider using + /// `import_library_object <binaryview.BinaryView.import_library_object>` instead. + pub fn get_named_object(&self, name: &QualifiedName) -> Option<Ref<Type>> { + let t = + unsafe { BNGetTypeLibraryNamedObject(self.as_raw(), &name.0 as *const _ as *mut _) }; + (!t.is_null()).then(|| unsafe { Type::ref_from_raw(t) }) + } + + /// Direct extracts a reference to a contained type -- when + /// attempting to extract types from a library into a BinaryView, consider using + /// `import_library_type <binaryview.BinaryView.import_library_type>` instead. + pub fn get_named_type(&self, name: &QualifiedName) -> Option<Ref<Type>> { + let t = unsafe { BNGetTypeLibraryNamedType(self.as_raw(), &name.0 as *const _ as *mut _) }; + (!t.is_null()).then(|| unsafe { Type::ref_from_raw(t) }) + } + + /// A dict containing all named objects (functions, exported variables) provided by a type library + pub fn named_objects(&self) -> Array<QualifiedNameAndType> { + let mut count = 0; + let result = unsafe { BNGetTypeLibraryNamedObjects(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// A dict containing all named types provided by a type library + pub fn named_types(&self) -> Array<QualifiedNameAndType> { + let mut count = 0; + let result = unsafe { BNGetTypeLibraryNamedTypes(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } +} + +impl Drop for TypeLibrary { + fn drop(&mut self) { + unsafe { BNFreeTypeLibrary(self.as_raw()) } + } +} + +impl CoreArrayProvider for TypeLibrary { + type Raw = *mut BNTypeLibrary; + type Context = (); + type Wrapped<'a> = &'a Self; +} + +unsafe impl CoreArrayProviderInner for TypeLibrary { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeTypeLibraryList(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::ref_from_raw(raw) + } +} |
