diff options
| author | LukBukkit <luk.bukkit@gmail.com> | 2025-04-24 16:20:32 +0000 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2025-10-07 16:47:33 -0400 |
| commit | 64633f61f7b9e03be9437b5f4896bbe122f7a7a2 (patch) | |
| tree | 8fafed1395a8d2e29e5a6b8b7f7d7b8a2af2731a /rust/plugin_examples/data_renderer/src | |
| parent | e6e4ebea5d0ea7842766c7e686e0dfd45cb54bb8 (diff) | |
[Rust] Implement custom data renderer API
Also adds an example plugin and misc rust fixes / documentation.
This is a continuation of https://github.com/Vector35/binaryninja-api/pull/6721
Co-authored-by: rbran <lgit@rubens.io>
Diffstat (limited to 'rust/plugin_examples/data_renderer/src')
| -rw-r--r-- | rust/plugin_examples/data_renderer/src/lib.rs | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/rust/plugin_examples/data_renderer/src/lib.rs b/rust/plugin_examples/data_renderer/src/lib.rs new file mode 100644 index 00000000..178402af --- /dev/null +++ b/rust/plugin_examples/data_renderer/src/lib.rs @@ -0,0 +1,111 @@ +use binaryninja::binary_view::{BinaryView, BinaryViewBase}; +use binaryninja::data_renderer::{ + register_data_renderer, CustomDataRenderer, RegistrationType, TypeContext, +}; +use binaryninja::disassembly::{ + DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind, +}; +use binaryninja::types::{Type, TypeClass}; +use uuid::Uuid; + +struct UuidDataRenderer {} + +impl CustomDataRenderer for UuidDataRenderer { + const REGISTRATION_TYPE: RegistrationType = RegistrationType::Specific; + + fn is_valid_for_data( + &self, + _view: &BinaryView, + _addr: u64, + type_: &Type, + types: &[TypeContext], + ) -> bool { + // We only want to render arrays with a size of 16 elements + if type_.type_class() != TypeClass::ArrayTypeClass { + return false; + } + if type_.count() != 0x10 { + return false; + } + + // The array elements must be of the type uint8_t + let Some(element_type_conf) = type_.element_type() else { + return false; + }; + let element_type = element_type_conf.contents; + if element_type.type_class() != TypeClass::IntegerTypeClass { + return false; + } + if element_type.width() != 1 { + return false; + } + + // The array should be embedded in a named type reference with the id macho:["uuid"] + for type_ctx in types { + if type_ctx.ty().type_class() != TypeClass::NamedTypeReferenceClass { + continue; + } + + let Some(name_ref) = type_ctx.ty().get_named_type_reference() else { + continue; + }; + + if name_ref.id() == "macho:[\"uuid\"]" { + return true; + } + } + + false + } + + fn lines_for_data( + &self, + view: &BinaryView, + addr: u64, + _type_: &Type, + prefix: Vec<InstructionTextToken>, + _width: usize, + _types_ctx: &[TypeContext], + _language: &str, + ) -> Vec<DisassemblyTextLine> { + let mut tokens = prefix.clone(); + + let mut buf = [0u8; 0x10]; + let bytes_read = view.read(&mut buf, addr); + + // Make sure that we've read all UUID bytes and convert them to token + if bytes_read == 0x10 { + tokens.extend([ + InstructionTextToken::new("UUID(\"", InstructionTextTokenKind::Text), + InstructionTextToken::new( + Uuid::from_bytes(buf).to_string(), + InstructionTextTokenKind::String { value: 0 }, + ), + InstructionTextToken::new("\")", InstructionTextTokenKind::Text), + ]); + } else { + tokens.push(InstructionTextToken::new( + "error: cannot read 0x10 bytes", + InstructionTextTokenKind::Annotation, + )); + } + + vec![DisassemblyTextLine::new_with_addr(tokens, addr)] + } +} + +/// # Safety +/// This function is called from Binary Ninja once to initialize the plugin. +#[allow(non_snake_case)] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn CorePluginInit() -> bool { + // Initialize logging + binaryninja::logger::Logger::new("UUID Data Renderer") + .with_level(log::LevelFilter::Debug) + .init(); + + // Register data renderer + register_data_renderer(UuidDataRenderer {}); + + true +} |
