Binary Ninja Blog

Binary Ninja 5.2 (Io)

The release codename Io is inspired by the Expanse, though of course it's a real moon in many other sci-fi stories as well. >

For the last few months, we’ve been hard at work on today’s release, Binary Ninja 5.2 (Io)! This release delivers some of our most impactful and highly requested features yet, including bitwise data-structure support (second most requested), container support (fifth most requested), full Hexagon architecture support for disassembly and decompilation, and much more. Under-the-hood, 5.2 also contains some other improvements that will help us chart a course toward even bigger improvements in the future.

Let’s dig in!

Major Features

Free Candy >

Free Candy

Well, not quite free candy, but it might seem like it if you’re a user of the Free edition of Binary Ninja! In 5.2, we’re adding many new features from the paid versions to Free:

Initial Bitfield Support

New in Binary Ninja 5.2, there is support for bitwise structure members, commonly referred to as bitfields. Structure members can now be represented with a given bit position and bit width, and Linear View will render the fields properly:

Bitfield Support

Currently, we use bitfield information when rendering structures in the data renderer, as shown above. The included debug info plugins (e.g. DWARF, PDB) have been updated to express bitfields alongside other plugins like the built-in SVD import, where MMIO peripherals make heavy use of bitfields.

In a future release, we will extend our analysis to resolve common access patterns for bitfields in Medium and High Level IL.

Container Support

One of our most-requested features is finally here: full container support. With the introduction of Container Transforms, Binary Ninja can now seamlessly handle nested formats like ZIP, IMG4, or CaRT directly in-memory — no manual extraction required.

At its core, container support lets you browse inside archives and automatically follow transformation layers to reach the data you care about. When a container resolves to a single target, Binary Ninja can transparently open it for analysis. Combined with the files.container.defaultPasswords setting, this makes it effortless to open password-protected samples or malware archives safely — everything happens in memory, so nothing ever touches disk, and you can create an analysis database immediately.

When there are multiple payloads, the new Container Browser lets you explore and choose exactly which one to load:

Container Browser

You can easily extend this functionality since it leverages the Transform API. A complete ZipInfo example is included with the API, so you can add support for whatever container formats you need.

Custom Strings / Constants

Want to add your own custom string deobfuscator that can be automatically applied merely by adding a type? How about support for custom string formats for a new language? Here’s some of the changes we made in this release to support it:

  • Custom String Rendering: These new APIs allow for custom callbacks, enabling strings to be rendered with different logic than just standard C-style strings.
  • Type Attributes: These are useful for annotating which strings to use a custom renderer on in a file that has a mix of obfuscated strings and regular C-style strings.
  • Better type-propagation: For the example plugin below, we had to add some additional type propagation features that would automatically propagate the types (including attributes).
  • Custom Constant Rendering: The constant renderer system makes similar changes to strings as the custom string rendering but applied to constants. For example, consider automatically converting constants passed to a library hashing function into their string representations.

We’ll show off more details in an upcoming blog post, but here are a few examples to whet your appetite. First, we asked one of our favorite YouTubers and malware analysis trainers, Josh Reynolds from InvokeRE, for a good sample that uses a custom string obfuscation implementation. He suggested a recent Amadey variant(1, 2). Next, we wrote a quick example plugin that allows us to deobfuscate strings using simple type annotations which is useful for lots of other samples as well.

  1. Load the example plugin (copy it or symlink it into your plugin folder from the install path).
  2. Open the sample linked above (4cfd8b1592254d745d8f654e97b393c620ed463e317e09caa13b78d4cd779fdd, 1, 2).
  3. Create a new type. Attributes can contain parameters that can be accessed by your plugin making this infinitely useful! This type was created from observing the aDecrypt function using a hard-coded subtraction key from offset 00405000. Navigate to that location, right-click on the string and choose Copy As/Binary/Raw Hex . The sub_encoded attribute will be used by our plugin from step 1 above to automatically replace strings.
 typedef char __attr("sub_encoded", "31656537366531313932396130373434356335616264373434616134303764623239613037343435633561626437343461613430376462")* deobfuscate;
  1. Now apply the type directly to the aDecrypt function: int32_t aDecrypt(deobfuscate arg1) (Note: the type is NOT a pointer since the typedef already has a pointer).
  2. That’s it! See how the strings are automatically de-obfuscated everywhere that function is used!

Another useful feature is custom constant rendering. Check out how the bid64_constant.py example plugin handles rendering a lesser-known floating point format.

We didn’t just make custom string renderers for this specific feature. Part of the vision for Binary Ninja over the next few releases is a push toward language-specific decompilation. You can already see that with our current Objective-C support. A lot of the work over the past few releases has been in core APIs and features needed to support specific architectures or languages, and custom string support is one such feature. Many languages have their own string representations and encodings, so keep an eye out as we begin to take advantage of this over the next several releases.

As a side-benefit, any strings identified by __builtin_strcpy and related functions will now also show up in the string list as Outlined. This makes it even more useful in quickly identifying stack-strings that might previously not have been shown in the strings view despite being identified during analysis.

Outlined Strings

Ghidra Import

Stuck working with co-workers who prefer another reverse engineering tool? While Binary Ninja has had IDB import support for some time now, with 5.2, you can also import directly from Ghidra!

You can either import the data into an existing file using the Plugins/Ghidra Import/Import Database... menu (or command-palette action), or just open the database directly with Plugins/Ghidra Import/Open Database... instead. You’ll be able to select a single .gbf or use the file browser from a .gpr to select the specific file to apply or load.

When importing, you can choose which categories of information to import into your current analysis:

Ghidra Import

With Commercial and above editions, you can also directly import part or all of a Ghidra project into a Binary Ninja project using Plugins/Ghidra Import/Import Project... if you run it inside an existing Binary Ninja Project.

We plan to include Ghidra export support as well in a future version of Binary Ninja for bi-directional compatibility when working with collaborators who are using Ghidra.

WARP Server

WARP, our function signature matching plugin, can now push and retrieve function and type information from a server! This allows user-contributed signatures so you can more easily share reverse engineering information with others using our WARP server. Another benefit is that we can provide signatures for uncommon libraries or one-off functions without worrying about the size on disk for users that may never need them.

Downloading Signatures

While the first network implementation of WARP is being implemented in Binary Ninja, we have publicly documented the format and API and look forward to other tools including WARP support. Our goal is to make WARP a common format for all reverse engineering tools to support sharing function signatures no matter what your tool of choice is.

Enable WARP

By default, WARP’s network functionality is disabled. The first time you access the WARP sidebar icon in Binary Ninja, you’ll be asked whether you want to enable networking.

Fetching data from the server on-demand for ~10k functions

When fetching from a server, we send the function’s GUID along with the platform name, keeping transmission of sensitive information to a minimum. No authentication is required to query the database, though authentication is required to push changes to the server.

Pushing Signatures

You can also push signatures to a WARP server using a free Binary Ninja account. See the documentation for more details!

Enterprise

Version 2.0 of the Enterprise server is scheduled for the Io Release 2 milestone and includes an integrated WARP server for all of our enterprise customers.

More

For more information regarding WARP server support, see the documentation and the WARP website and be sure to keep an eye out for another blog post showing several examples of using the WARP network service.

Hexagon

With Binary Ninja 5.2, we’re excited to announce we’ve added support for the Qualcomm Hexagon DSP architecture in our Ultimate and Enterprise editions.

Hexagon is a particularly tricky target for decompilation due to several characteristics of the DSP’s pipeline. In particular, we now support hardware loops, which we believe to be an industry first! We’ll be back with a blog post with more details on those features and how we were able to add support, but you might remember in 5.1 when we mentioned how the custom basic block analysis was a precursor for some tricky architectures — this is the first architecture released using that new system.

Hexagon Decompilation Example

Hexagon Hardware Loop Support

That brings the total count of first-party supported architectures for decompilation to 17 in Ultimate and above editions! Our Commercial and Non-Commercial editions include first-party support for 12 architectures, all of which are open source [1, 2, 3]. Of course, there are even more third-party architectures available in the extension manager, so the total count is even higher.

Cross References

One of the very first design decisions we made in Binary Ninja was to do things differently from other tools with our Cross References (xrefs). We love having a small xrefs window available that updates as you click around. That said, there’s plenty of people with muscle memory from other tools, so who are we to limit your choice? We now support three different modes of xrefs, available in the ui.defaultXrefInterface setting.

Cross References Setting

  • pinned: Pinned xrefs are persistent and do not change if you move your focus. You can have multiple pins in the same UI, similar to how Ghidra’s xrefs work. This is the new default setting and what you’ll get when you press the x hotkey.
  • sidebar: The sidebar setting maintains the behavior from previous versions of Binary Ninja, where our always-on xrefs sidebar is focused when you press the x hotkey.
  • dialog: For those who really prefer a modal dialog (how IDA Pro shows xrefs by default), use this setting. You can see the results here in the custom string section above.

Can’t decide which you like best? No problem, you can even bind all of them to different hotkeys and keep them all at your fingertips if you prefer:

  • Pinned: Pin Cross References
  • Sidebar: Focus Cross References
  • Dialog: Cross References Dialog...

TTD Queries and Analysis

This release brings major enhancements to WinDbg TTD (Time-Travel Debugging) integration. A TTD trace is a vast information source, and efficient querying is the key to unlocking its full potential. We’ve added powerful new widgets to make running TTD queries easier, and expanded the Python API to enable seamless automation.

TTD Calls Widget

The TTD Calls widget allows you to query and analyze function call events from your TTD trace. This is equivalent to WinDbg’s dx @$cursession.TTD.Calls() functionality, but integrated directly into Binary Ninja. It also lets you set a return address range, which in most cases identifies the caller, so you can limit results to calls from one specific module to another. This is invaluable for extracting API usage patterns and getting high-level behavioral information.

TTD Calls Widget

TTD Memory Widget

The TTD Memory widget allows you to query memory access events from your TTD trace. This is equivalent to WinDbg’s dx @$cursession.TTD.Memory() functionality. Use it to query read/write/execute operations in a given address range. This is especially helpful for surgical access to the trace—whether you’re hunting for specific memory accesses or tracking down executed instructions.

TTD Memory Widget

TTD Events Widget

The TTD Events widget displays important events that occurred during the TTD trace, such as thread creation/termination, module loads/unloads, and exceptions. This is equivalent to WinDbg’s dx @$cursession.TTD.Events() functionality. It creates three tabs by default, showing module/thread/exception information, giving you a high-level overview of the program’s behavior.

  • Module Events tab: list all of the module loads and unloads

TTD Module Events

  • Thread Events: list all of the thread creations and terminations

TTD Thread Events

  • Exception Events: list all of the exceptions that occurred during execution

TTD Exception Events

TTD Analysis

Creating UI widgets for TTD data model queries is great, but we can do even better! If you’ve ever used lighthouse or bncov, you know how valuable code coverage visualization is in reverse engineering. Here’s the exciting part: your TTD trace already contains that information! We’ve included TTD Code Coverage Analysis, which processes the coverage data and uses a render layer to highlight executed instructions directly in disassembly. More TTD analyses are coming soon!

  • TTD Analysis Dialog

TTD Analysis Feature

TTD Coverage Highlighting

Python API for TTD

We have created Python APIs that allow you to access TTD queries easily, letting you build your own analysis. Here is a quick example:

# Get the debugger controller
dbg = binaryninja.debugger.DebuggerController.get_controller(bv)

# Query all calls to a function
calls = dbg.get_ttd_calls_for_symbols("user32!MessageBoxA")
print(f"Found {len(calls)} calls to MessageBoxA")

# Query memory writes to an address range
events = dbg.get_ttd_memory_access_for_address(0x401000, 0x401004, "w")
print(f"Found {len(events)} writes to 0x401000-0x401004")

# Query all TTD events
print(dbg.get_ttd_events())

If you haven’t yet explored TTD, now is the perfect time to transform your dynamic analysis workflow! Read the documentation, or check out an awesome list of TTD resources.

Objective-C

In 5.2, we continue to work on ensuring we have the best Objective-C decompilation around. We’ve rewritten our Objective-C workflow in Rust and added two new features that drastically improve decompilation.

First, we propagate type information from [super init], which you can see below:

Second, we added a setting to remove reference counting calls which can really simplify decompilation in the Pseudo Objective-C view:

Let us know if you have any other feature requests for Objective-C, but just as a teaser, we’re already working on giving Swift the same treatment with a decompilation workflow and support for types, symbol demangling, debug information, and more.

Open-Source Contributions

Special thanks to the following open source contributors whose PRs were merged into this release:

We appreciate your contributions!

Everything Else

Analysis / Core

UI

  • Feature: Added new features to Database View including JSON formatting toggle, Show Differences option, Download All Snapshots button, and filtering snapshot fields (WARNING: backup your database before using this!)

Database View

Architectures and Platforms

Core Plugins

Collaboration / Projects

  • Feature: Add project file dependencies and support automatic downloading
  • Feature: Add support for automatically loading PDB/DWARF info from sibling files in projects
  • Improvement: Improve error handling in project APIs
  • Fix: Fix error caused by saving snapshots pulled through collaboration

API

Rust API

Debugger

Documentation

Other

Deprecations

Even this massive list isn’t everything! For even more items that were not included here including the usual assortment of performance improvements and more, check out our closed milestone on GitHub.