
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!
Check out WARP: our powerful new function signature-matching system!
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:
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:
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.
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 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).
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.
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:
To change between these two results:
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 would prefer to set a custom width instead, you can can use the rendering.strings.wrappingWidth setting.
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:
By default, only relatively simple expressions will be rendered this way. If you would 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.
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.
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!
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!
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.
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.
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.
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.
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.
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.
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.
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!
IDB file format changes in IDA 9.1.fp, lr names for x29, x30 registerscadd instructionR_MIPS_HI16 relocations caused by bad castMSR/MRS system registers using enums to avoid invalid data flow inferencediv.u instruction operand corruption due to missing temporary storagemov.a instruction incorrectly sign-extending const4 field instead of zero-extendingsysret instruction now properly marked as function terminatorDYLD Shared Cache and Kernel Cache are getting some quality-of-life updates:
super calls in Pseudo Objective-Cobjc_msgSend stubs due to ignored call type overridesid_1/SEL_1 instead of [id/SEL] in Objective-C runtime__init_offsets section in MachoView binaries.NOTE sections causing duplicate symbols in ELF executablesBIND_SPECIAL_DYLIB_SELF in chained fixups on macOS x86_64CheckBoxField for form inputs in Python APISectionBuilder from Section in RustFileAccessor with read/write functionality in Rust APIFlowGraphEdge type and node edge accessors in Rust APIFunction::variable_type method in Rust APIget_files_by_path_in_project() and get_path_in_project() methods in Pythonget_system_cache_directory() function to Python APIGetPathInProject() to core API for project path resolutionGetSystemCacheDirectory() function to C++ APILLIL_SEPARATE_PARAM_LIST_SSA support in Rust APILLIL_UNDEF mapping support in Rust APILowLevelILInstruction::basic_block method in Rust APILLIL_REG_PHI, LLIL_MEM_PHI, and LLIL_FLAG_PHI expressions in RustBnString for lossy UTF-8 conversionsBnString in RustLowLevelILInstruction and LowLevelILExpression implement Copy trait in RustSection::name return BnString to preserve binary section namesEdge structure for Rust APIIntoCStr in function signatures for better type safetyto_string shortcut from BnString for consistencyArchitecture trait signatures in RustAsCStr trait to IntoCStr in RustBnStrCompatible trait for easier usage in Rustinstruction_at and instruction_index_at on MLIL now work without an explicit architectureBinaryView reporting modified when loaded via databaseBnString::as_bytes_with_null not including null byte in Rust APIcaller_sites reliability issue in Python APIversion_switcher.py utilityBNGetMediumLevelILPossibleSSAVarValuesMediumLevelILVarSsaField missing expr_type property documentationBasicTypeParserResultGenerateILIfNotPresent APIWorkflow::Clone memory leak in C++ APITypeParserResult in PythonLowLevelILBlock to derive Clone properly after Copy trait changesthis parameters in clang type parserbinaryninja.interaction.ChoiceField documentationTEA (Tiny Encryption Algorithm) transformation supportSUB, ADD, MUL, and ROLQueryRelationships APIEven this list isn’t everything! There’s plenty more items not included here, check out our closed milestone on GitHub for more.