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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
use binaryninja::binary_view::BinaryViewBase;
use binaryninja::tracing::TracingLogListener;
fn main() {
tracing_subscriber::fmt::init();
let _listener = TracingLogListener::new().register();
// This loads all the core architecture, platform, etc plugins
let headless_session =
binaryninja::headless::Session::new().expect("Failed to initialize session");
tracing::info!("Loading binary...");
let bv = headless_session
.load("/bin/cat")
.expect("Couldn't open `/bin/cat`");
tracing::info!("File: `{}`", bv.file());
tracing::info!("File size: `{:#x}`", bv.len());
tracing::info!("Function count: {}", bv.functions().len());
for func in &bv.functions() {
println!("{:?}:", func.symbol().full_name());
let Ok(il) = func.medium_level_il() else {
continue;
};
// Get the SSA form for this function
let il = il.ssa_form();
// Loop through all blocks in the function
for block in il.basic_blocks().iter() {
// Loop though each instruction in the block
for instr in block.iter() {
// Uplift the instruction into a native rust format
let lifted = instr.lift();
let address = instr.address;
// Print the lifted instruction
println!("{address:08x}: {lifted:#x?}");
// Generically parse the IL tree and display the parts
visitor::print_il_expr(&lifted, 2);
}
}
}
}
mod visitor {
use binaryninja::architecture::Intrinsic;
use binaryninja::medium_level_il::MediumLevelILLiftedOperand::*;
use binaryninja::medium_level_il::{MediumLevelILFunction, MediumLevelILLiftedInstruction};
use binaryninja::variable::Variable;
fn print_indent(indent: usize) {
print!("{:<indent$}", "")
}
fn print_operation(operation: &MediumLevelILLiftedInstruction) {
print!("{}", operation.name());
}
fn print_variable(func: &MediumLevelILFunction, var: &Variable) {
print!("{}", func.function().variable_name(var));
}
pub(crate) fn print_il_expr(instr: &MediumLevelILLiftedInstruction, mut indent: usize) {
print_indent(indent);
print_operation(instr);
println!();
indent += 1;
for (_name, operand) in instr.operands() {
match operand {
Int(int) => {
print_indent(indent);
println!("int 0x{:x}", int);
}
Float(float) => {
print_indent(indent);
println!("float {:e}", float);
}
Expr(expr) => print_il_expr(&expr, indent),
Var(var) => {
print_indent(indent);
print!("var ");
print_variable(&instr.function, &var);
println!();
}
VarSsa(var) => {
print_indent(indent);
print!("ssa var ");
print_variable(&instr.function, &var.variable);
println!("#{}", var.version);
}
IntList(list) => {
print_indent(indent);
print!("index list ");
for i in list {
print!("{i} ");
}
println!();
}
VarList(list) => {
print_indent(indent);
print!("var list ");
for i in list {
print_variable(&instr.function, &i);
print!(" ");
}
println!();
}
VarSsaList(list) => {
print_indent(indent);
print!("ssa var list ");
for i in list {
print_variable(&instr.function, &i.variable);
print!("#{} ", i.version);
}
println!();
}
ExprList(list) => {
print_indent(indent);
println!("expr list");
for i in list {
print_il_expr(&i, indent + 1);
}
}
TargetMap(list) => {
print_indent(indent);
print!("target map ");
for (i, f) in list {
print!("({i}, {f}) ");
}
println!();
}
ConstantData(_) => println!("contantdata"),
Intrinsic(intrinsic) => println!("intrinsic {}", intrinsic.name()),
InstructionIndex(idx) => {
print_indent(indent);
println!("index {}", idx);
}
}
}
}
}
|