summaryrefslogtreecommitdiff
path: root/rust/plugin_examples/data_renderer/src
diff options
context:
space:
mode:
authorLukBukkit <luk.bukkit@gmail.com>2025-04-24 16:20:32 +0000
committerMason Reed <mason@vector35.com>2025-10-07 16:47:33 -0400
commit64633f61f7b9e03be9437b5f4896bbe122f7a7a2 (patch)
tree8fafed1395a8d2e29e5a6b8b7f7d7b8a2af2731a /rust/plugin_examples/data_renderer/src
parente6e4ebea5d0ea7842766c7e686e0dfd45cb54bb8 (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.rs111
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
+}