summaryrefslogtreecommitdiff
path: root/docs/dev/bnil-llil.md
blob: db251ab369a226f0287dd98f157d2c465e07d8af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# Binary Ninja Intermediate Language: Low Level IL

Make sure to checkout the [BNIL overview](bnil-overview.md) first if you haven't already. Or feel free to skip to [part 2](bnil-mlil.md) which covers MLIL, or [part 3](bnil-hlil.md) which covers HLIL. This developer guide is intended to cover some mechanics of LLIL to distinguish it from the other ILs in the BNIL family.

If you've already read the introduction, let's get right into the details of LLIL!

![BNIL-LLIL Selected](../img/BNIL-llil.png)

The Lifted IL is very similar to the LLIL and is primarily of interest for Architecture plugin authors. If you're writing an analysis plugin, you'll always want to be working at LLIL or higher. During each stage of the lifting process a number of transformations take place, and each layer of IL can have different instructions. Because of this, you can not rely on an instruction from one layer existing in another.

## Introduction by example

Since doing is the easiest way to learn let's start with a simple example binary and step through analyzing it using the python console.

![Low Level IL Option >](../img/llil-option.png)

 - Download [chal1](../files/chal1) and open it with Binary Ninja
 - Next, bring up the `Low Level IL` view by clicking in the view drop down at the top of the pane (or alternatively, use the `i` key to cycle view levels)
 - Navigate to main (`g`, then "main", or double-click it in the function list)
 - Finally, bring up the python console using: `~`

Next, enter the following in the console:

```pycon
>>> for block in current_function.low_level_il:
... 	for instr in block:
... 		print (instr.address, instr.instr_index, instr)
...
4196422 0 push(rbp)
4196423 1 rbp = rsp {var_8}
4196426 2 rsp = rsp - 0x110
4196433 3 rax = rbp - 0xc0 {var_c8}
...
```

This will print out all the LLIL instructions in the current function. How does this code work?

First we use the global magic variable `current_function` which gives us the python object [`function.Function`](https://api.binary.ninja/binaryninja.function-module.html#binaryninja.function.Function) for whatever function is currently selected in the UI. The variable is only usable from the python console, and shouldn't be used for headless plugins. In a script you can either use the function that was passed in if you [registered your plugin](https://api.binary.ninja/binaryninja.plugin-module.html#binaryninja.plugin.PluginCommand.register_for_function) to handle functions, or you can compute the function based on [a specific address](https://api.binary.ninja/binaryninja.binaryview-module.html?highlight=get_functions_at#binaryninja.binaryview.BinaryView.get_functions_at), or maybe even just iterate over all the functions in a BinaryView (`for func in bv.functions:`).

Next we get the [`lowlevelil.LowLevelILFunction`](https://api.binary.ninja/binaryninja.lowlevelil-module.html#binaryninja.lowlevelil.LowLevelILFunction) from the `Function` class: `current_function.low_level_il`. Iterating over the `LowLevelILFunction` class provides access to the [`lowlevelil.LowLevelILBasicBlock`](https://api.binary.ninja/binaryninja.lowlevelil-module.html#binaryninja.lowlevelil.LowLevelILBasicBlock) classes for this function. Inside the loop we can now iterate over the `LowLevelILBasicBlock` class which provides access to the individual [`lowlevelil.LowLevelILInstruction`](https://api.binary.ninja/binaryninja.lowlevelil-module.html#binaryninja.lowlevelil.LowLevelILInstruction) classes.

Finally, we can print out the attributes of the instruction. We first print out `address` which is the address of the corresponding assembly language instruction.  Next, we print the `instr_index`, this you can think of as the address of the IL instruction. Since translating assembly language is a many-to-many relationship, we may see multiple IL instructions needed to represent a single assembly language instruction, and thus each IL instruction needs to have its own index separate from its address. Finally, we print out the instruction text.

In python, iterating over a class is a distinct operation from subscripting. This separation is used in the `LowLevelILFunction` class. If you iterate over a `LowLevelILFunction` you get a list of `LowLevelILBasicBlocks`, however if you subscript a `LowLevelILFunction` you actually get the `LowLevelILInstruction` whose `instr_index` corresponds to the subscript:

```pycon
>>> list(current_function.low_level_il)
[<block: x86_64@0x0-0x3f>, <block: x86_64@0x3f-0x45>, <block: x86_64@0x45-0x47>,
 <block: x86_64@0x47-0x53>, <block: x86_64@0x53-0x57>, <block: x86_64@0x57-0x5a>]
>>> type(current_function.low_level_il[0])
<class 'binaryninja.lowlevelil.LowLevelILInstruction'>
>>> current_function.low_level_il[0]
<il: push(rbp)>
```

## Low Level IL Instructions
Now that we've established how to access LLIL Functions, Blocks, and Instructions, let's focus in on the instructions themselves. LLIL instructions are infinite length and structured as an expression tree. An expression tree means that instruction operands can be composed of operation. Thus, we can have an IL instruction like this:

```text
eax = eax + ecx * 4
```

The tree for such an instruction would look like:

```text
   =
  / \
eax  +
    / \
  eax  *
      / \
    ecx  4
```
There are quite a few reasons that we chose to use expression trees that we won't go into in detail here, but suffice it to say lifting to this form and reading this form are both much easier than other forms.

Now let's get back to the examples. First let's pick an instruction to work with:

```pycon
>>> instr = current_function.low_level_il[2]
>>> instr
<il: rsp = rsp - 0x110>
```

For the above instruction, we have a few operations we can perform:

* **address** - returns the virtual address

```pycon
>>> hex(instr.address)
'0x40084aL'
```

* **function** - returns the containing function

```pycon
>>> instr.function
<binaryninja.lowlevelil.LowLevelILFunction object at 0x111c79810>
```

* **instr_index** - returns the LLIL index

```pycon
>>> instr.instr_index
2
```

* **operands** - returns a list of all operands.

```pycon
>>> instr.operands
['rsp', <il: rsp - 0x110>]
```

* **operation** - returns the enumeration value of the current operation

```pycon
>>> instr.operation
<LowLevelILOperation.LLIL_SET_REG: 1>
```

* **src** - returns the source operand

```pycon
>>> instr.src
<il: rsp - 0x110>
```

* **dest** - returns the destination operand

```pycon
>>> instr.dest
'rsp'
```

* **size** - returns the size of the operation in bytes (in this case we have an 8 byte assignment)

```pycon
>>> instr.size
8L
```

Now with some knowledge of the `LowLevelIL` class let's try to do something with it. Let's say our goal is to find all the times the register `rdx` is written to in the current function. This code is straight forward:

```pycon
>>> for block in current_function.low_level_il:
...  for instr in block:
...   if instr.operation == LowLevelILOperation.LLIL_SET_REG and instr.dest.name == 'rdx':
...    print (instr.address, instr.instr_index, instr)
...
4196490 14 rdx = [rax].q
4196500 16 rdx = [rax + 8].q
4196511 18 rdx = [rax + 0x10].q
4196522 20 rdx = [rax + 0x18].q
4196533 22 rdx = [rax + 0x20].q
4196544 24 rdx = [rax + 0x28].q
4196798 77 rdx = [0x602090].q
```

## The Instructions

Going into gross detail on all the instructions is out of scope of this article, but we'll go over the different instructions types and speak generally about how they are used.


### Registers, Constants & Flags

When parsing an instruction tree the terminals are registers, constants and flags. This provides the basis from which all instructions are built.

* `LLIL_REG` - A register, terminal
* `LLIL_CONST` - A constant integer value, terminal
* `LLIL_SET_REG` - Sets a register to the results of the IL operation in `src` attribute.
* `LLIL_SET_REG_SPLIT` - Uses a pair of registers as one double sized register, setting both registers at once.
* `LLIL_SET_FLAG` - Sets the specified flag to the IL operation in `src` attribute.

### Memory Load & Store

Reading and writing memory is accomplished through the following instructions.

* `LLIL_LOAD` - Load a value from memory.
* `LLIL_STORE` - Store a value to memory.
* `LLIL_PUSH` - Store value to stack; adjusting stack pointer by `sizeof(value)` after the store.
* `LLIL_POP` - Load value from stack; adjusting stack pointer by `sizeof(value)` after the store.


### Control Flow & Conditionals

Control flow transferring- and comparison instructions are straightforward enough, but one instruction that deserves more attention is the `if` instruction. To understand the `if` instruction we need to first understand the concept of labels.

Labels function much like they do in C code. They can be put anywhere in the emitted IL and serve as a destination for the `if` and `goto` instructions.  Labels are required because one assembly language instruction can translate to multiple IL instructions, and you need to be able to branch to any of the emitted IL instructions. Let's consider the following x86 instruction `cmove` (Conditional move if equal flag is set):

```nasm
test    eax, eax
cmove  eax, ebx
```

To translate this instruction to IL we have to first create true and false labels. Then we emit the `if` instruction, passing it the proper conditional and labels. Next we emit the true label, then we emit the set register instruction and a goto false label instruction. This results in the following output:

```text
0 @ 00000002 if (eax == 0) then 1 else 3
1 @ 00000002 eax = ebx
2 @ 00000002 goto 3
```

As you can see from the above code, labels are really just used internally and aren't explicitly marked. In addition to `if` and `goto`, the `jump_to` IL instruction is the only other instruction that operates on labels.  The rest of the IL control flow instructions operate on addresses rather than labels, much like actual assembly language instructions. Note that an architecture plugin author should not be emitting `jump_to` IL instructions as those are generated by the analysis automatically.

* `LLIL_JUMP` - Branch execution to the result of the IL operation.
* `LLIL_JUMP_TO` - Jump table construct, contains an expression and list of possible targets.
* `LLIL_CALL` - Branch execution to the result of the IL operation.
* `LLIL_RET` - Return execution to the caller.
* `LLIL_NORET` - Instruction emitted automatically after syscall or call instruction which cause the program to terminate.
* `LLIL_SYSCALL` - System call instruction
* `LLIL_TAILCALL ` - This instruction calls the expression `dest` using `params` as input and `output` for return values
* `LLIL_IF` - `If` provides conditional execution. If condition is true execution branches to the true label and false label otherwise.
* `LLIL_GOTO` - `Goto` is used to branch to an IL label, this is different from jump since jump can only jump to addresses.
* `LLIL_FLAG_COND` - Returns the flag condition expression for the specified flag condition.
* `LLIL_CMP_E` - equality
* `LLIL_CMP_NE` - not equal
* `LLIL_CMP_SLT` - signed less than
* `LLIL_CMP_ULT` - unsigned less than
* `LLIL_CMP_SLE` - signed less than or equal
* `LLIL_CMP_ULE` - unsigned less than or equal
* `LLIL_CMP_SGE` - signed greater than or equal
* `LLIL_CMP_UGE` - unsigned greater than or equal
* `LLIL_CMP_SGT` - signed greater than
* `LLIL_CMP_UGT` - unsigned greater than


### The Arithmetic & Logical Instructions

LLIL implements the most common arithmetic as well as a host of more complicated instruction which make translating from assembly much easier. Most arithmetic and logical instruction contain `left` and `right` attributes which can themselves be other IL instructions.

The double precision instruction multiply, divide, modulus instructions are particularly helpful for instruction sets like x86 whose output/input can be double the size of the input/output.

* `LLIL_ADD` - Add
* `LLIL_ADC` - Add with carry
* `LLIL_SUB` - Subtract
* `LLIL_SBB` - Subtract with borrow
* `LLIL_AND` - Bitwise and
* `LLIL_OR` - Bitwise or
* `LLIL_XOR` - Exclusive or
* `LLIL_LSL` - Logical shift left
* `LLIL_LSR` - Logical shift right
* `LLIL_ASR` - Arithmetic shift right
* `LLIL_ROL` - Rotate left
* `LLIL_RLC` - Rotate left with carry
* `LLIL_ROR` - Rotate right
* `LLIL_RRC` - Rotate right with carry
* `LLIL_MUL` - Multiply single precision
* `LLIL_MULU_DP` - Unsigned multiply double precision
* `LLIL_MULS_DP` - Signed multiply double precision
* `LLIL_DIVU` - Unsigned divide single precision
* `LLIL_DIVU_DP` - Unsigned divide double precision
* `LLIL_DIVS` - Signed divide single precision
* `LLIL_DIVS_DP` - Signed divide double precision
* `LLIL_MODU` - Unsigned modulus single precision
* `LLIL_MODU_DP` - Unsigned modulus double precision
* `LLIL_MODS` - Signed modulus single precision
* `LLIL_MODS_DP` - Signed modulus double precision
* `LLIL_NEG` - Sign negation
* `LLIL_NOT` - Bitwise complement
* `LLIL_BSWAP` - Reverse the byte order of `src`
* `LLIL_POPCNT` - Population count (number of set bits) of `src`
* `LLIL_CLZ` - Count leading zero bits of `src`; the result is `8 * size` when `src` is zero
* `LLIL_CTZ` - Count trailing zero bits of `src`; the result is `8 * size` when `src` is zero
* `LLIL_RBIT` - Reverse the bit order of `src`
* `LLIL_CLS` - Count leading sign bits of `src` (the number of bits below the sign bit that match it)
* `LLIL_MINS` - Signed minimum of `left` and `right`
* `LLIL_MAXS` - Signed maximum of `left` and `right`
* `LLIL_MINU` - Unsigned minimum of `left` and `right`
* `LLIL_MAXU` - Unsigned maximum of `left` and `right`
* `LLIL_ABS` - Signed absolute value of `src`
* `LLIL_TEST_BIT ` - Test if bit `right` in expression `left` is set
* `LLIL_BOOL_TO_INT ` - Converts a bool `src` to an integer

### Floating Point Operations
* `LLIL_FLOAT_CONST` - Floating point constant value
* `LLIL_FADD` - Floating point add
* `LLIL_FSUB` - Floating point subtraction
* `LLIL_FMUL` - Floating point multiplication
* `LLIL_FDIV` - Floating point division
* `LLIL_FSQRT` - Floating point square root
* `LLIL_FNEG` - Floating point negate
* `LLIL_FABS` - Floating point absolute value
* `LLIL_FLOAT_TO_INT` - Floating point convert a floating point to an integer
* `LLIL_INT_TO_FLOAT` - Floating point convert an integer to a floating point
* `LLIL_FLOAT_CONV` -
* `LLIL_ROUND_TO_INT` - Rounds to the nearest integer
* `LLIL_FLOOR` - Returns the floor of a floating point value
* `LLIL_CEILING` - Returns the ceiling of a floating point value
* `LLIL_FTRUNC` - Computes the floating point truncation of the IEEE754 number in `src`

### Floating Point Conditionals

These are identical to their native counterparts but are lifted separately so that the operations can impact different flags. See [Control Flow & Conditionals](#control-flow-conditionals) above.

* `LLIL_FCMP_E ` - See above
* `LLIL_FCMP_NE ` - See above
* `LLIL_FCMP_LT ` - See above
* `LLIL_FCMP_LE ` - See above
* `LLIL_FCMP_GE ` - See above
* `LLIL_FCMP_GT ` - See above
* `LLIL_FCMP_O ` - See above
* `LLIL_FCMP_UO ` - See above

### Special instructions

The rest of the instructions are pretty much self-explanatory to anyone with familiarity with assembly languages.

* `LLIL_BP` - Breakpoint instruction
* `LLIL_EXTERN_PTR` - A synthesized (fake) pointer to something which doesn't exist within the memory space of the current binary
* `LLIL_INTRINSIC ` - Intrinsics are operations with `output` and `params` and an `intrinsic` where the exact behavior is not modelled but the dataflow system can be improved by annotating the inputs and outputs. An example intrinsic would CPU AES instructions where the exact behavior is not modelled, but the inputs and outputs are.
* `LLIL_INTRINSIC_SSA ` - SSA form of the `LLIL_INTRINSIC` operation
* `LLIL_MEMORY_INTRINSIC_SSA ` - Memory versioning SSA form of the `LLIL_INTRINSIC` operation
* `LLIL_NOP` - No operation
* `LLIL_SX` - Sign extend
* `LLIL_TRAP` - Trap instruction
* `LLIL_UNDEF` - Undefined instruction
* `LLIL_UNIMPL` - Unimplemented instruction
* `LLIL_UNIMPL_MEM` - Unimplemented memory access instruction
* `LLIL_ZX` - Zero extend
* `LLIL_MEM_PHI ` - A memory `PHI` represents memory modifications that could have occured down different source basic blocks similar to a `VAR_PHI`.
* `LLIL_LOW_PART ` - `size` bytes from the low end of `src` expression

### Currently Undocumented

* `LLIL_FLAG ` -
* `LLIL_FLAG_BIT ` -
* `LLIL_FLAG_GROUP ` -
* `LLIL_FLAG_BIT_SSA ` -
* `LLIL_FLAG_PHI ` -
* `LLIL_FLAG_SSA ` -
* `LLIL_TAILCALL_SSA ` -