diff options
Diffstat (limited to 'docs/dev')
| -rw-r--r-- | docs/dev/concepts.md | 73 | ||||
| -rw-r--r-- | docs/dev/cookbook.md | 24 |
2 files changed, 85 insertions, 12 deletions
diff --git a/docs/dev/concepts.md b/docs/dev/concepts.md index daf120b1..77afd33e 100644 --- a/docs/dev/concepts.md +++ b/docs/dev/concepts.md @@ -23,6 +23,79 @@ In the Binary Ninja API, there are often two parallel sets of functions with `_a ## Concepts for ILs +### Walking ILs + +Because our ILs are tree-based, some naive plugins that walk IL looking for specific operations will miss instructions that are part of nested expressions. While there is generally less folding in [MLIL](https://docs.binary.ninja/dev/bnil-mlil.html), making it better target for simple loops like: + +```python +for i in bv.mlil_instructions: + if isinstance(i, Localcall): + print(i.params) +``` + +it's still possible to miss instructions with this approach. Additionally, in HLIL it's even easier to miss instructions as there is significantly more nesting. Accordingly we created [`traverse`](https://api.binary.ninja/binaryninja.highlevelil-module.html#binaryninja.highlevelil.HighLevelILFunction.traverse) APIs to walk these tree-based ILs and match whatever property you're interested in. Here are several examples: + +```python +def find_strcpy(i, t) -> str: + match i: + case HighLevelILCall(dest=HighLevelILConstPtr(constant=c)) if c in t: + return str(i.params[1].constant_data.data) + +t = [ + bv.get_symbol_by_raw_name('__builtin_strcpy').address, + bv.get_symbol_by_raw_name('__builtin_strncpy').address +] + +list(current_hlil.traverse(find_strcpy, t)) + + +def get_memcpy_data(i, t) -> bytes: + match i: + case HighLevelILCall(dest=HighLevelILConstPtr(constant=c)) if c == t: + return bytes(i.params[1].constant_data.data) + +# Iterate through all instructions in the HLIL +t = bv.get_symbol_by_raw_name('__builtin_memcpy').address +list(current_hlil.traverse(get_memcpy_data, t)) + + +# find all the calls to __builtin_strcpy and get their values +def find_strcpy(i, t) -> str: + match i: + case HighLevelILCall(dest=HighLevelILConstPtr(constant=c)) if c in t: + return str(i.params[1].constant_data.data) + +t = [ + bv.get_symbol_by_raw_name('__builtin_strcpy').address, + bv.get_symbol_by_raw_name('__builtin_strncpy').address +] +list(current_hlil.traverse(find_strcpy, t)) + +# collect the number of parameters for each function call +def param_counter(i) -> int: + match i: + case HighLevelILCall(): + return len(i.params) +list(current_hlil.traverse(param_counter)) + + +# collect the target of each call instruction if its constant +def collect_call_target(i) -> None: + match i: + case HighLevelILCall(dest=HighLevelILConstPtr(constant=c)): + return c +set([hex(a) for a in current_hlil.traverse(print_call_target)]) + + +# collect all the Variables named 'this' +def collect_this_vars(i) -> Variable: + match i: + case HighLevelILVar(var=v) if v.name == 'this': + return v +list(v for v in current_hlil.traverse(collect_this_vars)) + +``` + ### Mapping between ILs ILs in general are critical to how Binary Ninja analyzes binaries and we have much more [in-depth](bnil-overview.md) documentation for BNIL (or Binary Ninja Intermediate Language -- the name given to the family of ILs that Binary Ninja uses). However, one important concept to summarize here is that the translation between each layer of IL is many-to-many. Going from disassembly to LLIL to MLIL can result in more or less instructions at each step. Additionally, at higher levels, data can be copied, moved around, etc. You can see this in action in the UI when you select a line of HLIL and many LLIL or disassembly instructions are highlighted. diff --git a/docs/dev/cookbook.md b/docs/dev/cookbook.md index abd1a089..eb1dbb20 100644 --- a/docs/dev/cookbook.md +++ b/docs/dev/cookbook.md @@ -11,7 +11,7 @@ One of the best ways to learn a complicated API is to simply find the right exam ## Recipes -#### Getting all functions in a binary +### Getting all functions in a binary ```python for func in bv.functions: @@ -21,7 +21,7 @@ for func in bv.functions: print(func.function_type) ``` -#### Getting a specific function +### Getting a specific function ```python func = bv.get_functions_by_name(here)[0] # Multiple functions can share the same name! @@ -32,7 +32,7 @@ func = bv.get_function_containing(here) # Functions that contain the given addr # But when working with ILs, addresses are approximate and can change for any given instruction ``` -#### All forms of a function: +### All forms of a function ```python for func in bv.functions: @@ -49,7 +49,7 @@ for func in bv.functions: base_function = <any>_level_il.source_function # Some helpers are only on the base function object! ``` -#### All decompiled instructions in a binary +### All decompiled instructions in a binary ```python for func in bv.functions: @@ -73,7 +73,7 @@ for inst in bv.hlil_instructions: print(f"{inst.address} : {inst}") ``` -#### Getting the decompiled instruction at an address +### Getting the decompiled instruction at an address ```python func = bv.get_functions_containing(here)[0] # You should probably be more robust than this @@ -91,13 +91,13 @@ hlil_inst.llils # All llil instructions that contributed to this hlil instructi ``` -#### All callers of a function +### All callers of a function ```python current_function.callers ``` -#### All locations where a function is called +### All locations where a function is called ```python for site in current_function.caller_sites: @@ -105,7 +105,7 @@ for site in current_function.caller_sites: inst = site.hlil ``` -#### All calls and call instructions in a function: +### All calls and call instructions in a function: ```python for site in current_function.call_sites: @@ -138,7 +138,7 @@ for ref in current_function.caller_sites: # For bonus points, query the range analysis using .possible_values ``` -### Search for a good nop-slide? +### Search for a good nop-slide ```python bv.find_next_data(0, b"\x90" * 10) @@ -161,7 +161,7 @@ for ref in current_function.caller_sites: print(ref.hlil) ``` -#### Common variable APIs +### Common variable APIs ```python for func in bv.functions: @@ -185,7 +185,7 @@ for func in bv.functions: use_insts = func.hlil.ssa_form.get_ssa_variable_uses(ssa_vars[0]) # There's only ever one ssa definition, but potentially many uses ``` -#### Working with Tags +### Working with Tags ```python # Data tags @@ -198,7 +198,7 @@ current_function.add_tag("Important", "Look at this later!") current_function.add_tag("Bug", "I think there's an overflow here?", here) ``` -#### Logging +### Logging ```python log.log_debug("Debug logs are hidden by default") |
