Skip to main content
Binary Ninja provides three levels of intermediate languages in Rust: Low Level IL (LLIL), Medium Level IL (MLIL), and High Level IL (HLIL).

IL levels

LLIL

Low-level, close to assembly

MLIL

Medium-level with variables

HLIL

High-level, decompiled C-like

Low Level IL

use binaryninja::low_level_il::{LowLevelILFunction, LowLevelILOperation};

// Get LLIL for function
let llil = func.low_level_il()?;

// Iterate instructions
for instr in llil.instructions() {
    println!("{:#x}: {:?}", instr.address, instr.kind);

    // Match on operation
    match instr.kind {
        LowLevelILOperation::SetReg { dest, src } => {
            println!("  Set register {} = {:?}", dest, src);
        }
        LowLevelILOperation::Call { dest } => {
            println!("  Call {:?}", dest);
        }
        _ => {}
    }
}

Medium Level IL

use binaryninja::medium_level_il::MediumLevelILFunction;

// Get MLIL for function
let mlil = func.medium_level_il()?;

// Iterate instructions
for instr in mlil.instructions() {
    println!("{:?}", instr);

    // Access variables
    if let Some(var) = instr.variable() {
        println!("  Uses variable: {}", var.name());
    }
}

High Level IL

use binaryninja::high_level_il::HighLevelILFunction;

// Get HLIL for function
let hlil = func.high_level_il()?;

// Iterate instructions
for instr in hlil.instructions() {
    println!("{:?}", instr);
}

// Get as AST
let root = hlil.root();
println!("Function AST: {:?}", root);

SSA forms

All IL levels support SSA (Static Single Assignment) form:
// Get SSA form
let llil_ssa = llil.ssa_form()?;
let mlil_ssa = mlil.ssa_form()?;
let hlil_ssa = hlil.ssa_form()?;

// Iterate SSA instructions
for instr in mlil_ssa.instructions() {
    println!("SSA: {:?}", instr);
}

IL visitor pattern

From rust/examples/medium_level_il.rs:
use binaryninja::medium_level_il::*;

fn visit_mlil(func: &Function) {
    let mlil = func.medium_level_il().unwrap();

    for block in mlil.basic_blocks().iter() {
        for instr in block.iter() {
            match instr.kind {
                MediumLevelILInstr::SetVar(op) => {
                    println!("Set var: {} = {:?}", op.dest, op.src);
                }
                MediumLevelILInstr::If(op) => {
                    println!("If: {:?}", op.condition);
                }
                MediumLevelILInstr::Call(op) => {
                    println!("Call: {:?}", op.dest);
                }
                _ => {}
            }
        }
    }
}

Complete example

use binaryninja::headless::Session;
use binaryninja::binary_view::BinaryViewExt;
use binaryninja::high_level_il::HighLevelILInstr;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let session = Session::new()?;
    let bv = session.load("/bin/ls")?;

    // Analyze first function
    if let Some(func) = bv.functions().first() {
        println!("=== {} ===", func.symbol().full_name());

        // Get HLIL
        if let Ok(hlil) = func.high_level_il() {
            for (i, instr) in hlil.instructions().take(10).enumerate() {
                println!("{}: {:?}", i, instr);
            }
        }
    }

    Ok(())
}
From rust/examples/high_level_il.rs

Next steps

Functions

Analyze functions

Examples

See complete IL examples

Build docs developers (and LLMs) love