summaryrefslogtreecommitdiff
path: root/docs/dev
diff options
context:
space:
mode:
Diffstat (limited to 'docs/dev')
-rw-r--r--docs/dev/concepts.md43
1 files changed, 40 insertions, 3 deletions
diff --git a/docs/dev/concepts.md b/docs/dev/concepts.md
index 25dd5af0..454f0fbf 100644
--- a/docs/dev/concepts.md
+++ b/docs/dev/concepts.md
@@ -1,5 +1,26 @@
# Important Concepts
+## Binary Views
+
+The highest level analysis object in Binary Ninja is a [BinaryView](https://api.binary.ninja/binaryninja.binaryview-module.html#binaryninja.binaryview.BinaryView) (or `bv` for short). You can think of a `bv` as the Binary Ninja equivalent of what an operating system does when loading an executable binary. These `bv`'s are the top-level analysis object representing how a file is loaded into memory as well as debug information, tables of function pointers, and many other structures.
+
+When you are interacting in the UI with an executable file, you can access `bv` in the python scripting console to see the representation of the current file's BinaryView:
+
+```python
+>>> bv
+<BinaryView: '/bin/ls', start 0x100000000, len 0x182f8>
+>>> len(bv.functions)
+140
+```
+
+???+ Info "Tip"
+ Note the use of `bv` here as a shortcut to the currently open BinaryView. For other "magic" variables, see the [user guide](../guide/index.md#magic-console-variables)
+
+If you want to start writing a plugin, most top-level methods will exist off of the BinaryView. Conceptually, you can think about the organization as a hierarchy starting with a BinaryView, then functions, then basic blocks, then instructions. There are of course lots of other ways to access parts of the binary but this is the most common organization. Check out the tab completion in the scripting console for `bv.get<TAB>` for example (a common prefix for many APIs):
+
+![Tab Completion ><](../img/getcompletion.png "Tab Completion")
+
+Some BinaryViews have parent views. The view used for decompilation includes memory mappings through segments and sections for example, but the "parent_view" property is a view of the original file on-disk.
## REPL versus Scripts
@@ -46,7 +67,13 @@ t = [
bv.get_symbol_by_raw_name('__builtin_strncpy').address
]
-list(current_hlil.traverse(find_strcpy, t))
+# Find the first call to a builtin:
+for result in current_hlil.traverse(find_strcpy, t):
+ # Any logic should live here, not inside the callable which is just for
+ # matching. Because this is a generator, it can fail fast when used for
+ # search!
+ print(result)
+ break
def get_memcpy_data(i, t) -> bytes:
@@ -56,7 +83,8 @@ def get_memcpy_data(i, t) -> bytes:
# 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))
+for i in current_hlil.traverse(get_memcpy_data, t):
+ print(f"Found some memcpy data: {repr(i)}")
# find all the calls to __builtin_strcpy and get their values
@@ -69,13 +97,20 @@ 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))
+
+for i in current_hlil.traverse(find_strcpy, t):
+ print(i)
# collect the number of parameters for each function call
def param_counter(i) -> int:
match i:
case HighLevelILCall():
return len(i.params)
+
+# Note that the results are a generator and usually anything that is found
+# should have processing done outside the callback, but you can always
+# convert it to a list like this:
+
list(current_hlil.traverse(param_counter))
@@ -84,6 +119,7 @@ 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(collect_call_target)])
@@ -92,6 +128,7 @@ 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))
```