From 2981774781039815538411794666534715667162 Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Tue, 9 Sep 2025 20:42:47 -0400 Subject: Docs: Better explanations of using IL labels --- docs/dev/bnil-modifying.md | 157 ++++++++++++++++----------------------------- 1 file changed, 57 insertions(+), 100 deletions(-) (limited to 'docs/dev') diff --git a/docs/dev/bnil-modifying.md b/docs/dev/bnil-modifying.md index ee57fe5f..ac521d4f 100644 --- a/docs/dev/bnil-modifying.md +++ b/docs/dev/bnil-modifying.md @@ -53,6 +53,11 @@ Based on your IL of choice, there are a bunch of places you can insert your modi - **Medium Level IL** modification is generally done right after `core.function.generateMediumLevelIL` since (as of writing) the MLIL translation is all done in that one monolithic step and future steps are simply processing and annotations. This may change some time in the future. - **High Level IL** modification is generally done right after `core.function.generateHighLevelIL` since HLIL generation is also monolithic. This also may change eventually. +### Notes on HLIL + +Cross-IL mappings are currently not implemented when modifying HLIL (see [Support](#support)), and modified functions will lose the ability to follow an expression to its MLIL equivalent (and likewise MLIL -> HLIL will be unavailable). +Support for this is planned soon, but not implemented as of Binary Ninja 5.1. + ## Terminology - An **IL Function** is a collection of **IL Instructions**, grouped into **IL Basic Blocks** @@ -62,6 +67,8 @@ Based on your IL of choice, there are a bunch of places you can insert your modi - An **Expression Index** points to an **IL Expression** and may be used as an operand of another **IL Expression**. - An **IL Instruction** is an **IL Expression** that has been added as a top-level instruction to the function with a call to `*LevelILFunction.append()` (C++: `*LevelILFunction::AddInstruction`) - An **Instruction Index** is assigned to an **IL Expression** that is added as an **IL Instruction**. Child expressions of an **IL Instruction** do not inherently have an **Instruction Index**, though the API tries to provide this for you. +- A **Mutate Transformation** is a simple modification of **IL Instructions** in an **IL Function** as per [Replacing Trivial Instructions (Mutate Transformation)](#replacing-trivial-instructions-mutate-transformation) below. +- A **Copy Transformation** is a more in-depth modification of an **IL Function** which involves copying its **IL Instructions** into a newly constructed **IL Function** with modifications made along the way, as per [Adding Instructions and Replacing Multiple Instructions (Copy Transformation)](#adding-instructions-and-replacing-multiple-instructions-copy-transformation) below. ## Writing a Transformation @@ -172,7 +179,7 @@ Then, define a new Activity on the Workflow, which allows you to run your code t A more in-depth explanation of the Workflows system is available [here](./workflows.md), with complete documentation of the Eligibility system and Workflows in general. This guide, however, will just give enough of an example for you to get to writing IL modification code. -### Replacing Trivial Instructions +### Replacing Trivial Instructions (Mutate Transformation) Replacing exactly one instruction with exactly one other instruction is relatively simple: @@ -185,9 +192,9 @@ Replacing exactly one instruction with exactly one other instruction is relative If you wish to replace more than one instruction, or replace an instruction with more than one new instruction, you will need to use the more complicated method described below. -### Adding Instructions and Replacing Multiple Instructions +### Adding Instructions and Replacing Multiple Instructions (Copy Transformation) -If you want to insert new instructions into a function, or want to replace an instruction with than one instruction, you will need to construct a new **IL Function** based on the original **IL Function** but with your changes. +If you want to insert new instructions into a function, or want to replace an instruction with than one instruction, you will need to construct a new **IL Function** based on the original **IL Function**, and make your changes while copying the instructions. This is a rather cumbersome process and it can be easy to make mistakes. First, you need to construct a new **IL Function** based on the existing function. @@ -441,15 +448,19 @@ You may realize this is rather at odds with the section below on having a [dry r Sadly, there is currently no good solution for that, since the IL mappings are generated during assignment to the Analysis Context. This may change in future versions, but is required for now. -### Using IL Labels and GOTO/IF Instructions +### Using GOTO/IF Instructions and IL Labels + +When you are trying to insert `*LIL_GOTO`, `*LIL_IF`, and `*LIL_JUMP_TO` instructions, you will need to specify the IL destination as a `*LevelILLabel`. +Your destination must be a properly marked label, which is actually rather tricky to obtain. +This is because **there is currently no way to get a label for already-emitted IL Instructions**, so if you want to modify the control flow of a function, you will need to do a **Copy Transformation** [as described above](#adding-instructions-and-replacing-multiple-instructions-copy-transformation). +This may change in future versions. + +Depending on your desired behavior, there are a few ways to write this: -When you are trying to insert `*LIL_GOTO`, `*LIL_IF`, and similar instructions, you will need to specify the IL destination as a `*LevelILLabel`. -To properly use a label, you must call `mark_label` on the **IL Function** _right before emitting the instruction that the label targets_, which is always at the start of an **IL Basic Block**. -Your `*LIL_GOTO` instruction can come either before or after its target, but you must make sure to use the same `*LevelILLabel` object in the call to `*LevelILFunction.goto()` (C++: `*LevelILFunction::Goto()`) and `*LevelILFunction.mark_label()` (C++: `*LevelILFunction::MarkLabel`). -Labels are not preserved when constructing a new function during transformation, so in practice you should not assume calls to `get_label_for_source_instruction` will always return a usable label. -This means, if you are emitting any of these control-flow instructions, you will need to transform the entire function in the process, as described in [Adding Instructions and Replacing Multiple Instructions](#adding-instructions-and-replacing-multiple-instructions), so you are able to call `mark_label` at the appropriate time. +#### Jumping to Previously Existing IL Blocks -An example of label creation and usage is as follows: +If the target of your branch is the start of an IL Basic Block that existed in the IL Function already, you can use `*LevelILFunction.get_label_for_source_instruction` (C++: `*LevelILFunction::GetLabelForSourceInstruction`) when doing a **Copy Transformation**. +Simply call `*LevelILFunction.get_label_for_source_instruction` (C++: `*LevelILFunction::GetLabelForSourceInstruction`) to get a label for the block where you want to go. === "Python" @@ -458,29 +469,15 @@ An example of label creation and usage is as follows: # Setup as described in the sections above old_func = context.mlil new_func = MediumLevelILFunction(old_func.arch, low_level_il=context.llil) + + # Calling prepare_to_copy_function creates labels in new_func + # for all blocks in old_func, accessible via get_label_for_source_instruction new_func.prepare_to_copy_function(old_func) - - # Keep a running list of labels for MLIL_GOTO targets - # Stored in a map of { :