Binary Ninja Deep Thoughts

Change is in the air

“How is Binary Ninja better than X?” That’s one of the most common questions we hear. (The other–“What is the main strength of Binary Ninja?”– is always the api and the platform that it provides for other scripts and plugins to build on.)

But “How is Binary Ninja better than X?” For one, our ability to change binaries quickly and easily.

Why would you want to be able to patch or modify an existing binary? Many reasons:

  • To test a change without a long build process
  • Black box application assessments
  • Maintaining or updating legacy applications
  • Tinkering and learning about a system through binary modification
  • Third-party patching of security flaws
  • Deobfuscation

There are both low-level and high-level ways to patch binaries and we support many different methods. From low level modifications like raw hex-editing and inline assembly editing, to simple right-click patching, and even a built-in C compiler.

HEXcising

Figure 1: Hex View

The first and most obvious way to modify binaries, the Hex Editor view is also the simplest. As shown in Figure 1, the Hex Editor view is available from the lower-right hand menu or via the hotkeys H, ⌘ + H, or ⌃ + H. (Note that all hotkeys referenced in this summary are also available in the user documentation.)

You can even live edit and see the results of hex changes in real-time. This makes quick testing of opcode changes fast and easy.

  1. To begin, find a function you’d like to change in Graph or Linear View.
  2. Using the View menu at the top of the window select Split to New Window.
  3. Now, either arrange the two windows to suit, switch one of them over to hex editor and modify the bytes. You’ll see the function updated while you type. Note that for some large functions this may be a bit slower. In those cases, you may want to copy/paste the larger chunks of hex into place to make the overwrites atomic.

Live Structures

This live preview functionality is also useful for more than just disassembly of opcodes. Here’s an example using it to modify a structure and seeing the decoded result live:

Two-Click Patching

Of course, binary patching via, well, binary, only makes sense if you are either changing data or really know an architecture well. For mere mortals, we have a number of other patching methods that require less low-level familiarity with native opcodes. For example, the right-click patching menu requires only two clicks.

Patch Menu

The patch menu has a number of options dedicated to modifying conditional branches. Force a branch to Always Branch or Never Branch. Use Invert Branch in cases when you want the opposite behavior from the default. This patching requires very little explanation. It’s simple, to the point and does exactly what you’d expect.

The other two-click patch available is the Convert to NOP option which does what it says on the tin: it will NOP out a specific instruction. The plugin handles variable-width instructions, automatically using the appropriate number of bytes.

Note: if you select a conditional branch, Convert to NOP isn’t shown since it’s the same as Never Branch!

Inline Skating Edits

There are other options hiding away in that Patch menu. Inline editing allows for quick modification of a single line of assembly. Select the line of assembly you want to modify, then press e or use the right-click Patch / Edit current line menu. The text of the assembly now becomes editable and once you press enter, Binary Ninja assembles replacement bytes and writes them in place.

In instances where the replacement instruction does not evenly align with the number of bytes it is replacing, the instruction will be padded out with NOPs of the appropriate length. This is most common with variable instruction length architectures (here’s looking at you, x86 and x64), but could occur when mixing architecture types of different lengths.

One caveat: while we strive to make sure all our disassembly/re-assembly can round-trip, there are occasions where this does not work either from formatting differences or missing instructions. Please send us bug reports of specific instances.

In-depth assembly

Larger Assembly

For more in-depth changes, you’ll want to use one of:

  • Edit / Assemble
  • ⌥ + ⌘ + A
  • ⇧ + ⌃ + A
  • <right-click> Patch / Assemble

For all built-in architectures that aren’t x86 or x64, we use a custom LLVM build. For x86/x64, we use yasm.

Who put a C compiler in my disassembler?

SCC Example

One of the best kept-secrets about Binary Ninja is the Shellcode Compiler (SCC). SCC is a minimal C compiler useful for writing small injectable code for many architectures and platforms. It’s also helpful for small binary modifications. SCC is frequently much easier than writing assembly code.

SCC is a custom, from the ground up, C compiler. It supports MacOS, Windows, Linux, and FreeBSD platforms. In addition, it has CPU support for x86, x86_64, PPC32, MIPS32, Arm (not thumb), and quark (a custom CPU architecture). SCC can generate code with signature and analysis evasions built in. It will randomize placement of basic blocks and randomize its register allocator to evade naive signatures. It will also add anti-disassembly sequences.

SCC also makes short work of writing shellcode for the Windows platform which can be a hassle otherwise since Windows system calls are rearranged with each release of the operating system (or sometimes service pack). While normal userland code is expected to make use of libraries to access OS functionality, SCC will handle all the necessary symbol resolution automatically.

1
2
3
4
5
6
7
8
9
10
void* __stdcall ShellExecute(void* hwnd,
                             const char* op,
                             const char* filename,
                             const char* parameters,
                             const char* directory,
                             int showcmd) __import("shell32");
void main() {
    MessageBoxA(NULL, "Backdoor Loading", "Loading up your backdoor now!", 0);
    ShellExecute(NULL, NULL, "notepad.exe", NULL, NULL, 0);
}

Notice how MessageBoxA is already available without any extra definitions. A list of all the built-in functions is available here. Additionally, other windows functions are automatically resolved just by defining the header for them as shown above for ShellExecute.

Hardly the most earth-shattering function, but it’s a lot simpler to write in C than it would be to hand-assemble! You’ve also got several other options when using SCC. Since it was originally designed for small shellcode payloads, it has some features not found in traditional compilers:

SCC Options

Limitations

The two biggest improvements yet to be completed in the current patching system are:

  • A smart-patching mechanism
  • Symbol/binary context in assembler and compiler

A smart-patching mechanism would be capable of broader changes to a binary without the user having to worry about what else was being overwritten. Short trampolines to code-caves, or even the ability to modify segments would be desired features for a true smart-patching system. Note that BNHook implements some of these features. Check it out!

The current patching systems would be greatly improved with the context of the binaries’ types and symbols to the assembler and compiler. This would allow for far more powerful patching with knowledge already synthesized from the binary. Related to that would be the ability to emit branches to addresses via relative addressing, or even to known addresses by symbol in a non-randomized binary. This level of integration between the compiler and the disassembler doesn’t yet exist, so keep an eye out for that improvement!

Saving Changes

There are two things you might want to save when editing an analyzed file in binary ninja. First, you might want to save your analysis database containing the file, any modifications, comments, symbols, etc. This file is the .bndb (it’s actually an sqlite file, though it has an extra compression layer so it’s not trivial to inspect manually). You can explicitly save this file via File/Save Analysis Database. If you just want to save the modified file contents (usually the case if you’re binary patching), you can do so via File/Save Contents As, ⇧⌘A, or ⇧⌃A.

Summary

Binary Ninja is a great choice when modifying binaries. Not only are there multiple fast and easy UI elements, but we even have an extremely powerful compiler built right in. As always, feel free to leave us comments below. Or–even better–join our slack or use any of the many other support methods to get in touch.