angr 9.2.139__py3-none-manylinux2014_x86_64.whl → 9.2.140__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/calling_convention/calling_convention.py +48 -21
- angr/analyses/cfg/cfg_base.py +13 -0
- angr/analyses/cfg/cfg_fast.py +11 -0
- angr/analyses/decompiler/ail_simplifier.py +67 -52
- angr/analyses/decompiler/clinic.py +68 -43
- angr/analyses/decompiler/decompiler.py +17 -7
- angr/analyses/decompiler/expression_narrower.py +1 -1
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +16 -10
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +2 -2
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +259 -108
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +27 -12
- angr/analyses/decompiler/structuring/dream.py +21 -17
- angr/analyses/decompiler/structuring/phoenix.py +152 -40
- angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
- angr/analyses/decompiler/structuring/structurer_base.py +36 -10
- angr/analyses/decompiler/structuring/structurer_nodes.py +4 -1
- angr/analyses/decompiler/utils.py +60 -1
- angr/analyses/deobfuscator/api_obf_finder.py +8 -5
- angr/analyses/deobfuscator/api_obf_type2_finder.py +18 -10
- angr/analyses/deobfuscator/string_obf_finder.py +105 -18
- angr/analyses/forward_analysis/forward_analysis.py +1 -1
- angr/analyses/propagator/top_checker_mixin.py +6 -6
- angr/analyses/reaching_definitions/__init__.py +2 -1
- angr/analyses/reaching_definitions/dep_graph.py +1 -12
- angr/analyses/reaching_definitions/engine_vex.py +36 -31
- angr/analyses/reaching_definitions/function_handler.py +15 -2
- angr/analyses/reaching_definitions/rd_state.py +1 -37
- angr/analyses/reaching_definitions/reaching_definitions.py +13 -24
- angr/analyses/s_propagator.py +6 -41
- angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
- angr/analyses/stack_pointer_tracker.py +36 -22
- angr/analyses/typehoon/simple_solver.py +45 -7
- angr/analyses/typehoon/typeconsts.py +18 -5
- angr/analyses/variable_recovery/engine_base.py +7 -5
- angr/block.py +69 -107
- angr/callable.py +14 -7
- angr/calling_conventions.py +15 -1
- angr/distributed/__init__.py +1 -1
- angr/engines/__init__.py +7 -8
- angr/engines/engine.py +1 -120
- angr/engines/failure.py +2 -2
- angr/engines/hook.py +2 -2
- angr/engines/light/engine.py +2 -2
- angr/engines/pcode/engine.py +2 -14
- angr/engines/procedure.py +2 -2
- angr/engines/soot/engine.py +2 -2
- angr/engines/soot/statements/switch.py +1 -1
- angr/engines/successors.py +124 -11
- angr/engines/syscall.py +2 -2
- angr/engines/unicorn.py +3 -3
- angr/engines/vex/heavy/heavy.py +3 -15
- angr/factory.py +4 -19
- angr/knowledge_plugins/key_definitions/atoms.py +8 -4
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
- angr/sim_type.py +19 -17
- angr/state_plugins/plugin.py +19 -4
- angr/storage/memory_mixins/memory_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +10 -5
- angr/utils/ssa/__init__.py +119 -4
- {angr-9.2.139.dist-info → angr-9.2.140.dist-info}/METADATA +6 -6
- {angr-9.2.139.dist-info → angr-9.2.140.dist-info}/RECORD +68 -68
- {angr-9.2.139.dist-info → angr-9.2.140.dist-info}/LICENSE +0 -0
- {angr-9.2.139.dist-info → angr-9.2.140.dist-info}/WHEEL +0 -0
- {angr-9.2.139.dist-info → angr-9.2.140.dist-info}/entry_points.txt +0 -0
- {angr-9.2.139.dist-info → angr-9.2.140.dist-info}/top_level.txt +0 -0
angr/callable.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import pycparser
|
|
3
3
|
|
|
4
|
+
from .sim_manager import SimulationManager
|
|
4
5
|
from .errors import AngrCallableError, AngrCallableMultistateError
|
|
5
6
|
from .calling_conventions import default_cc, SimCC
|
|
6
7
|
|
|
@@ -28,6 +29,7 @@ class Callable:
|
|
|
28
29
|
cc=None,
|
|
29
30
|
add_options=None,
|
|
30
31
|
remove_options=None,
|
|
32
|
+
step_limit: int | None = None,
|
|
31
33
|
):
|
|
32
34
|
"""
|
|
33
35
|
:param project: The project to operate on
|
|
@@ -60,6 +62,7 @@ class Callable:
|
|
|
60
62
|
self._func_ty = prototype
|
|
61
63
|
self._add_options = add_options if add_options else set()
|
|
62
64
|
self._remove_options = remove_options if remove_options else set()
|
|
65
|
+
self._step_limit = step_limit
|
|
63
66
|
|
|
64
67
|
self.result_path_group = None
|
|
65
68
|
self.result_state = None
|
|
@@ -95,16 +98,12 @@ class Callable:
|
|
|
95
98
|
remove_options=self._remove_options,
|
|
96
99
|
)
|
|
97
100
|
|
|
98
|
-
def step_func(pg):
|
|
99
|
-
pg2 = pg.prune()
|
|
100
|
-
if len(pg2.active) > 1:
|
|
101
|
-
raise AngrCallableMultistateError("Execution split on symbolic condition!")
|
|
102
|
-
return pg2
|
|
103
|
-
|
|
104
101
|
caller = self._project.factory.simulation_manager(state)
|
|
105
|
-
caller.run(step_func=
|
|
102
|
+
caller.run(step_func=self._step_func).unstash(from_stash="deadended")
|
|
106
103
|
caller.prune(filter_func=lambda pt: pt.addr == self._deadend_addr)
|
|
107
104
|
|
|
105
|
+
if "step_limited" in caller.stashes:
|
|
106
|
+
caller.stash(from_stash="step_limited", to_stash="active")
|
|
108
107
|
if len(caller.active) == 0:
|
|
109
108
|
raise AngrCallableError("No paths returned from function")
|
|
110
109
|
|
|
@@ -159,3 +158,11 @@ class Callable:
|
|
|
159
158
|
raise AngrCallableError(f"Unsupported expression type {type(expr)}.")
|
|
160
159
|
|
|
161
160
|
return self.__call__(*args)
|
|
161
|
+
|
|
162
|
+
def _step_func(self, pg: SimulationManager):
|
|
163
|
+
pg2 = pg.prune()
|
|
164
|
+
if self._concrete_only and len(pg2.active) > 1:
|
|
165
|
+
raise AngrCallableMultistateError("Execution split on symbolic condition!")
|
|
166
|
+
if self._step_limit:
|
|
167
|
+
pg2.stash(filter_func=lambda p: p.history.depth >= self._step_limit, to_stash="step_limited")
|
|
168
|
+
return pg2
|
angr/calling_conventions.py
CHANGED
|
@@ -687,7 +687,7 @@ class SimCC:
|
|
|
687
687
|
ty = ty.with_arch(self.arch)
|
|
688
688
|
if isinstance(ty, (SimStruct, SimUnion, SimTypeFixedSizeArray)):
|
|
689
689
|
raise AngrTypeError(
|
|
690
|
-
f"{self} doesn't know how to return aggregate types. Consider overriding return_val to "
|
|
690
|
+
f"{self} doesn't know how to return aggregate types ({type(ty)}). Consider overriding return_val to "
|
|
691
691
|
"implement its ABI logic"
|
|
692
692
|
)
|
|
693
693
|
if self.return_in_implicit_outparam(ty):
|
|
@@ -1334,6 +1334,20 @@ class SimCCMicrosoftAMD64(SimCC):
|
|
|
1334
1334
|
def return_val(self, ty, perspective_returned=False):
|
|
1335
1335
|
if ty._arch is None:
|
|
1336
1336
|
ty = ty.with_arch(self.arch)
|
|
1337
|
+
|
|
1338
|
+
# Unions are allocated according to the layout of the largest member
|
|
1339
|
+
if isinstance(ty, SimUnion):
|
|
1340
|
+
chosen = None
|
|
1341
|
+
size = None
|
|
1342
|
+
for subty in ty.members.values():
|
|
1343
|
+
if subty.size is not None and (size is None or size < subty.size):
|
|
1344
|
+
chosen = subty
|
|
1345
|
+
size = subty.size
|
|
1346
|
+
if chosen is None:
|
|
1347
|
+
# fallback to void*
|
|
1348
|
+
chosen = SimTypePointer(SimTypeBottom())
|
|
1349
|
+
return self.return_val(chosen, perspective_returned=perspective_returned)
|
|
1350
|
+
|
|
1337
1351
|
if not isinstance(ty, SimStruct):
|
|
1338
1352
|
return super().return_val(ty, perspective_returned)
|
|
1339
1353
|
|
angr/distributed/__init__.py
CHANGED
angr/engines/__init__.py
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from .
|
|
4
|
-
from .engine import SimEngine, SuccessorsMixin
|
|
5
|
-
|
|
6
|
-
from .vex import HeavyVEXMixin, TrackActionsMixin, SimInspectMixin, HeavyResilienceMixin, SuperFastpathMixin
|
|
7
|
-
from .procedure import ProcedureMixin, ProcedureEngine
|
|
8
|
-
from .unicorn import SimEngineUnicorn
|
|
3
|
+
from .engine import SimEngine
|
|
9
4
|
from .failure import SimEngineFailure
|
|
10
|
-
from .syscall import SimEngineSyscall
|
|
11
5
|
from .hook import HooksMixin
|
|
6
|
+
from .procedure import ProcedureEngine, ProcedureMixin
|
|
12
7
|
from .soot import SootMixin
|
|
8
|
+
from .successors import SimSuccessors, SuccessorsEngine
|
|
9
|
+
from .syscall import SimEngineSyscall
|
|
10
|
+
from .unicorn import SimEngineUnicorn
|
|
11
|
+
from .vex import HeavyResilienceMixin, HeavyVEXMixin, SimInspectMixin, SuperFastpathMixin, TrackActionsMixin
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class UberEngine(
|
|
@@ -47,7 +46,7 @@ __all__ = [
|
|
|
47
46
|
"SimInspectMixin",
|
|
48
47
|
"SimSuccessors",
|
|
49
48
|
"SootMixin",
|
|
50
|
-
"
|
|
49
|
+
"SuccessorsEngine",
|
|
51
50
|
"SuperFastpathMixin",
|
|
52
51
|
"TrackActionsMixin",
|
|
53
52
|
"UberEngine",
|
angr/engines/engine.py
CHANGED
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Generic, TypeVar
|
|
4
3
|
import abc
|
|
5
|
-
import
|
|
4
|
+
from typing import Generic, TypeVar
|
|
6
5
|
|
|
7
|
-
import claripy
|
|
8
|
-
from archinfo.arch_soot import SootAddressDescriptor
|
|
9
6
|
|
|
10
7
|
import angr
|
|
11
|
-
from angr.sim_state import SimState
|
|
12
|
-
from angr import sim_options as o
|
|
13
|
-
from angr.errors import SimException
|
|
14
|
-
from angr.state_plugins.inspect import BP_AFTER, BP_BEFORE
|
|
15
|
-
from .successors import SimSuccessors
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
l = logging.getLogger(name=__name__)
|
|
19
|
-
|
|
20
8
|
|
|
21
9
|
StateType = TypeVar("StateType")
|
|
22
10
|
ResultType = TypeVar("ResultType")
|
|
23
11
|
DataType_co = TypeVar("DataType_co", covariant=True)
|
|
24
|
-
HeavyState = SimState[int | SootAddressDescriptor, claripy.ast.BV | SootAddressDescriptor]
|
|
25
12
|
|
|
26
13
|
|
|
27
14
|
class SimEngine(Generic[StateType, ResultType], metaclass=abc.ABCMeta):
|
|
@@ -40,109 +27,3 @@ class SimEngine(Generic[StateType, ResultType], metaclass=abc.ABCMeta):
|
|
|
40
27
|
|
|
41
28
|
def __setstate__(self, state):
|
|
42
29
|
self.project = state[0]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class SuccessorsMixin(SimEngine[HeavyState, SimSuccessors]):
|
|
46
|
-
"""
|
|
47
|
-
A mixin for SimEngine which implements ``process`` to perform common operations related to symbolic execution
|
|
48
|
-
and dispatches to a ``process_successors`` method to fill a SimSuccessors object with the results.
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
def __init__(self, project: angr.Project):
|
|
52
|
-
super().__init__(project)
|
|
53
|
-
|
|
54
|
-
self.successors: SimSuccessors | None = None
|
|
55
|
-
|
|
56
|
-
def process(self, state: HeavyState, **kwargs) -> SimSuccessors: # pylint:disable=unused-argument
|
|
57
|
-
"""
|
|
58
|
-
Perform execution with a state.
|
|
59
|
-
|
|
60
|
-
You should only override this method in a subclass in order to provide the correct method signature and
|
|
61
|
-
docstring. You should override the ``_process`` method to do your actual execution.
|
|
62
|
-
|
|
63
|
-
:param state: The state with which to execute. This state will be copied before
|
|
64
|
-
modification.
|
|
65
|
-
:param inline: This is an inline execution. Do not bother copying the state.
|
|
66
|
-
:param force_addr: Force execution to pretend that we're working at this concrete address
|
|
67
|
-
:returns: A SimSuccessors object categorizing the execution's successor states
|
|
68
|
-
"""
|
|
69
|
-
inline = kwargs.pop("inline", False)
|
|
70
|
-
force_addr = kwargs.pop("force_addr", None)
|
|
71
|
-
|
|
72
|
-
ip = state._ip
|
|
73
|
-
addr = (
|
|
74
|
-
(ip if isinstance(ip, SootAddressDescriptor) else state.solver.eval(ip))
|
|
75
|
-
if force_addr is None
|
|
76
|
-
else force_addr
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
# make a copy of the initial state for actual processing, if needed
|
|
80
|
-
new_state = state.copy() if not inline and o.COPY_STATES in state.options else state
|
|
81
|
-
# enforce this distinction
|
|
82
|
-
old_state = state
|
|
83
|
-
del state
|
|
84
|
-
self.state = new_state
|
|
85
|
-
|
|
86
|
-
# we have now officially begun the stepping process! now is where we "cycle" a state's
|
|
87
|
-
# data - move the "present" into the "past" by pushing an entry on the history stack.
|
|
88
|
-
# nuance: make sure to copy from the PREVIOUS state to the CURRENT one
|
|
89
|
-
# to avoid creating a dead link in the history, messing up the statehierarchy
|
|
90
|
-
new_state.register_plugin("history", old_state.history.make_child())
|
|
91
|
-
new_state.history.recent_bbl_addrs.append(addr)
|
|
92
|
-
if new_state.arch.unicorn_support:
|
|
93
|
-
assert isinstance(addr, int)
|
|
94
|
-
new_state.scratch.executed_pages_set = {addr & ~0xFFF}
|
|
95
|
-
|
|
96
|
-
self.successors = SimSuccessors(addr, old_state)
|
|
97
|
-
|
|
98
|
-
new_state._inspect(
|
|
99
|
-
"engine_process", when=BP_BEFORE, sim_engine=self, sim_successors=self.successors, address=addr
|
|
100
|
-
)
|
|
101
|
-
self.successors = new_state._inspect_getattr("sim_successors", self.successors)
|
|
102
|
-
try:
|
|
103
|
-
self.process_successors(self.successors, **kwargs)
|
|
104
|
-
except SimException as e:
|
|
105
|
-
if o.EXCEPTION_HANDLING not in old_state.options:
|
|
106
|
-
raise
|
|
107
|
-
assert old_state.project is not None
|
|
108
|
-
old_state.project.simos.handle_exception(self.successors, self, e)
|
|
109
|
-
|
|
110
|
-
new_state._inspect("engine_process", when=BP_AFTER, sim_successors=self.successors, address=addr)
|
|
111
|
-
self.successors = new_state._inspect_getattr("sim_successors", self.successors)
|
|
112
|
-
assert self.successors is not None
|
|
113
|
-
|
|
114
|
-
# downsizing
|
|
115
|
-
if new_state.supports_inspect:
|
|
116
|
-
new_state.inspect.downsize()
|
|
117
|
-
# if not TRACK, clear actions on OLD state
|
|
118
|
-
# if o.TRACK_ACTION_HISTORY not in old_state.options:
|
|
119
|
-
# old_state.history.recent_events = []
|
|
120
|
-
|
|
121
|
-
# fix up the descriptions...
|
|
122
|
-
description = str(self.successors)
|
|
123
|
-
l.info("Ticked state: %s", description)
|
|
124
|
-
for succ in self.successors.all_successors:
|
|
125
|
-
succ.history.recent_description = description
|
|
126
|
-
for succ in self.successors.flat_successors:
|
|
127
|
-
succ.history.recent_description = description
|
|
128
|
-
|
|
129
|
-
return self.successors
|
|
130
|
-
|
|
131
|
-
def process_successors(self, successors, **kwargs): # pylint:disable=unused-argument,no-self-use
|
|
132
|
-
"""
|
|
133
|
-
Implement this function to fill out the SimSuccessors object with the results of stepping state.
|
|
134
|
-
|
|
135
|
-
In order to implement a model where multiple mixins can potentially handle a request, a mixin may implement
|
|
136
|
-
this method and then perform a super() call if it wants to pass on handling to the next mixin.
|
|
137
|
-
|
|
138
|
-
Keep in mind python's method resolution order when composing multiple classes implementing this method.
|
|
139
|
-
In short: left-to-right, depth-first, but deferring any base classes which are shared by multiple subclasses
|
|
140
|
-
(the merge point of a diamond pattern in the inheritance graph) until the last point where they would be
|
|
141
|
-
encountered in this depth-first search. For example, if you have classes A, B(A), C(B), D(A), E(C, D), then the
|
|
142
|
-
method resolution order will be E, C, B, D, A.
|
|
143
|
-
|
|
144
|
-
:param state: The state to manipulate
|
|
145
|
-
:param successors: The successors object to fill out
|
|
146
|
-
:param kwargs: Any extra arguments. Do not fail if you are passed unexpected arguments.
|
|
147
|
-
"""
|
|
148
|
-
successors.processed = False # mark failure
|
angr/engines/failure.py
CHANGED
|
@@ -3,13 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
from angr.errors import AngrExitError
|
|
6
|
-
from .
|
|
6
|
+
from .successors import SuccessorsEngine
|
|
7
7
|
from .procedure import ProcedureMixin
|
|
8
8
|
|
|
9
9
|
l = logging.getLogger(name=__name__)
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class SimEngineFailure(
|
|
12
|
+
class SimEngineFailure(SuccessorsEngine, ProcedureMixin):
|
|
13
13
|
def process_successors(self, successors, **kwargs):
|
|
14
14
|
state = self.state
|
|
15
15
|
jumpkind = state.history.parent.jumpkind if state.history and state.history.parent else None
|
angr/engines/hook.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
|
-
from .
|
|
4
|
+
from .successors import SuccessorsEngine
|
|
5
5
|
from .procedure import ProcedureMixin
|
|
6
6
|
from archinfo.arch_soot import SootAddressDescriptor
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ l = logging.getLogger(name=__name__)
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
# pylint: disable=abstract-method,unused-argument,arguments-differ
|
|
12
|
-
class HooksMixin(
|
|
12
|
+
class HooksMixin(SuccessorsEngine, ProcedureMixin):
|
|
13
13
|
"""
|
|
14
14
|
A SimEngine mixin which adds a SimSuccessors handler which will look into the project's hooks and run the hook at
|
|
15
15
|
the current address.
|
angr/engines/light/engine.py
CHANGED
|
@@ -159,7 +159,7 @@ class SimEngineLightVEX(
|
|
|
159
159
|
|
|
160
160
|
@staticmethod
|
|
161
161
|
def binopv_handler(
|
|
162
|
-
f: Callable[[T, int, int, pyvex.expr.Binop], DataType_co]
|
|
162
|
+
f: Callable[[T, int, int, pyvex.expr.Binop], DataType_co],
|
|
163
163
|
) -> Callable[[T, int, int, pyvex.expr.Binop], DataType_co]:
|
|
164
164
|
f.binopv_handler = True
|
|
165
165
|
return f
|
|
@@ -181,7 +181,7 @@ class SimEngineLightVEX(
|
|
|
181
181
|
|
|
182
182
|
@staticmethod
|
|
183
183
|
def dirty_handler(
|
|
184
|
-
f: Callable[[T, pyvex.stmt.Dirty], StmtDataType]
|
|
184
|
+
f: Callable[[T, pyvex.stmt.Dirty], StmtDataType],
|
|
185
185
|
) -> Callable[[T, pyvex.stmt.Dirty], StmtDataType]:
|
|
186
186
|
f.dirty_handler = True
|
|
187
187
|
return f
|
angr/engines/pcode/engine.py
CHANGED
|
@@ -5,7 +5,7 @@ import claripy
|
|
|
5
5
|
import logging
|
|
6
6
|
|
|
7
7
|
from angr.calling_conventions import DEFAULT_CC, default_cc, SimRegArg
|
|
8
|
-
from angr.engines.
|
|
8
|
+
from angr.engines.successors import SuccessorsEngine, SimSuccessors
|
|
9
9
|
from angr.misc.ux import once
|
|
10
10
|
from angr.utils.constants import DEFAULT_STATEMENT
|
|
11
11
|
from angr import sim_options as o
|
|
@@ -19,7 +19,7 @@ l = logging.getLogger(__name__)
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class HeavyPcodeMixin(
|
|
22
|
-
|
|
22
|
+
SuccessorsEngine,
|
|
23
23
|
PcodeLifterEngineMixin,
|
|
24
24
|
PcodeEmulatorMixin,
|
|
25
25
|
):
|
|
@@ -52,7 +52,6 @@ class HeavyPcodeMixin(
|
|
|
52
52
|
self,
|
|
53
53
|
successors: SimSuccessors,
|
|
54
54
|
irsb: IRSB | None = None,
|
|
55
|
-
insn_text: str | None = None,
|
|
56
55
|
insn_bytes: bytes | None = None,
|
|
57
56
|
thumb: bool = False,
|
|
58
57
|
size: int | None = None,
|
|
@@ -67,21 +66,10 @@ class HeavyPcodeMixin(
|
|
|
67
66
|
extra_stop_points=extra_stop_points,
|
|
68
67
|
num_inst=num_inst,
|
|
69
68
|
size=size,
|
|
70
|
-
insn_text=insn_text,
|
|
71
69
|
insn_bytes=insn_bytes,
|
|
72
70
|
**kwargs,
|
|
73
71
|
)
|
|
74
72
|
|
|
75
|
-
if insn_text is not None:
|
|
76
|
-
if insn_bytes is not None:
|
|
77
|
-
raise errors.SimEngineError("You cannot provide both 'insn_bytes' and 'insn_text'!")
|
|
78
|
-
|
|
79
|
-
insn_bytes = self.project.arch.asm(insn_text, addr=successors.addr, thumb=thumb)
|
|
80
|
-
if insn_bytes is None:
|
|
81
|
-
raise errors.AngrAssemblyError(
|
|
82
|
-
"Assembling failed. Please make sure keystone is installed, and the assembly string is correct."
|
|
83
|
-
)
|
|
84
|
-
|
|
85
73
|
successors.sort = "IRSB"
|
|
86
74
|
successors.description = "IRSB"
|
|
87
75
|
self.state.history.recent_block_count = 1
|
angr/engines/procedure.py
CHANGED
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
from angr import sim_options as o
|
|
5
5
|
from angr import errors
|
|
6
6
|
from angr.state_plugins.inspect import BP_BEFORE, BP_AFTER
|
|
7
|
-
from .
|
|
7
|
+
from .successors import SuccessorsEngine
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
l = logging.getLogger(name=__name__)
|
|
@@ -58,7 +58,7 @@ class ProcedureMixin:
|
|
|
58
58
|
successors.processed = True
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
class ProcedureEngine(ProcedureMixin,
|
|
61
|
+
class ProcedureEngine(ProcedureMixin, SuccessorsEngine):
|
|
62
62
|
"""
|
|
63
63
|
A SimEngine that you may use if you only care about processing SimProcedures. *Requires* the procedure
|
|
64
64
|
kwarg to be passed to process.
|
angr/engines/soot/engine.py
CHANGED
|
@@ -15,7 +15,7 @@ from angr.errors import SimEngineError, SimTranslationError
|
|
|
15
15
|
from cle import CLEError
|
|
16
16
|
from angr.state_plugins.inspect import BP_AFTER, BP_BEFORE
|
|
17
17
|
from angr.sim_type import SimTypeFunction, parse_type
|
|
18
|
-
from angr.engines.
|
|
18
|
+
from angr.engines.successors import SuccessorsEngine
|
|
19
19
|
from angr.engines.procedure import ProcedureMixin
|
|
20
20
|
from .exceptions import BlockTerminationNotice, IncorrectLocationException
|
|
21
21
|
from .statements import SimSootStmt_Return, SimSootStmt_ReturnVoid, translate_stmt
|
|
@@ -26,7 +26,7 @@ l = logging.getLogger("angr.engines.soot.engine")
|
|
|
26
26
|
# pylint: disable=arguments-differ
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class SootMixin(
|
|
29
|
+
class SootMixin(SuccessorsEngine, ProcedureMixin):
|
|
30
30
|
"""
|
|
31
31
|
Execution engine based on Soot.
|
|
32
32
|
"""
|
|
@@ -25,7 +25,7 @@ class SwitchBase(SimSootStmt):
|
|
|
25
25
|
jmp_condition = lookup_value == key_val
|
|
26
26
|
self._add_jmp_target(jmp_target, jmp_condition)
|
|
27
27
|
# add condition for the default target
|
|
28
|
-
default_jmp_conditions += [
|
|
28
|
+
default_jmp_conditions += [lookup_value != key_val]
|
|
29
29
|
|
|
30
30
|
# add default target
|
|
31
31
|
default_jmp_target = self._get_bb_addr_from_instr(self.stmt.default_target)
|
angr/engines/successors.py
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
import claripy
|
|
6
|
-
|
|
7
6
|
from archinfo.arch_soot import ArchSoot, SootAddressDescriptor
|
|
8
7
|
|
|
8
|
+
import angr
|
|
9
9
|
from angr import sim_options as o
|
|
10
10
|
from angr.calling_conventions import SYSCALL_CC
|
|
11
|
-
from angr.
|
|
12
|
-
from angr.
|
|
13
|
-
|
|
11
|
+
from angr.engines.engine import SimEngine
|
|
12
|
+
from angr.errors import (
|
|
13
|
+
AngrSyscallError,
|
|
14
|
+
AngrUnsupportedSyscallError,
|
|
15
|
+
SimException,
|
|
16
|
+
SimSolverModeError,
|
|
17
|
+
SimUnsatError,
|
|
18
|
+
SimValueError,
|
|
19
|
+
)
|
|
20
|
+
from angr.sim_state import SimState
|
|
14
21
|
from angr.state_plugins.callstack import CallStack
|
|
22
|
+
from angr.state_plugins.inspect import BP_AFTER, BP_BEFORE
|
|
15
23
|
from angr.state_plugins.sim_action_object import _raw_ast
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if TYPE_CHECKING:
|
|
19
|
-
from angr import SimState
|
|
20
|
-
from angr.engines.engine import HeavyState
|
|
24
|
+
from angr.storage import DUMMY_SYMBOLIC_READ_VALUE
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
l = logging.getLogger(name=__name__)
|
|
@@ -300,7 +304,7 @@ class SimSuccessors:
|
|
|
300
304
|
else:
|
|
301
305
|
# The architecture doesn't have an ip_at_syscall register.
|
|
302
306
|
# Nothing to do but hope vigorously.
|
|
303
|
-
l.warning(
|
|
307
|
+
l.warning("Handling syscall on arch %s without ip_at_syscall register", state.arch.name)
|
|
304
308
|
|
|
305
309
|
try:
|
|
306
310
|
symbolic_syscall_num, concrete_syscall_nums = self._resolve_syscall(state)
|
|
@@ -539,3 +543,112 @@ class SimSuccessors:
|
|
|
539
543
|
addrs = state.solver.eval_upto(ip, limit)
|
|
540
544
|
|
|
541
545
|
return [(ip == addr, addr) for addr in addrs]
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
HeavyState = SimState[int | SootAddressDescriptor, claripy.ast.BV | SootAddressDescriptor]
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
class SuccessorsEngine(SimEngine[HeavyState, SimSuccessors]):
|
|
552
|
+
"""
|
|
553
|
+
A mixin for SimEngine which implements ``process`` to perform common operations related to symbolic execution
|
|
554
|
+
and dispatches to a ``process_successors`` method to fill a SimSuccessors object with the results.
|
|
555
|
+
"""
|
|
556
|
+
|
|
557
|
+
def __init__(self, project: angr.Project):
|
|
558
|
+
super().__init__(project)
|
|
559
|
+
|
|
560
|
+
self.successors: SimSuccessors | None = None
|
|
561
|
+
|
|
562
|
+
def process(self, state: HeavyState, **kwargs) -> SimSuccessors: # pylint:disable=unused-argument
|
|
563
|
+
"""
|
|
564
|
+
Perform execution with a state.
|
|
565
|
+
|
|
566
|
+
You should only override this method in a subclass in order to provide the correct method signature and
|
|
567
|
+
docstring. You should override the ``_process`` method to do your actual execution.
|
|
568
|
+
|
|
569
|
+
:param state: The state with which to execute. This state will be copied before
|
|
570
|
+
modification.
|
|
571
|
+
:param inline: This is an inline execution. Do not bother copying the state.
|
|
572
|
+
:param force_addr: Force execution to pretend that we're working at this concrete address
|
|
573
|
+
:returns: A SimSuccessors object categorizing the execution's successor states
|
|
574
|
+
"""
|
|
575
|
+
inline = kwargs.pop("inline", False)
|
|
576
|
+
force_addr = kwargs.pop("force_addr", None)
|
|
577
|
+
|
|
578
|
+
ip = state._ip
|
|
579
|
+
addr = (
|
|
580
|
+
(ip if isinstance(ip, SootAddressDescriptor) else state.solver.eval(ip))
|
|
581
|
+
if force_addr is None
|
|
582
|
+
else force_addr
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
# make a copy of the initial state for actual processing, if needed
|
|
586
|
+
new_state = state.copy() if not inline and o.COPY_STATES in state.options else state
|
|
587
|
+
# enforce this distinction
|
|
588
|
+
old_state = state
|
|
589
|
+
del state
|
|
590
|
+
self.state = new_state
|
|
591
|
+
|
|
592
|
+
# we have now officially begun the stepping process! now is where we "cycle" a state's
|
|
593
|
+
# data - move the "present" into the "past" by pushing an entry on the history stack.
|
|
594
|
+
# nuance: make sure to copy from the PREVIOUS state to the CURRENT one
|
|
595
|
+
# to avoid creating a dead link in the history, messing up the statehierarchy
|
|
596
|
+
new_state.register_plugin("history", old_state.history.make_child())
|
|
597
|
+
new_state.history.recent_bbl_addrs.append(addr)
|
|
598
|
+
if new_state.arch.unicorn_support:
|
|
599
|
+
assert isinstance(addr, int)
|
|
600
|
+
new_state.scratch.executed_pages_set = {addr & ~0xFFF}
|
|
601
|
+
|
|
602
|
+
self.successors = SimSuccessors(addr, old_state)
|
|
603
|
+
|
|
604
|
+
new_state._inspect(
|
|
605
|
+
"engine_process", when=BP_BEFORE, sim_engine=self, sim_successors=self.successors, address=addr
|
|
606
|
+
)
|
|
607
|
+
self.successors = new_state._inspect_getattr("sim_successors", self.successors)
|
|
608
|
+
try:
|
|
609
|
+
self.process_successors(self.successors, **kwargs)
|
|
610
|
+
except SimException as e:
|
|
611
|
+
if o.EXCEPTION_HANDLING not in old_state.options:
|
|
612
|
+
raise
|
|
613
|
+
assert old_state.project is not None
|
|
614
|
+
old_state.project.simos.handle_exception(self.successors, self, e)
|
|
615
|
+
|
|
616
|
+
new_state._inspect("engine_process", when=BP_AFTER, sim_successors=self.successors, address=addr)
|
|
617
|
+
self.successors = new_state._inspect_getattr("sim_successors", self.successors)
|
|
618
|
+
assert self.successors is not None
|
|
619
|
+
|
|
620
|
+
# downsizing
|
|
621
|
+
if new_state.supports_inspect:
|
|
622
|
+
new_state.inspect.downsize()
|
|
623
|
+
# if not TRACK, clear actions on OLD state
|
|
624
|
+
# if o.TRACK_ACTION_HISTORY not in old_state.options:
|
|
625
|
+
# old_state.history.recent_events = []
|
|
626
|
+
|
|
627
|
+
# fix up the descriptions...
|
|
628
|
+
description = str(self.successors)
|
|
629
|
+
l.info("Ticked state: %s", description)
|
|
630
|
+
for succ in self.successors.all_successors:
|
|
631
|
+
succ.history.recent_description = description
|
|
632
|
+
for succ in self.successors.flat_successors:
|
|
633
|
+
succ.history.recent_description = description
|
|
634
|
+
|
|
635
|
+
return self.successors
|
|
636
|
+
|
|
637
|
+
def process_successors(self, successors, **kwargs): # pylint:disable=unused-argument,no-self-use
|
|
638
|
+
"""
|
|
639
|
+
Implement this function to fill out the SimSuccessors object with the results of stepping state.
|
|
640
|
+
|
|
641
|
+
In order to implement a model where multiple mixins can potentially handle a request, a mixin may implement
|
|
642
|
+
this method and then perform a super() call if it wants to pass on handling to the next mixin.
|
|
643
|
+
|
|
644
|
+
Keep in mind python's method resolution order when composing multiple classes implementing this method.
|
|
645
|
+
In short: left-to-right, depth-first, but deferring any base classes which are shared by multiple subclasses
|
|
646
|
+
(the merge point of a diamond pattern in the inheritance graph) until the last point where they would be
|
|
647
|
+
encountered in this depth-first search. For example, if you have classes A, B(A), C(B), D(A), E(C, D), then the
|
|
648
|
+
method resolution order will be E, C, B, D, A.
|
|
649
|
+
|
|
650
|
+
:param state: The state to manipulate
|
|
651
|
+
:param successors: The successors object to fill out
|
|
652
|
+
:param kwargs: Any extra arguments. Do not fail if you are passed unexpected arguments.
|
|
653
|
+
"""
|
|
654
|
+
successors.processed = False # mark failure
|
angr/engines/syscall.py
CHANGED
|
@@ -3,14 +3,14 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
import angr
|
|
5
5
|
from angr.errors import AngrUnsupportedSyscallError
|
|
6
|
-
from .
|
|
6
|
+
from .successors import SuccessorsEngine
|
|
7
7
|
from .procedure import ProcedureMixin
|
|
8
8
|
|
|
9
9
|
l = logging.getLogger(name=__name__)
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
# pylint:disable=abstract-method,arguments-differ
|
|
13
|
-
class SimEngineSyscall(
|
|
13
|
+
class SimEngineSyscall(SuccessorsEngine, ProcedureMixin):
|
|
14
14
|
"""
|
|
15
15
|
A SimEngine mixin which adds a successors handling step that checks if a syscall was just requested and if so
|
|
16
16
|
handles it as a step.
|
angr/engines/unicorn.py
CHANGED
|
@@ -8,7 +8,7 @@ import claripy
|
|
|
8
8
|
|
|
9
9
|
import angr
|
|
10
10
|
from angr.errors import SimIRSBError, SimIRSBNoDecodeError, SimValueError
|
|
11
|
-
from .
|
|
11
|
+
from .successors import SuccessorsEngine
|
|
12
12
|
from .vex.heavy.heavy import VEXEarlyExit
|
|
13
13
|
from angr import sim_options as o
|
|
14
14
|
from angr.misc.ux import once
|
|
@@ -21,7 +21,7 @@ from angr.utils.constants import DEFAULT_STATEMENT
|
|
|
21
21
|
l = logging.getLogger(name=__name__)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
class SimEngineUnicorn(
|
|
24
|
+
class SimEngineUnicorn(SuccessorsEngine):
|
|
25
25
|
"""
|
|
26
26
|
Concrete execution in the Unicorn Engine, a fork of qemu.
|
|
27
27
|
|
|
@@ -281,7 +281,7 @@ class SimEngineUnicorn(SuccessorsMixin):
|
|
|
281
281
|
def _get_vex_block_details(self, block_addr, block_size):
|
|
282
282
|
# Mostly based on the lifting code in HeavyVEXMixin
|
|
283
283
|
# pylint:disable=no-member
|
|
284
|
-
irsb =
|
|
284
|
+
irsb = self.project.factory.block(addr=block_addr, backup_state=self.state, size=block_size).vex
|
|
285
285
|
if irsb.size == 0:
|
|
286
286
|
if irsb.jumpkind == "Ijk_NoDecode":
|
|
287
287
|
if not self.state.project.is_hooked(irsb.addr):
|
angr/engines/vex/heavy/heavy.py
CHANGED
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
import claripy
|
|
4
4
|
import pyvex
|
|
5
5
|
|
|
6
|
-
from angr.engines.
|
|
6
|
+
from angr.engines.successors import SuccessorsEngine
|
|
7
7
|
from angr.engines.vex.light import VEXMixin
|
|
8
8
|
from angr.engines.vex.lifter import VEXLifter
|
|
9
9
|
from angr.engines.vex.claripy.datalayer import ClaripyDataMixin, symbol
|
|
@@ -57,7 +57,7 @@ class SimStateStorageMixin(VEXMixin):
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
# pylint:disable=arguments-differ
|
|
60
|
-
class HeavyVEXMixin(
|
|
60
|
+
class HeavyVEXMixin(SuccessorsEngine, ClaripyDataMixin, SimStateStorageMixin, VEXMixin, VEXLifter):
|
|
61
61
|
"""
|
|
62
62
|
Execution engine based on VEX, Valgrind's IR.
|
|
63
63
|
|
|
@@ -83,7 +83,6 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
83
83
|
self,
|
|
84
84
|
successors,
|
|
85
85
|
irsb=None,
|
|
86
|
-
insn_text=None,
|
|
87
86
|
insn_bytes=None,
|
|
88
87
|
thumb=False,
|
|
89
88
|
size=None,
|
|
@@ -99,21 +98,10 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
99
98
|
extra_stop_points=extra_stop_points,
|
|
100
99
|
num_inst=num_inst,
|
|
101
100
|
size=size,
|
|
102
|
-
insn_text=insn_text,
|
|
103
101
|
insn_bytes=insn_bytes,
|
|
104
102
|
**kwargs,
|
|
105
103
|
)
|
|
106
104
|
|
|
107
|
-
if insn_text is not None:
|
|
108
|
-
if insn_bytes is not None:
|
|
109
|
-
raise errors.SimEngineError("You cannot provide both 'insn_bytes' and 'insn_text'!")
|
|
110
|
-
|
|
111
|
-
insn_bytes = self.project.arch.asm(insn_text, addr=successors.addr, thumb=thumb)
|
|
112
|
-
if insn_bytes is None:
|
|
113
|
-
raise errors.AngrAssemblyError(
|
|
114
|
-
"Assembling failed. Please make sure keystone is installed, and the assembly string is correct."
|
|
115
|
-
)
|
|
116
|
-
|
|
117
105
|
successors.sort = "IRSB"
|
|
118
106
|
successors.description = "IRSB"
|
|
119
107
|
self.state.history.recent_block_count = 1
|
|
@@ -137,9 +125,9 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
137
125
|
|
|
138
126
|
if irsb is None:
|
|
139
127
|
irsb = self.lift_vex(
|
|
128
|
+
insn_bytes=insn_bytes,
|
|
140
129
|
addr=addr,
|
|
141
130
|
state=self.state,
|
|
142
|
-
insn_bytes=insn_bytes,
|
|
143
131
|
thumb=thumb,
|
|
144
132
|
size=size,
|
|
145
133
|
num_inst=num_inst,
|