1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
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::tracing_init!();
tracing::info!("Core plugin initialized");
// Register data renderer
register_data_renderer(UuidDataRenderer {});
true
}
|