angr 9.2.139__py3-none-manylinux2014_x86_64.whl → 9.2.141__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 +136 -53
- angr/analyses/calling_convention/fact_collector.py +44 -18
- angr/analyses/calling_convention/utils.py +3 -1
- angr/analyses/cfg/cfg_base.py +13 -0
- angr/analyses/cfg/cfg_fast.py +11 -0
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +9 -8
- angr/analyses/decompiler/ail_simplifier.py +115 -72
- angr/analyses/decompiler/callsite_maker.py +24 -11
- angr/analyses/decompiler/clinic.py +78 -43
- angr/analyses/decompiler/decompiler.py +18 -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/duplication_reverter/duplication_reverter.py +3 -1
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +21 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +84 -15
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +92 -11
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +53 -9
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +44 -7
- angr/analyses/decompiler/region_identifier.py +6 -4
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +287 -122
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +31 -13
- angr/analyses/decompiler/ssailification/rewriting.py +23 -15
- angr/analyses/decompiler/ssailification/rewriting_engine.py +105 -24
- angr/analyses/decompiler/ssailification/ssailification.py +22 -14
- angr/analyses/decompiler/structured_codegen/c.py +73 -137
- angr/analyses/decompiler/structuring/dream.py +22 -18
- angr/analyses/decompiler/structuring/phoenix.py +158 -41
- angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
- angr/analyses/decompiler/structuring/structurer_base.py +37 -10
- angr/analyses/decompiler/structuring/structurer_nodes.py +4 -1
- angr/analyses/decompiler/utils.py +106 -21
- 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/s_reaching_definitions/s_rda_view.py +43 -25
- 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_ail.py +1 -1
- angr/analyses/variable_recovery/engine_base.py +7 -5
- angr/analyses/variable_recovery/engine_vex.py +20 -4
- angr/block.py +69 -107
- angr/callable.py +14 -7
- angr/calling_conventions.py +30 -11
- 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 +12 -22
- angr/knowledge_plugins/key_definitions/atoms.py +8 -4
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
- angr/knowledge_plugins/variables/variable_manager.py +7 -5
- angr/sim_type.py +19 -17
- angr/simos/simos.py +3 -1
- 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/utils/types.py +48 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/METADATA +6 -6
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/RECORD +87 -86
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/LICENSE +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/WHEEL +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/entry_points.txt +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/top_level.txt +0 -0
angr/calling_conventions.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import logging
|
|
4
4
|
from typing import cast
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
from collections.abc import Iterable, Sequence
|
|
6
7
|
from collections import defaultdict
|
|
7
8
|
import contextlib
|
|
8
9
|
|
|
@@ -82,7 +83,8 @@ class AllocHelper:
|
|
|
82
83
|
|
|
83
84
|
def size(self):
|
|
84
85
|
val = self.translate(self.ptr, claripy.BVV(0, len(self.ptr)))
|
|
85
|
-
assert val.op == "BVV"
|
|
86
|
+
assert isinstance(val, claripy.ast.Base) and val.op == "BVV"
|
|
87
|
+
assert isinstance(val.args[0], int)
|
|
86
88
|
return abs(val.args[0])
|
|
87
89
|
|
|
88
90
|
@classmethod
|
|
@@ -130,6 +132,7 @@ def refine_locs_with_struct_type(
|
|
|
130
132
|
arg_type = SimTypeInt(label=arg_type.label).with_arch(arch)
|
|
131
133
|
|
|
132
134
|
if isinstance(arg_type, (SimTypeReg, SimTypeNum, SimTypeFloat)):
|
|
135
|
+
assert arg_type.size is not None
|
|
133
136
|
seen_bytes = 0
|
|
134
137
|
pieces = []
|
|
135
138
|
while seen_bytes < arg_type.size // arch.byte_width:
|
|
@@ -147,20 +150,21 @@ def refine_locs_with_struct_type(
|
|
|
147
150
|
piece.is_fp = True
|
|
148
151
|
return piece
|
|
149
152
|
if isinstance(arg_type, SimTypeFixedSizeArray):
|
|
153
|
+
assert arg_type.elem_type.size is not None and arg_type.length is not None
|
|
150
154
|
# TODO explicit stride
|
|
151
|
-
|
|
155
|
+
locs_list = [
|
|
152
156
|
refine_locs_with_struct_type(
|
|
153
157
|
arch, locs, arg_type.elem_type, offset=offset + i * arg_type.elem_type.size // arch.byte_width
|
|
154
158
|
)
|
|
155
159
|
for i in range(arg_type.length)
|
|
156
160
|
]
|
|
157
|
-
return SimArrayArg(
|
|
161
|
+
return SimArrayArg(locs_list)
|
|
158
162
|
if isinstance(arg_type, SimStruct):
|
|
159
|
-
|
|
163
|
+
locs_dict = {
|
|
160
164
|
field: refine_locs_with_struct_type(arch, locs, field_ty, offset=offset + arg_type.offsets[field])
|
|
161
165
|
for field, field_ty in arg_type.fields.items()
|
|
162
166
|
}
|
|
163
|
-
return SimStructArg(arg_type,
|
|
167
|
+
return SimStructArg(arg_type, locs_dict)
|
|
164
168
|
if isinstance(arg_type, SimUnion):
|
|
165
169
|
# Treat a SimUnion as functionality equivalent to its longest member
|
|
166
170
|
for member in arg_type.members.values():
|
|
@@ -574,8 +578,8 @@ class SimCC:
|
|
|
574
578
|
# (if applicable) and the arguments. Probably zero.
|
|
575
579
|
STACKARG_SP_DIFF = 0 # The amount of stack space reserved for the return address
|
|
576
580
|
CALLER_SAVED_REGS: list[str] = [] # Caller-saved registers
|
|
577
|
-
RETURN_ADDR: SimFunctionArgument
|
|
578
|
-
RETURN_VAL: SimFunctionArgument
|
|
581
|
+
RETURN_ADDR: SimFunctionArgument # The location where the return address is stored, as a SimFunctionArgument
|
|
582
|
+
RETURN_VAL: SimFunctionArgument # The location where the return value is stored, as a SimFunctionArgument
|
|
579
583
|
OVERFLOW_RETURN_VAL: SimFunctionArgument | None = (
|
|
580
584
|
None # The second half of the location where a double-length return value is stored
|
|
581
585
|
)
|
|
@@ -687,7 +691,7 @@ class SimCC:
|
|
|
687
691
|
ty = ty.with_arch(self.arch)
|
|
688
692
|
if isinstance(ty, (SimStruct, SimUnion, SimTypeFixedSizeArray)):
|
|
689
693
|
raise AngrTypeError(
|
|
690
|
-
f"{self} doesn't know how to return aggregate types. Consider overriding return_val to "
|
|
694
|
+
f"{self} doesn't know how to return aggregate types ({type(ty)}). Consider overriding return_val to "
|
|
691
695
|
"implement its ABI logic"
|
|
692
696
|
)
|
|
693
697
|
if self.return_in_implicit_outparam(ty):
|
|
@@ -728,6 +732,7 @@ class SimCC:
|
|
|
728
732
|
l.warning("Function argument type cannot be BOT. Treating it as a 32-bit int.")
|
|
729
733
|
arg_type = SimTypeInt().with_arch(self.arch)
|
|
730
734
|
is_fp = isinstance(arg_type, SimTypeFloat)
|
|
735
|
+
assert arg_type.size is not None
|
|
731
736
|
size = arg_type.size // self.arch.byte_width
|
|
732
737
|
try:
|
|
733
738
|
arg = next(session.fp_iter) if is_fp else next(session.int_iter)
|
|
@@ -760,7 +765,7 @@ class SimCC:
|
|
|
760
765
|
def is_fp_value(val):
|
|
761
766
|
return (
|
|
762
767
|
isinstance(val, (float, claripy.ast.FP))
|
|
763
|
-
or (isinstance(val, claripy.ast.Base) and val.op.startswith("fp"))
|
|
768
|
+
or (isinstance(val, claripy.ast.Base) and val.op.startswith("fp")) # type: ignore
|
|
764
769
|
or (isinstance(val, claripy.ast.Base) and val.op == "Reverse" and val.args[0].op.startswith("fp"))
|
|
765
770
|
)
|
|
766
771
|
|
|
@@ -1130,7 +1135,7 @@ class SimCC:
|
|
|
1130
1135
|
|
|
1131
1136
|
@staticmethod
|
|
1132
1137
|
def find_cc(
|
|
1133
|
-
arch: archinfo.Arch, args:
|
|
1138
|
+
arch: archinfo.Arch, args: Sequence[SimFunctionArgument], sp_delta: int, platform: str = "Linux"
|
|
1134
1139
|
) -> SimCC | None:
|
|
1135
1140
|
"""
|
|
1136
1141
|
Pinpoint the best-fit calling convention and return the corresponding SimCC instance, or None if no fit is
|
|
@@ -1334,6 +1339,20 @@ class SimCCMicrosoftAMD64(SimCC):
|
|
|
1334
1339
|
def return_val(self, ty, perspective_returned=False):
|
|
1335
1340
|
if ty._arch is None:
|
|
1336
1341
|
ty = ty.with_arch(self.arch)
|
|
1342
|
+
|
|
1343
|
+
# Unions are allocated according to the layout of the largest member
|
|
1344
|
+
if isinstance(ty, SimUnion):
|
|
1345
|
+
chosen = None
|
|
1346
|
+
size = None
|
|
1347
|
+
for subty in ty.members.values():
|
|
1348
|
+
if subty.size is not None and (size is None or size < subty.size):
|
|
1349
|
+
chosen = subty
|
|
1350
|
+
size = subty.size
|
|
1351
|
+
if chosen is None:
|
|
1352
|
+
# fallback to void*
|
|
1353
|
+
chosen = SimTypePointer(SimTypeBottom())
|
|
1354
|
+
return self.return_val(chosen, perspective_returned=perspective_returned)
|
|
1355
|
+
|
|
1337
1356
|
if not isinstance(ty, SimStruct):
|
|
1338
1357
|
return super().return_val(ty, perspective_returned)
|
|
1339
1358
|
|
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):
|