summaryrefslogtreecommitdiff
path: root/docs/dev/cookbook.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/dev/cookbook.md')
-rw-r--r--docs/dev/cookbook.md163
1 files changed, 153 insertions, 10 deletions
diff --git a/docs/dev/cookbook.md b/docs/dev/cookbook.md
index 61cd6386..abd1a089 100644
--- a/docs/dev/cookbook.md
+++ b/docs/dev/cookbook.md
@@ -7,31 +7,110 @@ One of the best ways to learn a complicated API is to simply find the right exam
- [Gist Collection](https://gist.github.com/psifertex/6fbc7532f536775194edd26290892ef7): Jordan's collection of python examples usually created for (or contributed by) customers
- [Offline examples](https://github.com/Vector35/binaryninja-api/tree/dev/python/examples): These examples are especially useful because they're included in your offline install as well, just look in the examples/python subfolder wherever Binary Ninja installed
- That said, most of those examples tend to be more complex and so the following recipes are meant to be simple but useful building-blocks with which to learn useful techniques:
+ That said, most of those examples tend to be more complex and so the following recipes are meant to be simple but useful building-blocks with which to learn useful techniques. Many of them also make use of the built-in Python console's [magic variables](../guide/index.md#magic-console-variables):
## Recipes
-### Accessing cross references
+#### Getting all functions in a binary
-This recipe is useful for iterating over all of the HLIL cross-references of a given interesting function:
+```python
+for func in bv.functions:
+ print(func.name)
+ print(func.start)
+ print(func.parameter_vars)
+ print(func.function_type)
+```
+
+#### Getting a specific function
```python
-for ref in current_function.caller_sites:
- print(ref.hlil)
+func = bv.get_functions_by_name(here)[0] # Multiple functions can share the same name!
+func = bv.get_function_at(here) # Shortcut for the next one
+func = bv.get_functions_at(here)[0] # Binary Ninja support functions that overlap!
+func = bv.get_function_containing(here) # Functions that contain the given address
+# Just a note that using address to work with functions is fine
+# But when working with ILs, addresses are approximate and can change for any given instruction
```
-But what if you don't have that function yet?
+#### All forms of a function:
+
+```python
+for func in bv.functions:
+ low_level_il = func.llil
+ low_level_il_ssa = func.llil.ssa_form
-### Getting a function by name
+ medium_level_il = func.mlil
+ medium_level_il_ssa = func.mlil.ssa_form
+
+ # Decompilation:
+ high_level_il = func.hlil
+ high_level_il_ssa = func.hlil.ssa_form
+
+ base_function = <any>_level_il.source_function # Some helpers are only on the base function object!
+```
+
+#### All decompiled instructions in a binary
```python
-bv.get_functions_by_name('_start')
+for func in bv.functions:
+ for inst in func.hlil.instructions:
+ print(f"{inst.address} : {inst}")
```
-### Finding the function with the most bytes
+or
```python
-max(bv.functions, key=lambda x: x.total_bytes)
+for func in bv.functions:
+ for bb in func.hlil:
+ for inst in bb:
+ print(f"{inst.address} : {inst}")
+```
+
+or
+
+```python
+for inst in bv.hlil_instructions:
+ print(f"{inst.address} : {inst}")
+```
+
+#### Getting the decompiled instruction at an address
+
+```python
+func = bv.get_functions_containing(here)[0] # You should probably be more robust than this
+llil_inst = func.get_llil_at(here) # LLIL have the "closest" mapping to actual addresses, but you should still consider this volatile/fuzzy
+hlil_inst = llil_inst.hlil # This is also very approximate
+
+# What's "more correct" walking down instead:
+hlil_inst.mlil # Approximate "direct" mapping down
+hlil_inst.mlils # All mlil instructions that contributed to this hlil instruction - most correct!
+hlil_inst.llil # Approximate "direct" mapping down
+hlil_inst.llils # All llil instructions that contributed to this hlil instruction - most correct!
+# Be careful when working with address and mappings! We try to make them work as well as possible
+# (and in most cases using the direct mapping is _fine_)
+# But you should always be aware that they are approximate and can change!
+```
+
+
+#### All callers of a function
+
+```python
+current_function.callers
+```
+
+#### All locations where a function is called
+
+```python
+for site in current_function.caller_sites:
+ addr = site.address
+ inst = site.hlil
+```
+
+#### All calls and call instructions in a function:
+
+```python
+for site in current_function.call_sites:
+ addr = site.address
+ inst = site.hlil
```
### Finding the most "connected" function
@@ -42,6 +121,12 @@ As defined by having the highest sum of incoming and outgoing calls. Adjust acco
max(bv.functions, key=lambda x: len(x.callers + x.callees))
```
+### Finding the largest function (by most bytes)
+
+```python
+max(bv.functions, key=lambda x: x.total_bytes)
+```
+
### Querying possible values of a function parameter
Is that memcpy length a bit too big?
@@ -67,6 +152,64 @@ Make sure to check out the much more in-depth [applying annotations](annotation.
current_function.type = Type.function(Type.void(), [])
```
+### Accessing cross references
+
+This recipe is useful for iterating over all of the HLIL cross-references of a given interesting function:
+
+```python
+for ref in current_function.caller_sites:
+ print(ref.hlil)
+```
+
+#### Common variable APIs
+
+```python
+for func in bv.functions:
+ all_vars = func.vars # This isn't the most meaningful thing to do, because....
+ hlil_vars = func.hlil.vars # ...you probably only want the variables used in the IL you're looking at
+ hlil_aliased_vars = func.hlil.aliased_vars # ...but don't forget about aliased variables!
+ parameter_vars = func.parameter_vars # ...or parameter variables!
+
+ var = hlil_vars[0]
+ if var.source_type == StackVariableSourceType:
+ print(var.storage) # var.storage is the variables stack offset, but ONLY IF the source type is `StackVariableSourceType`
+
+ # There are many ways to *estimate* the size of a variable on the stack
+ print(var.offset_to_next_variable) # Distance to the next variable that Binary Ninja has identified on the stack
+ print(abs(var.storage)) # Absolute maximum size the variable can be until it overwrites the saved return pointer!
+ print(abs(var.type.width)) # If Binary Ninja gave the variable a type, or you manually applied a type, then you can get the size from that type
+
+ # SSA
+ hlil_ssa_vars = func.hlil.ssa_vars # You can also get ssa variables
+ def_inst = func.hlil.ssa_form.get_ssa_variable_definition(ssa_vars[0]) # But if you want definitions, you need to use the ssa form
+ 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
+
+```python
+# Data tags
+bv.add_tag(here, "Crashes", "Description")
+
+# Function tags
+current_function.add_tag("Important", "Look at this later!")
+
+# Function address tags
+current_function.add_tag("Bug", "I think there's an overflow here?", here)
+```
+
+#### Logging
+
+```python
+log.log_debug("Debug logs are hidden by default")
+log.log_info("Info logs are displayed in the console")
+log.log_warn("Warning logs will print in yellow text")
+log.log_error("Errors are red!")
+log.log_alert("This pops up a dialogue box!")
+
+log.log_error("You can add your own filter group easily to any of these APIs", "My Log Group")
+```
+
### Find a variable's definition and all uses using SSA
```python