From 75242aecc30c565ee56d3e74ec2e2dd502a6f073 Mon Sep 17 00:00:00 2001 From: Josh Watson Date: Sun, 29 Oct 2017 12:51:23 -0400 Subject: Fixed possible IndexError in Function.get_*_at methods (#775) `Function.get_low_level_il_at` and `Function.get_lifted_il_at` methods could raise an IndexError because proper checking was not performed on the index returned by the core method that retrieves the IL instruction index of the requested instruction. The methods now check this value to see if it is equal to the length of the IL function, and if so, returns `None` instead. The onus of checking for `None` will be on the user, but at least they shouldn't have to wrap this in a try/except block anymore. --- python/function.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/function.py b/python/function.py index 5daa7b2a..9aafdf52 100644 --- a/python/function.py +++ b/python/function.py @@ -727,7 +727,13 @@ class Function(object): """ if arch is None: arch = self.arch - return self.low_level_il[core.BNGetLowLevelILForInstruction(self.handle, arch.handle, addr)] + + idx = core.BNGetLowLevelILForInstruction(self.handle, arch.handle, addr) + + if idx == len(self.low_level_il): + return None + + return self.low_level_il[idx] def get_low_level_il_exits_at(self, addr, arch=None): if arch is None: @@ -878,7 +884,13 @@ class Function(object): def get_lifted_il_at(self, addr, arch=None): if arch is None: arch = self.arch - return self.lifted_il[core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr)] + + idx = core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr) + + if idx == len(self.lifted_il): + return None + + return self.lifted_il[idx] def get_lifted_il_flag_uses_for_definition(self, i, flag): flag = self.arch.get_flag_index(flag) -- cgit v1.3.1 From 0ca722550555a1a0fc82766686bade6d669af3dc Mon Sep 17 00:00:00 2001 From: Cory Duplantis Date: Sun, 29 Oct 2017 13:23:33 -0500 Subject: Add convenience API's for accessing blocks and instructions in Function (#792) * Update export-svg.py path splitting Changed the path splitting part to the way python's documentation recommends it. I got some errors trying to use that function on windows, because it didn't split correctly. I stumbled upon this in the python documentation: https://docs.python.org/2/library/os.html#os.sep I changed the relevant line using their recommendation. * Rename data to session_data, as this API is per-session and not stored in the db * get_basic_blocks_starting_at incorrectly in the docs * Update troubleshooting.md * Zoom * get_instruction_low_level_il tweak made api docs less ambiguous * documenting Type.int and Type.function * Update __init__.py * Add convenience API's for accessing blocks and instructions in Function --- python/function.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'python') diff --git a/python/function.py b/python/function.py index 9aafdf52..cbbdf9bd 100644 --- a/python/function.py +++ b/python/function.py @@ -666,6 +666,41 @@ class Function(object): """Sets a comment for the current function""" return core.BNSetFunctionComment(self.handle, comment) + @property + def llil_basic_blocks(self): + """A generator of all LowLevelILBasicBlock objects in the current function""" + for block in self.low_level_il: + yield block + + @property + def mlil_basic_blocks(self): + """A generator of all MediumLevelILBasicBlock objects in the current function""" + for block in self.medium_level_il: + yield block + + @property + def instructions(self): + """A generator of instruction tokens and their start addresses for the current function""" + for block in self.basic_blocks: + start = block.start + for i in block: + yield (i[0], start) + start += i[1] + + @property + def llil_instructions(self): + """A generator of llil instructions of the current function""" + for block in self.llil_basic_blocks: + for i in block: + yield i + + @property + def mlil_instructions(self): + """A generator of mlil instructions of the current function""" + for block in self.mlil_basic_blocks: + for i in block: + yield i + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) -- cgit v1.3.1 From c396d2cfb3682cb4c152b9dba6f866f6783e4a80 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Mon, 30 Oct 2017 17:46:49 -0400 Subject: __hash__ for three types of basic blocks --- python/basicblock.py | 3 +++ python/lowlevelil.py | 3 +++ python/mediumlevelil.py | 3 +++ 3 files changed, 9 insertions(+) (limited to 'python') diff --git a/python/basicblock.py b/python/basicblock.py index 26db925d..66d96882 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -68,6 +68,9 @@ class BasicBlock(object): """Internal method used to instantiante child instances""" return BasicBlock(view, handle) + def __hash__(self): + return hash((self.start, self.end, self.arch.name)) + @property def function(self): """Basic block function (read-only)""" diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 75a3f1ad..dfc5af5f 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -1733,6 +1733,9 @@ class LowLevelILBasicBlock(basicblock.BasicBlock): """Internal method by super to instantiante child instances""" return LowLevelILBasicBlock(view, handle, self.il_function) + def __hash__(self): + return hash((self.start, self.end, self.il_function)) + def LLIL_TEMP(n): return n | 0x80000000 diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 07759a47..9167212a 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -893,3 +893,6 @@ class MediumLevelILBasicBlock(basicblock.BasicBlock): def _create_instance(self, view, handle): """Internal method by super to instantiante child instances""" return MediumLevelILBasicBlock(view, handle, self.il_function) + + def __hash__(self): + return hash((self.start, self.end, self.il_function)) -- cgit v1.3.1 From a774e47ee36a5d4418c9aec13e5612f158a825d3 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Mon, 30 Oct 2017 21:21:48 -0400 Subject: add current_llil and current_mlil scripting console aliases --- docs/getting-started.md | 2 ++ python/scriptingprovider.py | 2 ++ 2 files changed, 4 insertions(+) (limited to 'python') diff --git a/docs/getting-started.md b/docs/getting-started.md index 692c1e67..39809747 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -210,6 +210,8 @@ By default the interactive python prompt has a number of convenient helper funct - `bv` / `current_view` / : the current [BinaryView](https://api.binary.ninja/binaryninja.BinaryView.html) - `current_function`: the current [Function](https://api.binary.ninja/binaryninja.Function.html) - `current_basic_block`: the current [BasicBlock](https://api.binary.ninja/binaryninja.BasicBlock.html) +- `current_llil`: the current [LowLevelILBasicBlock](https://api.binary.ninja/binaryninja.lowlevelil.LowLevelILBasicBlock.html) +- `current_mlil`: the current [MediumLevelILBasicBlock](https://api.binary.ninja/binaryninja.mediumlevelil.MediumLevelILBasicBlock.html) - `current_selection`: a tuple of the start and end addresses of the current selection - `write_at_cursor(data)`: function that writes data to the start of the current selection - `get_selected_data()`: function that returns the data in the current selection diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index ed9688b9..211d2fb7 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -540,6 +540,8 @@ class PythonScriptingInstance(ScriptingInstance): self.locals["current_address"] = self.active_addr self.locals["here"] = self.active_addr self.locals["current_selection"] = (self.active_selection_begin, self.active_selection_end) + self.locals["current_llil"] = self.active_func.low_level_il + self.locals["current_mlil"] = self.active_func.medium_level_il self.interpreter.runsource(code) -- cgit v1.3.1 From de70f093cc429a125dde201cfe245b616c10ebce Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 30 Oct 2017 22:03:01 -0400 Subject: Provide a slightly different implementation for @joshwatson's AnalysisCompletionEvent PR and documentation update --- python/binaryview.py | 13 ++++++++++++- python/interaction.py | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/binaryview.py b/python/binaryview.py index 9304d412..e6cb5b04 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -103,6 +103,17 @@ class StringReference(object): class AnalysisCompletionEvent(object): + """ + The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving + callbacks when analysis is complete. + + :Example: + >>> def on_complete(self): + ... print "Analysis Complete", self.view + ... + >>> evt = AnalysisCompletionEvent(bv, on_complete) + >>> + """ def __init__(self, view, callback): self.view = view self.callback = callback @@ -114,7 +125,7 @@ class AnalysisCompletionEvent(object): def _notify(self, ctxt): try: - self.callback() + self.callback(self) except: log.log_error(traceback.format_exc()) diff --git a/python/interaction.py b/python/interaction.py index 979549f5..96cac42d 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -520,7 +520,7 @@ def show_html_report(title, contents, plaintext=""): :param str contents: HTML contents to display :param str plaintext: Plain text version to display (used on the command line) :rtype: None - :Example" + :Example: >>> show_html_report("title", "

Contents

", "Plain text contents") Plain text contents """ -- cgit v1.3.1 From 9a70f039ffd68190a3a6efc53a4fab3cf20b7963 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Wed, 1 Nov 2017 00:42:32 -0400 Subject: fix new scripting provider aliases when no current context exists --- python/scriptingprovider.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 211d2fb7..f9758cc9 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -540,8 +540,12 @@ class PythonScriptingInstance(ScriptingInstance): self.locals["current_address"] = self.active_addr self.locals["here"] = self.active_addr self.locals["current_selection"] = (self.active_selection_begin, self.active_selection_end) - self.locals["current_llil"] = self.active_func.low_level_il - self.locals["current_mlil"] = self.active_func.medium_level_il + if self.active_func == None: + self.locals["current_llil"] = None + self.locals["current_mlil"] = None + else: + self.locals["current_llil"] = self.active_func.low_level_il + self.locals["current_mlil"] = self.active_func.medium_level_il self.interpreter.runsource(code) -- cgit v1.3.1 From 54a23d9e1ae34936427461b2807e3d5980e17486 Mon Sep 17 00:00:00 2001 From: David Barksdale Date: Thu, 2 Nov 2017 11:30:12 -0500 Subject: Make SSAVariables unique between functions (#855) This helps a ton with inter-function analysis. --- python/mediumlevelil.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'python') diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 9167212a..333a6c4d 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -39,12 +39,12 @@ class SSAVariable(object): def __eq__(self, other): return ( - (self.var.identifier, self.version) == - (other.var.identifier, other.version) + (self.var.identifier, self.var.function, self.version) == + (other.var.identifier, other.var.function, other.version) ) def __hash__(self): - return hash((self.var.identifier, self.version)) + return hash((self.var.identifier, self.var.function, self.version)) class MediumLevelILLabel(object): -- cgit v1.3.1 From 704ceff1223485e9dc12947a36b0d56a3ff9d3ae Mon Sep 17 00:00:00 2001 From: David Barksdale Date: Thu, 2 Nov 2017 11:38:11 -0500 Subject: Move the function discrimination from SSAVariable to Variable (#856) --- python/function.py | 4 ++-- python/mediumlevelil.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'python') diff --git a/python/function.py b/python/function.py index cbbdf9bd..f8aaae44 100644 --- a/python/function.py +++ b/python/function.py @@ -241,10 +241,10 @@ class Variable(object): return self.name def __eq__(self, other): - return self.identifier == other.identifier + return (self.identifier, self.function) == (other.identifier, other.function) def __hash__(self): - return hash(self.identifier) + return hash((self.identifier, self.function)) class ConstantReference(object): diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 333a6c4d..6f5515bb 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -39,12 +39,12 @@ class SSAVariable(object): def __eq__(self, other): return ( - (self.var.identifier, self.var.function, self.version) == - (other.var.identifier, other.var.function, other.version) + (self.var, self.version) == + (other.var, other.version) ) def __hash__(self): - return hash((self.var.identifier, self.var.function, self.version)) + return hash((self.var, self.version)) class MediumLevelILLabel(object): -- cgit v1.3.1