Skip to content

Commit 4b71d2d

Browse files
committed
better exception handling and misc fixes
1 parent a4876a6 commit 4b71d2d

File tree

7 files changed

+41
-43
lines changed

7 files changed

+41
-43
lines changed

models/libc.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ..utility.expr_wrap_util import symbolic
33
from ..expr import BVV, BVS, BoolV, ITE, Or, And
44
from ..utility.models_util import get_arg_k
5-
from ..utility.exceptions import ExitException
5+
from ..utility.exceptions import ExitException, ModelError
66
from ..utility.string_util import as_bytes, str_to_bv_list
77
from ..memory.sym_memory import InitData
88
import re
@@ -34,9 +34,8 @@ def strtoul_handler(state: State, view):
3434
endptr = get_arg_k(state, 2, state.arch.bits() // 8, view)
3535
base = get_arg_k(state, 3, 4, view)
3636

37-
assert not symbolic(base) # concrete model
38-
assert not symbolic(endptr) # concrete model
39-
assert not symbolic(str_p) # concrete model
37+
if symbolic(base) or symbolic(endptr) or symbolic(str_p):
38+
raise ModelError("strtoul", "symbolic arguments are not supported")
4039

4140
i = 0
4241
str_data = b""
@@ -334,8 +333,12 @@ def _atox(state: State, view, size: int):
334333

335334
input_p = get_arg_k(state, 1, state.arch.bits() // 8, view)
336335

337-
# no man. Don't make me cry
338-
assert not symbolic(input_p) or not state.solver.symbolic(input_p)
336+
if symbolic(input_p) and state.solver.symbolic(input_p):
337+
# FIXME: I should:
338+
# 1. return a fresh new symbol
339+
# 2. allocate a new buffer with a concrete address
340+
# 3. store the correct expression in the buffer for consistency
341+
raise ModelError("atox", "symbolic input pointer (not supported)")
339342

340343
def build_or_expression(b):
341344
conditions = []

plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"longdescription": "# SENinja - Symbolic Execution Plugin for Binary Ninja\n![](https://github.com/borzacchiello/seninja/raw/master/pictures/screenshot.png)\nThis is a binary ninja plugin that implements a symbolic execution engine based only on z3, highly inspired by the _angr framework_ (https://angr.io/). \nThe plugin is implemented as an emulator of LLIL instructions that builds and manipulates z3 formulas. \n\nSENinja simulates a debugger: the execution is _path driven_, only one state is _active_ and executes instructions. The other states, generated at branches, are saved in a _deferred queue_. At any time, the active state can be changed with a deferred one.\n\n### Commands\nThe plugin adds the following commands:\n![](pictures/commands.png)\n\n---\n\nMore APIs can be executed through the python shell. For example, we can use the solver to _prove_ a condition for the current state:\n\n``` python\n>>> import borzacchiello_seninja as seninja\n>>> s = seninja.get_current_state()\n>>> s.solver.satisfiable(extra_constraints=[s.regs.eax == 3])\n```\n\nthe code will check the satisfiablity of `eax == 3` given the path constraint of the active state.\n\nConsult the [wiki](https://github.com/borzacchiello/seninja/wiki) to have more info about the commands.\n\n### Settings\n\nSENinja gives to the user the possibility to configure many parts of the symbolic engine (e.g. dimension of pages, symbolic memory access strategy, etc.). \nAll the available settings can be accessed and modified by clicking on `Edit/Preferences/Settings` and selecting `SENinja` in the left widget.\n\n### UI Widgets\n\nSENinja comes with two widgets that can be used to visualize the registers and a portion of memory of the active state. The widgets can be activated by clicking on `View/Show SENinja *`. \n\n#### Buffers View\n![](https://github.com/borzacchiello/seninja/raw/master/pictures/buffers_view.png)\nThis widget allows the creation of buffers containing symbolic data.\n\n#### Register View\n![](https://github.com/borzacchiello/seninja/raw/master/pictures/register_view.png)\n\nThe Register View can be used to visualize the value of the registers of the active state. The value of a register can be modifyied by double-clicking on it. The right-click menu allows to:\n- Copy the content of the register\n- Concretize the value of the register\n- Evaluate the value of the register using the solver\n- Inject symbols\n- Show the register expression\n- Set the register to the address of a buffer created with the buffer view\n\n#### Memory View\n![](https://github.com/borzacchiello/seninja/raw/master/pictures/memory_view.png)\n\nThe Memory View can be used to visualize the value of a portion of memory of the active state. By clicking on \"monitor memory\", the user can specify a memory address to monitor. The widget will show 512 bytes starting from that address. \nThe memory view is splitted in two sections: an hexview and an ascii view. The hexview shows the hex value of each byte only if the byte is mapped and concrete. If the byte is unmapped, the characted `_` is shown; if the byte is symbolic, the widget shows the character `.`. \n\nDouble-clicking on a byte allows the user to modify its value in the active state.\nThe right-click menu allows to:\n- Copy the selection (in various format, e.g. little-endian, binary, etc.)\n- Concretize the value of the selection\n- Evaluate the value of the selection using the solver\n- Inject symbols\n\n#### Version and Dependencies\nTested with \n- binary ninja `2.1` with personal license\n- python `3.6.9` \n- z3 `4.8.7`\n\nTo make it work, you need to install z3 with pip:\n`$ pip3 install z3-solver`\n",
1313
"license": {
1414
"name": "2-Clause BSD",
15-
"text": "Copyright 2019 Luca Borzacchiello\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
15+
"text": "Copyright 2019-2022 Luca Borzacchiello\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
1616
},
1717
"platforms": [
1818
"Darwin",

sym_executor.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import sys
2+
13
from binaryninja import (
24
BinaryReader, BinaryWriter,
35
RegisterValueType, enums
@@ -360,7 +362,8 @@ def _execute_one(self):
360362
self.put_in_exited(self.state)
361363
self.state = None
362364
except exceptions.SENinjaError as err:
363-
print("An error occurred: %s" % err.message)
365+
sys.stderr.write("An error occurred: %s\n" % err.message)
366+
self.put_in_errored(self.state, str(err))
364367
self.state = None
365368
self._last_error = err
366369
if err.is_fatal():
@@ -389,13 +392,30 @@ def execute_one(self):
389392
if not self.state:
390393
return
391394

392-
single_llil_step = self.bncache.get_setting(
393-
"single_llil_step") == 'true'
394-
if single_llil_step:
395-
res = self._execute_one()
396-
else:
397-
old_ip = self.ip
398-
res = old_ip
399-
while res == old_ip:
395+
res = None
396+
try:
397+
single_llil_step = self.bncache.get_setting(
398+
"single_llil_step") == 'true'
399+
if single_llil_step:
400400
res = self._execute_one()
401+
else:
402+
old_ip = self.ip
403+
res = old_ip
404+
while res == old_ip:
405+
res = self._execute_one()
406+
except exceptions.SENinjaError:
407+
res = None
408+
except Exception as e:
409+
import os
410+
_, _, exc_tb = sys.exc_info()
411+
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
412+
sys.stderr.write("Unknown exception in SymbolicExecutor.execute_one():\n")
413+
sys.stderr.write(" ".join(map(str, "\t", repr(e), fname, exc_tb.tb_lineno, "\n")))
414+
415+
res = None
416+
417+
if res is None:
418+
if not self.fringe.is_empty():
419+
self.select_from_deferred()
420+
401421
return res

ui/buffer_view.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@
55
get_choice_input
66
)
77
from binaryninjaui import (
8-
DockHandler,
98
DockContextHandler,
109
getMonospaceFont,
1110
UIActionHandler
1211
)
1312
from PySide6 import QtCore
1413
from PySide6.QtCore import Qt, QMimeData
15-
from PySide6.QtGui import QBrush, QColor
1614
from PySide6.QtWidgets import (
1715
QApplication,
1816
QVBoxLayout,
1917
QWidget,
20-
QComboBox,
2118
QTableWidget,
2219
QTableWidgetItem,
2320
QMenu,

ui/hexview.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,13 @@
1212
QItemSelection
1313
)
1414
from PySide6.QtWidgets import (
15-
QApplication,
1615
QTableView,
1716
QWidget,
18-
QTableWidgetItem,
19-
QMainWindow,
20-
QFormLayout,
2117
QVBoxLayout,
2218
QLabel,
2319
QSizePolicy,
2420
QAbstractItemView,
2521
QMenu,
26-
QHeaderView,
2722
QItemDelegate,
2823
QSizePolicy
2924
)
@@ -503,7 +498,7 @@ def _handle_mouse_release(self, key_event):
503498

504499

505500
class HexViewWidget(QWidget):
506-
full_data_changed = Signal(list, list, int)
501+
full_data_changed = Signal(object, dict, int)
507502
single_data_changed = Signal(object, list)
508503
data_edited = Signal(object, int)
509504

@@ -584,9 +579,6 @@ def _handle_data_edited(self, address, data):
584579
# print("edited address data", address, data)
585580

586581
def _handle_data_changed(self, new_address, new_data, new_data_size):
587-
if new_address == []:
588-
return
589-
590582
self._model.buf = new_data
591583
self._model.buf_size = new_data_size
592584
self._model.start_address = new_address

ui/memory_view.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,18 @@
22
from binaryninja.interaction import (
33
show_message_box,
44
get_int_input,
5-
get_choice_input
65
)
76
from binaryninjaui import (
8-
DockHandler,
97
DockContextHandler,
10-
getMonospaceFont,
118
UIActionHandler
129
)
13-
from PySide6 import QtCore
14-
from PySide6.QtCore import Qt, QMimeData
15-
from PySide6.QtGui import QBrush, QColor, QStandardItemModel, QStandardItem
10+
from PySide6.QtCore import QMimeData
1611
from PySide6.QtWidgets import (
1712
QApplication,
1813
QGridLayout,
1914
QWidget,
20-
QComboBox,
21-
QTableWidget,
22-
QTableWidgetItem,
23-
QStackedWidget,
2415
QMenu,
25-
QTableView,
2616
QPushButton,
27-
QHeaderView
2817
)
2918

3019
from ..utility.expr_wrap_util import symbolic, split_bv_in_list

ui/registers_view.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,16 @@
44
get_choice_input
55
)
66
from binaryninjaui import (
7-
DockHandler,
87
DockContextHandler,
98
getMonospaceFont,
109
UIActionHandler
1110
)
12-
from PySide6 import QtCore
1311
from PySide6.QtCore import Qt, QMimeData
1412
from PySide6.QtGui import QBrush, QColor
1513
from PySide6.QtWidgets import (
1614
QApplication,
1715
QVBoxLayout,
1816
QWidget,
19-
QComboBox,
2017
QTableWidget,
2118
QTableWidgetItem,
2219
QMenu

0 commit comments

Comments
 (0)