Binary Ninja Blog

5.1 Helion

Phido as Jackal and Binjy as Riddick >

Binary Ninja 5.1 might not help you see in the dark like Riddick (our 5.1 Helion release is named after a system from the Riddick universe), but it WILL help you reverse engineer better! With a bunch of quality of life improvements, bug-fixes, and even a few new features, we’re continually working to improve your reversing experience. We’re introducing WARP, our new static function matching system, which will be helping not only Binary Ninja users in the future, but the entire reverse engineering community. Also, we’re shipping the BinExport plugin pre-built for all platforms, for easy integration with BinDiff. Finally, we’ve added a ton of improvements to the readability and presentation of decompilation, better tooling for re-writing IL with scripts, and a ton of architecture improvements.

We really wanted to focus on quality and fixes for 5.1, but even with that focus we were still able to ship a number of major new features that will enable a better reverse engineering experience. We’ve also got a major update for Sidekick coming soon, so keep an eye out on the blog or our social media!

WARP

Check out WARP: our powerful new function signature-matching system!

WARP

You should never have to rely on heuristics or raw analysis if you have exact type information you can apply. Prior to this release, our main mechanisms for importing or applying large amounts of types were:

  • Importing type information from headers or another analysis database
  • Type Libraries with type information matching specific imported libraries
  • Type Archives that collect and synchronize types between multiple analysis databases
  • Signature Libraries (generated by Sigkit) that apply types to functions that match a given signature

WARP is the next-generation equivalent of Sigkit and, as of 5.1, is available and enabled by default. You can still use Signature Libraries for at least one more stable release, but we will be deprecating Sigkit in the near future. All official signature libraries will be shipped via WARP going forward.

Why replace Sigkit with WARP? First, let’s start with the design goals:

  • Better performance on both generation and matching
  • Significantly improved ease-of-use for generating new libraries
  • Support both type information and symbols (Sigkit only matched symbols, relying on other type libraries to then bring over type information)
  • Support for network lookups and submissions (similar to Lumina)
  • Cross-tool-compatibility: One of our goals with WARP is to enable better cross-platform sharing of type information between other major tools. Keep an eye out on future releases as we plan to include plugins for Ghidra, IDA, Angr, and Radare that can all consume and create the same WARP signature libraries

For our 5.1 release, we’re starting with an open-source plugin that is enabled by default as well as signatures for some common Windows libraries like msvcrt. In future releases, we will be releasing additional signatures and moving forward with plans to address our other design goals.

If you’d like to see some other use-cases for WARP (such as matching the Go runtime and matching it from start to finish) check out its showcase in our feature release live-stream video, or keep an eye out here for the forthcoming blog post where we’ll show off even more ways you can use it to make your reverse engineering experience better.

Finally, keep an eye out for an upcoming deep-dive here on this blog that will showcase other ways WARP can help you quickly make sense of your binaries.

Pseudo Objective-C

In what has to be one of the most overkill accidental-job-applications of all time, one of the best features in 5.1 actually comes from a third-party contributor who is now first-party! If you’re in the Slack, make sure to welcome Mark to the team. While originally written before he was at Vector 35, he’s of course even more active now that he’s joined us and is helping support our iOS, Objective-C, kernelcache, dyld_shared_cache, and Swift reverse engineering workflows.

This plugin showcases the power of what you can do with Language Representations and is even more useful than the two examples we launched the feature with.

Not only does decompiling back to the original source language help represent language-specific features better, but if your goal is to be able to recompile, this is a step much closer in that direction for Objective-C binaries.

BinExport / BinDiff

BinExport compatibility is now available in all paid editions of Binary Ninja! The plugin is disabled by default due to being a late addition in the release cycle, so you will need to enable the setting to use it. But, once you do, you’ll be able to export .BinExport files directly from Binary Ninja on macOS, Linux, and Windows without having to build the third-party plugin yourself. The goal here is to enable better support for tools like BinDiff and a better out-of-the-box experience. For more information, see the user documentation, or check out our fork (which will likely be upstreamed before the next release).

BinExport

Analysis / Decompilation Improvements

In addition to making Binary Ninja’s decompilation more readable and true to the original source, 5.1 also includes new ways to customize how it is structured. From giving you granular control over how control flow is structured to intelligently wrapping long strings and rendering concise ternary expressions, these improvements focus on making decompiled code easier to understand and work with.

Customizable Control Flow

The control flow structuring system now allows you to influence how decompilation is represented. Want to invert a conditional? Want to prevent a switch from being displayed that way? Now you can! Here’s an example showing how you can right-click on a switch statement to disable switch recovery:

BinExport

To change between these two results:

String Wrapping

While 5.0 added line wrapping to HLIL output, large strings were still not wrapped and the default string length could sometimes harm readability. Now, in 5.1, strings will be intelligently wrapped to fit the available space. If you prefer to set a custom width instead, you can use the rendering.strings.wrappingWidth setting.

String Wrapping

Ternary Operator

To help make our decompilation as succinct as possible, we’ve added support for ternary operators. Now, simple if-statements with assignments will be rendered in a shorter C-style format:

Ternary Support

By default, only relatively simple expressions will be rendered this way. If you prefer more complex expressions to be styled this way, or want to disable it altogether, you can change the value of the setting rendering.format.maxTernarySimplificationTokens.

This change is only implemented at the rendering layer, so no changes to your HLIL automation scripts are required.

Guided Analysis Mode

The new Guided Analysis mode gives you granular control over which code blocks are analyzed. By default, this mode will be automatically entered when invalid instructions are encountered within a function. Right-clicking on blocks in the Disassembly view now has menu options for iteratively continuing or halting analysis of branch targets. This is particularly powerful for navigating control flow obfuscation, bypassing anti-analysis techniques, and efficiently analyzing large binaries by concentrating on the code that matters most.

If you would like to toggle guided analysis for functions more quickly, see the section below on Quick Settings, which can be used with analysis.guided.enable.

Guided Analysis Context Menu

String Clamping

If you have been looking at a lot of Golang, or any other platform that doesn’t use null-terminated strings, Binary Ninja 5.1 will now respect the size of the string.

Keep an eye out on issue 1334 for when we implement custom string representation types, which will be even more helpful for these types of situations!

IL Rewriting

Binary Ninja 5.1 improves support for writing custom IL transformations, letting you modify analysis in more powerful ways. We’re adding new APIs for modifying Medium Level IL in Python, and we have new examples, and better documentation to help you write bigger and better plugins.

To demonstrate the power of this new API, we’ve written an example script that deobfuscates Control-Flow Flattening in a couple simple cases. We’ve noticed how many of you are tackling this problem as well, so we hope this example assists you in your plugin writing. As a demonstration, here’s the before-and-after from running this plugin on a case it can handle:

If you want to see more, you can check out our feature stream where we demonstrated using it live. We look forward to seeing what new plugins you will create to take advantage of these new abilities!

Architecture / Platforms

x86-64 x32 ABI

We’ve added support for the Linux x86-64 x32 ABI. To enable this, we’ve made it so that custom platforms can now override the default pointer width of their underlying Architecture. This allows us (and you in third-party plugins) to support similar situations such as AArch64 ILP32.

x86-64 x32 ABI

Custom Basic Block Analysis

Architecture plugins can now perform their own function-level basic block analysis. This gives architecture authors full control over how a function’s basic blocks are recovered. This could include deriving context from previous instructions or from metadata elsewhere in the binary. As an example, this is required to represent zero-overhead / hardware loops in DSP architectures.

This is just the first step on the way to support for a wide range of new architectures. We have one more feature planned similar to this (function level lifting) that will unlock the ability for anyone to lift architectures such as Hexagon, TMS-320 C6xx, Blackfin, PIC, and even VM bytecode such as WASM, PYK, JVM, or MSFT CIL.

MIPS R5900

We have now officially integrated support from a side-project for the MIPS R5900, which was commonly used in the PS2’s Emotion Engine. This extension to our existing architecture is available on all paid editions of the product (as well as Cloud) and is open source.

PPC-VLE

This improvement is actually two updates in one! First, we’ve replaced our previous Capstone-based open-source PowerPC plugin with a ground-up rewrite that now includes support for PPC-VLE. As this architecture replaces our previous PPC plugin, it is available in all paid editions (and Cloud!) and is open source.

PPC VLE

Native EFI Resolver Workflow

We’ve now officially integrated our UEFI plugin that we’ve previously shown off. Now, the feature no longer needs to be enabled manually. This, in addition to our built-in TE view support, means you can literally drag-and-drop to get fantastic UEFI decompilation with no plugins or manual effort required.

UEFI

UI Improvements

With so many features and plugins being added to the sidebar (Sidekick, Firmware Ninja, Debugger, Collaboration, and not to mention third-party plugins!), we realized we needed the ability to hide certain sidebars. Now, you can control which sidebars are shown using the right-click menu. Some sidebars will also elect to hide themselves by default, for example, the Debugger Modules sidebar will hide when not debugging.

To see the hidden sidebars, just click the … ellipsis icon with the “More” hover text.

Sidebar Pane Hiding

Quick Settings

Quick Settings lets you add commonly-used settings to the right-click menu in analysis views. They will appear in the “Function Settings” submenu, where you can toggle them for individual functions without interrupting your work. You can add settings to Quick Settings by going to the regular Settings menu and right-clicking the ones you want to add. For more information on the quick Settings UI (and other new settings features not mentioned here), see the user documentation.

Quick Settings

Open Source Contributions

Special thanks to the following open source contributors who submitted PRs during this last release period!

Note: Previously, we included only contributions that landed in the shipping build. For this release and going forward, we’ll be highlighting all submissions.

We appreciate your contributions!

Everything Else

Analysis

UI

String Sorting

Variable Placement

Memory Map Segment Creation UI

  • Improvement: Major performance improvements to the Cross References Widget
  • Improvement: Base Structure section of the Create Structure dialog UI improvements

Create Structure Dialog

Debugger

Architectures and Platforms

DYLD Shared Cache / Kernel Cache / Objective-C

DYLD Shared Cache and Kernel Cache are getting some quality-of-life updates:

Views

API

  • Feature: Added CheckBoxField for form inputs in Python API
  • Feature: Added hierarchical settings inheritance for resource settings
  • Feature: Added line formatter API to Rust bindings
  • Feature: Added per-function metadata support to store function-specific information
  • Feature: Added plugin command registration for project browser
  • Feature: Added SSA form support for LLIL in Rust API
  • Feature: Rust language representation support for implementing language representations
  • Feature: Added ability to construct SectionBuilder from Section in Rust
  • Feature: Added CoreRegister name to Debug implementation in Rust
  • Feature: Added documentation comments for undo actions in Rust API
  • Feature: Added FileAccessor with read/write functionality in Rust API
  • Feature: Added FlowGraphEdge type and node edge accessors in Rust API
  • Feature: Added Function::variable_type method in Rust API
  • Feature: Added get_files_by_path_in_project() and get_path_in_project() methods in Python
  • Feature: Added get_system_cache_directory() function to Python API
  • Feature: Added GetPathInProject() to core API for project path resolution
  • Feature: Added GetSystemCacheDirectory() function to C++ API
  • Feature: Added interaction handlers to flow graph API in Rust
  • Feature: Implemented interaction APIs for Rust API
  • Feature: Added LLIL_SEPARATE_PARAM_LIST_SSA support in Rust API
  • Feature: Added LLIL_UNDEF mapping support in Rust API
  • Feature: Added LowLevelILInstruction::basic_block method in Rust API
  • Feature: Added pretty printing for LLIL sub-expressions in Rust
  • Feature: Added many Rust API tests
  • Feature: Added support for LLIL_REG_PHI, LLIL_MEM_PHI, and LLIL_FLAG_PHI expressions in Rust
  • Improvement: Changed Rust API to return String instead of BnString for lossy UTF-8 conversions
  • Improvement: Changed section strings to retain core string as BnString in Rust
  • Improvement: Extensive Rust API cleanup including string handling and error improvements
  • Improvement: Improved metadata API in Rust bindings
  • Improvement: Improved section handling in Rust API
  • Improvement: Made LowLevelILInstruction and LowLevelILExpression implement Copy trait in Rust
  • Improvement: Made Section::name return BnString to preserve binary section names
  • Improvement: Made the target field public in Edge structure for Rust API
  • Improvement: Reduced usage of IntoCStr in function signatures for better type safety
  • Improvement: Removed to_string shortcut from BnString for consistency
  • Improvement: Removed unneeded mut from Architecture trait signatures in Rust
  • Improvement: Removed unused file from Rust codebase
  • Improvement: Renamed AsCStr trait to IntoCStr in Rust
  • Improvement: Rust API cleanup removing Architecture trait bounds on LLIL structures
  • Improvement: Simplified BnStrCompatible trait for easier usage in Rust
  • Improvement: Simplified C string usage in Rust API
  • Improvement: Simplified enterprise initialization in Rust API
  • Improvement: SSA to non-SSA form mapping for instructions/expressions in Rust
  • Improvement: Support for retrieving use/def of SSA registers in LLIL
  • Improvement: Various clippy lint fixes and documentation additions in Rust API
  • Improvement: instruction_at and instruction_index_at on MLIL now work without an explicit architecture
  • Fix: BinaryView reporting modified when loaded via database
  • Fix: BnString::as_bytes_with_null not including null byte in Rust API
  • Fix: caller_sites reliability issue in Python API
  • Fix: version_switcher.py utility
  • Fix: crash in BNGetMediumLevelILPossibleSSAVarValues
  • Fix: crash when writing None to database globals in Python API
  • Fix: function tags API reporting address of 0
  • Fix: MediumLevelILVarSsaField missing expr_type property documentation
  • Fix: message boxes missing title on Mac
  • Fix: parse_types_from_string return type to BasicTypeParserResult
  • Fix: plugin builds on Windows 11 with clang-cl and C++ > 17
  • Fix: PyCharm skeleton generator check to be case-insensitive
  • Fix: race condition in GenerateILIfNotPresent API
  • Fix: type parser inconsistency with struct and demangled type names
  • Fix: Workflow::Clone memory leak in C++ API
  • Fix: wrong type annotation for TypeParserResult in Python
  • Fix: CMake dependencies for binaryninjaui project
  • Fix: LowLevelILBlock to derive Clone properly after Copy trait changes
  • Fix: panic when encountering unhandled MLIL instructions in Rust
  • Fix: Section implementations to properly compare and hash sections in Rust

Documentation

Other

Deprecation Notes

  • We’ve updated our code base to use C++ 20 features. C++ plugin authors should make sure their plugins support the new language version.
  • In future releases, with Apple announcing macOS Tahoe as the last version to support x64, we will reduce our own testing and support for x64 on macOS. We will ship universal binaries for as long as possible, but future releases will not be tested on x64 on macOS.

Even this list isn’t everything! There’s plenty more items not included here, check out our closed milestone on GitHub for more.