Binary Ninja Intermediate Language Series, Part 0: Overview¶
The Binary Ninja Intermediate Language (BNIL) is a semantic representation of the assembly language instructions for a native architecture in Binary Ninja. BNIL is actually a family of intermediate languages that work together to provide functionality at different abstraction layers.
BNIL is a tree-based, architecture-independent intermediate representation of machine code used throughout Binary Ninja.
During each step a number of optimizations and analysis passes occur, resulting in a higher and higher level of abstraction the further through the analysis binaries are processed.
Except that overview isn't telling the whole story! The real stack of BNIL actually looks like this:
All of the various ILs (with the exception of the SSA forms) are intended to be easily human-readable and look much like pseudo-code. There is some shorthand notation that is used throughout the ILs, though, explained below:
First, all comparisons are either signed
s<= or unsigned
Besides the typical
&& bitwise operators, BNIL makes use of
zx to indicate
Expressions in BNIL can have one of the following suffixes to indicate a size:
.q -- Qword (8 bytes) .d -- Dword (4 bytes) .w -- Word (2 bytes) .b -- Byte (1 byte)
Note that floating point IL instructions have their own possible size suffixes:
.h -- Half (2 bytes) .s -- Single (4 bytes) .d -- Double (8 bytes) .t -- Ten (10 bytes) .o -- Oword (16 bytes)
Additionally, floating point IL operations are indicated with a prefixed
f* -- Floating-point multiplication f/ -- Floating-point division f+ -- Floating-point addition f- -- Floating-point subtraction
Offsets into variables are specified with a
:$offset syntax indicating how many bits from the bottom of the variable the expression is referencing.
So putting all that together, if you were to see the following in an IL expression:
It represents the lower 32-bits of variable
rax_2, sign-extended into a 64-bit variable.