Binary Ninja Blog

Introducing the nanoMIPS Architecture Plugin for Binary Ninja

One of the more frustrating situations as a reverse engineer is when the architecture of your target is not supported by your decompiler. So, today, let’s dive into one of our latest creations: the official Binary Ninja nanoMIPS architecture plugin.

2024-09-13 Edit: The nanoMIPS architecture is now part of our Binary Ninja Ultimate edition! See more details here.

nanoMIPS and the Architecture Plugin

nanoMIPS is a variable-length ISA whose instructions can be 2, 4, or 6 bytes long. It is mainly designed for embedded devices and, as its name suggests, it is more lightweight than the MIPS architecture.

nanoMIPS and MIPS share many assembly instructions, but their encodings are different. As a result, a MIPS disassembler cannot be used for nanoMIPS. We wrote the disassembler from scratch following the ISA documentation and then lifted the nanoMIPS code to LLIL. Thanks to the design of BNIL, this gives us full decompilation of nanoMIPS code “for free”! Below is an example of the HLIL for a simple function that does string XOR. Looking at this, you might not even know that it’s a compiled nanoMIPS function at all.

string xor

For reference, you can check out the disassembly of the same function as well:

string xor

(The code snippet and the nanoMIPS toolchain used to build it aren’t ours.)

In the above function, the disassembly shows the compiler does division-by-multiplication, a common optimization technique. But, thanks to the flexibility of Binary Ninja’s analysis pipeline, we’ve managed to simplify it to i u% 0xc without any special treatment for nanoMIPS.

division-by-multiplication

MD1ROM Binary View

If you work with nanoMIPS code, chances are you have already seen mobile baseband firmware in md1rom format. For Android phones from several vendors, the md1rom firmware can be extracted from a rooted device or from the fastboot ROM.

We have developed a Binary View to parse and load any firmware in md1rom format. As with our other Binary Views, the code is open-source. Interestingly, the md1rom firmware can also contain symbol names for the majority of functions, which can be quite helpful for analysis. Below is a screenshot for several AES functions in a specific firmware:

AES functions

The md1rom Binary View is available in the base Binary Ninja product, starting from version 4.1.5036-dev.

If you load an md1rom firmware without the nanoMIPS architecture plugin, it will be able to create the segments/sections, and process the symbols within it. Of course, it works best with the nanoMIPS architecture plugin, and you can see from the feature map that Binary Ninja gradually analyzes the code in a 75MB firmware and eventually achieves almost 100% code coverage:

Feature map

A Small Crackme

Nobody would complain if we wrapped up the blog post here since most, if not all, real-world nanoMIPS binaries are proprietary. But we’d also like to show off a nanoMIPS crackme before we finish. It is called baby MIPS and was part of the 0CTF 2020 qualifiers.

The file is an ELF. Looking at the main function, we can see that the flag has a length of 0x3e, it must start with flag{, and it must end with }.

crackme_main

The code then puts the individual characters of the string between the {} into a buffer (which is a 9x9 board based on later analysis). The buffer has been pre-populated with some characters, and the characters from the flag are only put into the places that are zero (not populated yet).

This is what the buffer looks like before the operation:

crackme_buffer

Then, a check function is called and the program prints Right or Wrong depending on the result.

Result Checking

The check function is simple: It calls another three functions and all of them must return true. They all look similar, so we will only analyze one of them.

crackme_check

Now, we look at check2 as an example. This code iterates over every line of the board and puts all the elements in a line into a buffer. It then calls a function to validate the line elements. Every such validation must succeed.

crackme_check2

Inside the validation function, there is a switch case that counts the number of occurrences of certain characters. The characters being counted are acdeqswxz.

crackme_tuple

You can see how the switch-case is handled by the versatile brsc instruction:

crackme_brsc

There is a jump table at 0x400798 which holds the relative distance to jump. The lwxs loads a specific entry from it based on the index. Then the brsc instruction does a relative jump based on the value of that.

crackme_jumptable

If you are not super familiar with nanoMIPS instructions, you can always refer to the LLIL and see how the code works behind the scenes:

crackme_LLIL

Now, let us get back to the crackme. The code checks whether the number of occurrences is all one, effectively checking whether the input string is a tuple of acdeqswxz.

To sum up, the crackme checks whether each row, column, and square contains a tuple of acdeqswxz. Now you should see this is a Sudoku, and it can be solved by any Sudoku solver.

Interested? Let us know!

Unlike many of our other architecture plugins, the nanoMIPS architecture plugin must be purchased separately from the base product. If you are interested, contact support for a quote.