Skip to main content
This example demonstrates how to create custom UI plugins that integrate with Binary Ninja’s interface, using the Triage plugin as a comprehensive reference.

Overview

The Triage plugin (triage.cpp) shows how to:
  • Register custom view types
  • Create UI actions and menu items
  • Configure plugin settings
  • Integrate custom views into the Binary Ninja UI
  • Handle user interactions and navigation

Complete Source Code

#include "uitypes.h"
#include "view.h"
#include "files.h"
#include "byte.h"

extern "C"
{
    BN_DECLARE_UI_ABI_VERSION

    BINARYNINJAPLUGIN bool UIPluginInit()
    {
        SettingsRef settings = BinaryNinja::Settings::Instance();
        
        // Register settings group
        settings->RegisterGroup("triage", "Triage");
        
        settings->RegisterSetting("triage.preferSummaryView",
            R"({
                "title" : "Always Prefer Triage Summary View",
                "type" : "boolean",
                "default" : false,
                "description" : "Always prefer opening binaries in Triage Summary view, even when performing full analysis."
            })");

        settings->RegisterSetting("triage.preferSummaryViewForRaw",
            R"({
                "title" : "Prefer Triage Summary View for Raw Files",
                "type" : "boolean",
                "default" : false,
                "description" : "Prefer opening raw files in Triage Summary view."
            })");

        settings->RegisterSetting("triage.analysisMode",
            R"({
                "title" : "Triage Analysis Mode",
                "type" : "string",
                "default" : "basic",
                "description" : "Controls the amount of analysis performed on functions when opening for triage.",
                "enum" : ["controlFlow", "basic", "full"],
                "enumDescriptions" : [
                    "Only perform control flow analysis on the binary. Cross references are valid only for direct function calls.",
                    "Perform fast initial analysis of the binary. This mode does not analyze types or data flow through stack variables.",
                    "Perform full analysis of the binary." ]
            })");

        settings->RegisterSetting("triage.linearSweep",
            R"({
                "title" : "Triage Linear Sweep Mode",
                "type" : "string",
                "default" : "partial",
                "description" : "Controls the level of linear sweep performed when opening for triage.",
                "enum" : ["none", "partial", "full"],
                "enumDescriptions" : [
                    "Do not perform linear sweep of the binary.",
                    "Perform linear sweep on the binary, but skip the control flow graph analysis phase.",
                    "Perform full linear sweep on the binary." ]
            })");

        // Register custom view type
        ViewType::registerViewType(new TriageViewType());

        // Register UI actions
        UIAction::registerAction("Open for Triage...", QKeySequence("Ctrl+Alt+O"));
        UIAction::registerAction("Open Selected Files");

        UIActionHandler::globalActions()->bindAction("Open for Triage...", 
            UIAction([](const UIActionContext& context) {
                UIContext* currentContext = context.context;
                if (!currentContext)
                    return;

                // Create custom widget
                TriageFilePicker* fp = new TriageFilePicker(currentContext);
                currentContext->createTabForWidget("Open for Triage", fp);
            }));

        // Add menu item
        Menu::mainMenu("File")->addAction("Open for Triage...", "Open");

        // Register file open mode
        UIContext::registerFileOpenMode(
            "Triage...", 
            "Open file(s) for quick analysis in the Triage Summary view.", 
            "Open for Triage...");

        ViewType::registerViewType(new ByteViewType());
        return true;
    }
}

Key Concepts Explained

1
Declare UI ABI Version
2
extern "C"
{
    BN_DECLARE_UI_ABI_VERSION
    
    BINARYNINJAPLUGIN bool UIPluginInit()
    {
        // Plugin initialization code
    }
}
3
UI plugins must:
4
  • Declare BN_DECLARE_UI_ABI_VERSION to ensure compatibility
  • Export a UIPluginInit() function that returns bool
  • Use extern "C" linkage for the plugin entry point
  • 5
    Register Plugin Settings
    6
    SettingsRef settings = BinaryNinja::Settings::Instance();
    settings->RegisterGroup("triage", "Triage");
    
    settings->RegisterSetting("triage.analysisMode",
        R"({
            "title" : "Triage Analysis Mode",
            "type" : "string",
            "default" : "basic",
            "description" : "Controls the amount of analysis performed...",
            "enum" : ["controlFlow", "basic", "full"],
            "enumDescriptions" : [...]
        })");
    
    7
    Settings provide user-configurable options:
    8
  • Create a settings group for organization
  • Define settings with JSON schema
  • Supported types: boolean, string, number, array
  • Use enum for dropdown selections
  • Access settings in code with settings->Get<Type>("setting.name")
  • 9
    Register Custom View Types
    10
    ViewType::registerViewType(new TriageViewType());
    
    11
    Custom view types allow you to create new views in the UI:
    12
  • Implement a ViewType subclass
  • Override create() to instantiate your view
  • Override getPriority() to control when the view is default
  • Register with ViewType::registerViewType()
  • 13
    Create UI Actions
    14
    UIAction::registerAction("Open for Triage...", QKeySequence("Ctrl+Alt+O"));
    
    UIActionHandler::globalActions()->bindAction("Open for Triage...", 
        UIAction([](const UIActionContext& context) {
            UIContext* currentContext = context.context;
            if (!currentContext)
                return;
    
            TriageFilePicker* fp = new TriageFilePicker(currentContext);
            currentContext->createTabForWidget("Open for Triage", fp);
        }));
    
    15
    Actions provide user interactions:
    16
  • Register action with name and optional keyboard shortcut
  • Bind action to a callback function (lambda or function pointer)
  • Access UI context through UIActionContext
  • Create tabs with createTabForWidget()
  • 17
    Add Menu Items
    18
    Menu::mainMenu("File")->addAction("Open for Triage...", "Open");
    
    19
    Integrate actions into menus:
    20
  • mainMenu("MenuName") - Access top-level menus (File, Edit, View, etc.)
  • addAction(actionName, groupName) - Add action to menu
  • Group names control placement within the menu
  • 21
    Register File Open Modes
    22
    UIContext::registerFileOpenMode(
        "Triage...", 
        "Open file(s) for quick analysis in the Triage Summary view.", 
        "Open for Triage...");
    
    23
    File open modes appear in the “Open with” dialog:
    24
  • First parameter: Display name
  • Second parameter: Description
  • Third parameter: Associated action name
  • Creating Custom View Types

    Implement ViewType Subclass

    class TriageViewType : public ViewType
    {
    public:
        TriageViewType() : ViewType("Triage", "Triage Summary") {}
        
        virtual int getPriority(BinaryViewRef data, const QString& filename) override
        {
            // Return higher priority to be selected by default
            SettingsRef settings = Settings::Instance();
            if (settings->Get<bool>("triage.preferSummaryView"))
                return 100;
            return 1;
        }
        
        virtual QWidget* create(BinaryViewRef data, ViewFrame* frame) override
        {
            return new TriageView(frame, data);
        }
    };
    

    Implement Custom Widget

    class TriageView : public QWidget
    {
        Q_OBJECT
        
    private:
        BinaryViewRef m_data;
        ViewFrame* m_frame;
        
    public:
        TriageView(ViewFrame* frame, BinaryViewRef data)
            : QWidget(frame), m_data(data), m_frame(frame)
        {
            QVBoxLayout* layout = new QVBoxLayout(this);
            
            // Add custom UI components
            QLabel* label = new QLabel("Triage Summary");
            layout->addWidget(label);
            
            // Add file information
            QString info = QString("File: %1\n").arg(data->GetFile()->GetFilename().c_str());
            QTextEdit* infoWidget = new QTextEdit(info);
            layout->addWidget(infoWidget);
        }
    };
    

    Advanced UI Features

    Create Context-Sensitive Actions

    UIAction::registerAction("Process Current Function");
    
    UIActionHandler::globalActions()->bindAction("Process Current Function",
        UIAction([](const UIActionContext& context) {
            if (!context.function)
                return;
            
            // Process the current function
            FunctionRef func = context.function;
            // ... custom processing ...
        }),
        // Validity check - only enable when a function is selected
        [](const UIActionContext& context) {
            return context.function != nullptr;
        });
    

    Add Context Menu Items

    UIActionHandler::globalActions()->bindAction("My Custom Action",
        UIAction([](const UIActionContext& context) {
            // Action handler
        }));
    
    ContextMenuManager::instance()->registerAction("MyCustomAction", "My Custom Action");
    

    Create Sidebars

    class CustomSidebar : public SidebarWidget
    {
    public:
        CustomSidebar(const QString& title) : SidebarWidget(title) {}
        
        void notifyViewChanged(ViewFrame* frame) override
        {
            // Update sidebar when view changes
        }
    };
    
    // Register sidebar
    Sidebar::addSidebarWidgetType(new CustomSidebarType());
    

    Building UI Plugins

    CMake Configuration

    cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
    
    project(MyUIPlugin)
    
    find_package(BinaryNinjaUI REQUIRED)
    
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTORCC ON)
    
    add_library(MyUIPlugin SHARED
        plugin.cpp
        customview.cpp
    )
    
    target_link_libraries(MyUIPlugin
        BinaryNinja::UI
        Qt6::Core
        Qt6::Gui
        Qt6::Widgets
    )
    
    bn_install_plugin(${PROJECT_NAME})
    

    Building

    mkdir build && cd build
    cmake ..
    make
    

    Expected Behavior

    When the Triage plugin is loaded:
    1. Settings appear in Preferences under “Triage” group
    2. Menu item “Open for Triage…” appears in File menu
    3. Keyboard shortcut Ctrl+Alt+O opens the triage dialog
    4. File open mode “Triage…” appears in open dialogs
    5. Custom view shows triage summary when opening files

    Common UI Components

    Available Context Objects

    struct UIActionContext
    {
        UIContext* context;           // Current UI context
        BinaryViewRef binaryView;     // Current binary view
        FunctionRef function;         // Current function (if any)
        uint64_t address;             // Current address
        size_t length;                // Selection length
        // ... more fields ...
    };
    

    Qt Widgets

    Binary Ninja UI plugins can use Qt widgets:
    • QWidget - Base widget class
    • QLabel, QPushButton, QLineEdit - Basic controls
    • QTableView, QTreeView - Data views
    • QVBoxLayout, QHBoxLayout - Layouts

    Use Cases

    • Custom Analysis Views - Specialized visualizations
    • Triage Tools - Quick binary assessment interfaces
    • Automation Dashboards - Analysis workflow interfaces
    • Data Visualization - Custom graph and chart views
    • Integration Tools - Connect Binary Ninja to external tools

    Build docs developers (and LLMs) love