From 3890253606296374983392205858649196758261 Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Tue, 9 Sep 2025 16:03:08 -0400 Subject: IL Modifying docs: Add section on labels and GOTOs --- docs/dev/bnil-modifying.md | 185 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 6 deletions(-) (limited to 'docs/dev') diff --git a/docs/dev/bnil-modifying.md b/docs/dev/bnil-modifying.md index b888ed6e..ee57fe5f 100644 --- a/docs/dev/bnil-modifying.md +++ b/docs/dev/bnil-modifying.md @@ -63,7 +63,7 @@ Based on your IL of choice, there are a bunch of places you can insert your modi - 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. -## Writing The Plugin +## Writing a Transformation Once you figure out which level of IL you want to modify, and where in the Workflow pipeline you want to do modifications, it is time to write some code! @@ -206,7 +206,7 @@ Let's call the new function `new_func` and the existing function `old_func`. new_func = MediumLevelILFunction(old_func.arch, low_level_il=context.llil) # Tell the new function that we are copying from an existing function - # (this transfers various metadata like block labels) + # (this transfers various metadata like some block labels) new_func.prepare_to_copy_function(old_func) # continues ... @@ -232,7 +232,7 @@ Let's call the new function `new_func` and the existing function `old_func`. ); // Tell the new function that we are copying from an existing function - // (this transfers various metadata like block labels) + // (this transfers various metadata like some block labels) newFunc->PrepareToCopyFunction(oldFunc); // Continues... @@ -256,7 +256,7 @@ When you reach a part where you want to insert new instructions (or replace inst # Copy each block in the old function to the new function for old_block in old_func.basic_blocks: - # Copy block labels and tell new IL instructions they came from this block + # Copy some block labels and tell new IL instructions they came from this block new_func.prepare_to_copy_block(old_block) # Copy each instruction from the old block to the new function @@ -280,7 +280,7 @@ When you reach a part where you want to insert new instructions (or replace inst // Copy each block in the old function to the new function for (auto& oldBlock: oldFunc->GetBasicBlocks()) { - // Copy block labels and tell new IL instructions they came from this block + // Copy some block labels and tell new IL instructions they came from this block newFunc->PrepareToCopyBlock(oldBlock); // Copy each instruction from the old block to the new function @@ -441,7 +441,180 @@ 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. -### Notes on HLIL +### Using IL Labels and GOTO/IF Instructions + +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. + +An example of label creation and usage is as follows: + +=== "Python" + + ```py + def rewrite_action(context: AnalysisContext): + # Setup as described in the sections above + old_func = context.mlil + new_func = MediumLevelILFunction(old_func.arch, low_level_il=context.llil) + new_func.prepare_to_copy_function(old_func) + + # Keep a running list of labels for MLIL_GOTO targets + # Stored in a map of { :