angr 9.2.123__py3-none-macosx_11_0_arm64.whl → 9.2.124__py3-none-macosx_11_0_arm64.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/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
- angr/analyses/decompiler/ail_simplifier.py +16 -19
- angr/analyses/decompiler/callsite_maker.py +8 -7
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
- angr/analyses/decompiler/clinic.py +27 -1
- angr/analyses/decompiler/condition_processor.py +10 -3
- angr/analyses/decompiler/decompilation_cache.py +2 -0
- angr/analyses/decompiler/decompiler.py +50 -8
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
- angr/analyses/decompiler/dephication/rewriting_engine.py +64 -1
- angr/analyses/decompiler/expression_narrower.py +5 -1
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +7 -0
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +23 -4
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
- angr/analyses/decompiler/region_identifier.py +36 -0
- angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
- angr/analyses/decompiler/ssailification/rewriting.py +5 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
- angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
- angr/analyses/decompiler/ssailification/ssailification.py +17 -9
- angr/analyses/decompiler/ssailification/traversal.py +3 -1
- angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
- angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
- angr/analyses/decompiler/structured_codegen/c.py +42 -4
- angr/analyses/decompiler/structuring/phoenix.py +3 -0
- angr/analyses/propagator/engine_ail.py +10 -3
- angr/analyses/reaching_definitions/engine_ail.py +10 -15
- angr/analyses/s_propagator.py +16 -9
- angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
- angr/analyses/variable_recovery/engine_ail.py +14 -0
- angr/analyses/variable_recovery/engine_base.py +11 -0
- angr/engines/light/engine.py +12 -0
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/decompilation.py +45 -0
- angr/knowledge_plugins/key_definitions/atoms.py +8 -0
- angr/lib/angr_native.dylib +0 -0
- angr/procedures/definitions/parse_win32json.py +2 -1
- angr/storage/memory_mixins/actions_mixin.py +7 -7
- angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
- angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
- angr/storage/memory_mixins/clouseau_mixin.py +3 -3
- angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
- angr/storage/memory_mixins/default_filler_mixin.py +3 -3
- angr/storage/memory_mixins/memory_mixin.py +45 -34
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
- angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
- angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
- angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
- angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
- angr/storage/memory_mixins/simplification_mixin.py +2 -2
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
- angr/storage/memory_mixins/slotted_memory.py +3 -3
- angr/storage/memory_mixins/smart_find_mixin.py +1 -0
- angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
- angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
- angr/storage/memory_object.py +4 -3
- angr/utils/constants.py +1 -1
- angr/utils/graph.py +15 -0
- angr/vaults.py +2 -2
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/METADATA +6 -6
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/RECORD +84 -83
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from collections.abc import Iterator
|
|
3
|
+
from typing import Any, Generic, TypeGuard, TypeVar, cast
|
|
3
4
|
import archinfo
|
|
4
5
|
|
|
5
6
|
import claripy
|
|
6
7
|
|
|
8
|
+
from angr.errors import AngrTypeError
|
|
7
9
|
from angr.storage.memory_object import bv_slice
|
|
8
10
|
|
|
11
|
+
MVType = TypeVar("MVType", bound=claripy.ast.BV | claripy.ast.FP)
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
class MultiValues(Generic[MVType]):
|
|
11
15
|
"""
|
|
12
16
|
Represents a byte vector where each byte can have one or multiple values.
|
|
13
17
|
|
|
@@ -20,27 +24,31 @@ class MultiValues:
|
|
|
20
24
|
"_single_value",
|
|
21
25
|
)
|
|
22
26
|
|
|
23
|
-
_single_value:
|
|
24
|
-
_values: dict[int, set[
|
|
27
|
+
_single_value: MVType | None
|
|
28
|
+
_values: dict[int, set[MVType]] | None
|
|
25
29
|
|
|
26
30
|
def __init__(
|
|
27
31
|
self,
|
|
28
|
-
v:
|
|
29
|
-
offset_to_values=None,
|
|
32
|
+
v: MVType | MultiValues[MVType] | None | dict[int, set[MVType]] = None,
|
|
33
|
+
offset_to_values: dict[int, set[MVType]] | None = None,
|
|
30
34
|
):
|
|
31
35
|
if v is not None and offset_to_values is not None:
|
|
32
36
|
raise TypeError("You cannot specify v and offset_to_values at the same time!")
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
38
|
+
if v is None:
|
|
39
|
+
self._single_value = None
|
|
40
|
+
self._values = offset_to_values
|
|
41
|
+
elif isinstance(v, (claripy.ast.BV, claripy.ast.FP)):
|
|
42
|
+
self._single_value = v
|
|
43
|
+
self._values = None
|
|
44
|
+
elif isinstance(v, MultiValues):
|
|
45
|
+
self._single_value = v._single_value
|
|
46
|
+
self._values = v._values
|
|
47
|
+
elif isinstance(v, dict):
|
|
48
|
+
self._single_value = None
|
|
49
|
+
self._values = v
|
|
50
|
+
else:
|
|
51
|
+
raise TypeError(type(v))
|
|
44
52
|
|
|
45
53
|
if self._single_value is None and self._values is None:
|
|
46
54
|
self._values = {}
|
|
@@ -56,7 +64,7 @@ class MultiValues:
|
|
|
56
64
|
if not isinstance(vs, set):
|
|
57
65
|
raise TypeError("Each value in offset_to_values must be a set!")
|
|
58
66
|
|
|
59
|
-
def add_value(self, offset: int, value:
|
|
67
|
+
def add_value(self, offset: int, value: MVType) -> None:
|
|
60
68
|
if len(value) == 0:
|
|
61
69
|
return
|
|
62
70
|
if self._single_value is not None:
|
|
@@ -80,32 +88,40 @@ class MultiValues:
|
|
|
80
88
|
|
|
81
89
|
succ_offset = self._adjacent_offset(offset, before=False)
|
|
82
90
|
if succ_offset is not None:
|
|
83
|
-
value_end = offset + value.
|
|
91
|
+
value_end = offset + value.size() // 8
|
|
84
92
|
if value_end > succ_offset:
|
|
93
|
+
if isinstance(value, claripy.ast.FP):
|
|
94
|
+
raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
|
|
85
95
|
# value is too long. we need to break value into two
|
|
86
96
|
mid_value_size = succ_offset - offset
|
|
87
|
-
remaining_value = value[value.
|
|
97
|
+
remaining_value = cast(MVType, value[value.size() - mid_value_size * 8 - 1 : 0])
|
|
88
98
|
# update value
|
|
89
|
-
value = value[value.
|
|
99
|
+
value = cast(MVType, value[value.size() - 1 : value.size() - mid_value_size * 8])
|
|
90
100
|
self.add_value(succ_offset, remaining_value)
|
|
91
101
|
|
|
92
102
|
if self._values[offset]:
|
|
93
|
-
curr_value_size = next(iter(self._values[offset])).
|
|
94
|
-
if curr_value_size > value.
|
|
103
|
+
curr_value_size = next(iter(self._values[offset])).size() // 8
|
|
104
|
+
if curr_value_size > value.size() // 8:
|
|
95
105
|
# we need to break existing values
|
|
96
106
|
new_curr_values = set()
|
|
97
107
|
remaining_values = set()
|
|
98
108
|
for v in self._values[offset]:
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
if isinstance(v, claripy.ast.FP):
|
|
110
|
+
raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
|
|
111
|
+
|
|
112
|
+
new_curr_values.add(v[v.size() - 1 : v.size() - value.size()])
|
|
113
|
+
remaining_values.add(v[v.size() - value.size() - 1 : 0])
|
|
101
114
|
self._values[offset] = new_curr_values
|
|
102
115
|
for v in remaining_values:
|
|
103
|
-
self.add_value(offset + value.
|
|
104
|
-
elif curr_value_size < value.
|
|
116
|
+
self.add_value(offset + value.size() // 8, v)
|
|
117
|
+
elif curr_value_size < value.size() // 8:
|
|
118
|
+
if isinstance(value, claripy.ast.FP):
|
|
119
|
+
raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
|
|
120
|
+
|
|
105
121
|
# value is too long. we need to break value into two
|
|
106
|
-
remaining_value = value[value.
|
|
122
|
+
remaining_value = cast(MVType, value[value.size() - curr_value_size * 8 - 1 : 0])
|
|
107
123
|
# update value
|
|
108
|
-
value = value[value.
|
|
124
|
+
value = cast(MVType, value[value.size() - 1 : value.size() - curr_value_size * 8])
|
|
109
125
|
self.add_value(offset + curr_value_size, remaining_value)
|
|
110
126
|
|
|
111
127
|
self._values[offset].add(value)
|
|
@@ -113,26 +129,28 @@ class MultiValues:
|
|
|
113
129
|
pre_offset = self._adjacent_offset(offset, before=True)
|
|
114
130
|
if pre_offset is not None:
|
|
115
131
|
pre_values = self._values[pre_offset]
|
|
116
|
-
pre_values_size = next(iter(pre_values)).
|
|
132
|
+
pre_values_size = next(iter(pre_values)).size() // 8
|
|
117
133
|
if pre_offset + pre_values_size > offset:
|
|
118
134
|
# we need to break the preceding values
|
|
119
135
|
new_pre_value_size = offset - pre_offset
|
|
120
136
|
new_pre_values = set()
|
|
121
137
|
remaining_values = set()
|
|
122
138
|
for v in pre_values:
|
|
123
|
-
|
|
124
|
-
|
|
139
|
+
if isinstance(v, claripy.ast.FP):
|
|
140
|
+
raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
|
|
141
|
+
new_pre_values.add(v[v.size() - 1 : v.size() - new_pre_value_size * 8])
|
|
142
|
+
remaining_values.add(v[v.size() - new_pre_value_size * 8 - 1 : 0])
|
|
125
143
|
self._values[pre_offset] = new_pre_values
|
|
126
144
|
for v in remaining_values:
|
|
127
145
|
self.add_value(offset, v)
|
|
128
146
|
|
|
129
|
-
def one_value(self, strip_annotations: bool = False) ->
|
|
147
|
+
def one_value(self, strip_annotations: bool = False) -> MVType | None:
|
|
130
148
|
if self._single_value is not None:
|
|
131
149
|
return self._single_value
|
|
132
150
|
|
|
133
151
|
assert self._values is not None
|
|
134
152
|
|
|
135
|
-
if len(self._values) == 1 and len(self._values[0]) == 1:
|
|
153
|
+
if len(self._values) == 1 and 0 in self._values and len(self._values[0]) == 1:
|
|
136
154
|
return next(iter(self._values[0]))
|
|
137
155
|
if strip_annotations:
|
|
138
156
|
all_values_wo_annotations = {
|
|
@@ -144,7 +162,7 @@ class MultiValues:
|
|
|
144
162
|
|
|
145
163
|
def __len__(self) -> int:
|
|
146
164
|
if self._single_value is not None:
|
|
147
|
-
return self._single_value.
|
|
165
|
+
return self._single_value.size()
|
|
148
166
|
|
|
149
167
|
assert self._values is not None
|
|
150
168
|
|
|
@@ -155,7 +173,7 @@ class MultiValues:
|
|
|
155
173
|
max_len = max(x.size() for x in self._values[max_offset])
|
|
156
174
|
return max_offset * 8 + max_len # FIXME: we are assuming byte_width of 8
|
|
157
175
|
|
|
158
|
-
def merge(self, mv: MultiValues) -> MultiValues:
|
|
176
|
+
def merge(self, mv: MultiValues[MVType]) -> MultiValues[MVType]:
|
|
159
177
|
new_values = {k: set(v) for k, v in self.items()}
|
|
160
178
|
for off, vs in mv.items():
|
|
161
179
|
if off not in new_values:
|
|
@@ -187,47 +205,46 @@ class MultiValues:
|
|
|
187
205
|
def __contains__(self, offset: int) -> bool:
|
|
188
206
|
if self._single_value is not None:
|
|
189
207
|
return offset == 0
|
|
190
|
-
|
|
208
|
+
assert self._values is not None
|
|
209
|
+
return offset in self._values
|
|
191
210
|
|
|
192
|
-
def __getitem__(self, offset: int) -> set[
|
|
211
|
+
def __getitem__(self, offset: int) -> set[MVType]:
|
|
193
212
|
if self._single_value is not None:
|
|
194
213
|
if offset == 0:
|
|
195
214
|
return {self._single_value}
|
|
196
|
-
raise KeyError
|
|
197
|
-
|
|
198
|
-
raise KeyError
|
|
215
|
+
raise KeyError(offset)
|
|
216
|
+
assert self._values is not None
|
|
199
217
|
return self._values[offset]
|
|
200
218
|
|
|
201
219
|
def keys(self) -> set[int]:
|
|
202
220
|
if self._single_value is not None:
|
|
203
221
|
return {0}
|
|
204
|
-
|
|
222
|
+
assert self._values is not None
|
|
223
|
+
return set(self._values.keys())
|
|
205
224
|
|
|
206
|
-
def values(self) -> Iterator[set[
|
|
225
|
+
def values(self) -> Iterator[set[MVType]]:
|
|
207
226
|
if self._single_value is not None:
|
|
208
227
|
yield {self._single_value}
|
|
209
228
|
else:
|
|
210
|
-
|
|
211
|
-
return
|
|
229
|
+
assert self._values is not None
|
|
212
230
|
yield from self._values.values()
|
|
213
231
|
|
|
214
|
-
def items(self) -> Iterator[tuple[int, set[
|
|
232
|
+
def items(self) -> Iterator[tuple[int, set[MVType]]]:
|
|
215
233
|
if self._single_value is not None:
|
|
216
234
|
yield 0, {self._single_value}
|
|
217
235
|
else:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
else:
|
|
221
|
-
yield from self._values.items()
|
|
236
|
+
assert self._values is not None
|
|
237
|
+
yield from self._values.items()
|
|
222
238
|
|
|
223
239
|
def count(self) -> int:
|
|
224
240
|
if self._single_value is not None:
|
|
225
241
|
return 1
|
|
226
|
-
|
|
227
|
-
return 0
|
|
242
|
+
assert self._values is not None
|
|
228
243
|
return len(self._values)
|
|
229
244
|
|
|
230
|
-
def extract(
|
|
245
|
+
def extract(
|
|
246
|
+
self: MultiValues[claripy.ast.BV], offset: int, length: int, endness: str
|
|
247
|
+
) -> MultiValues[claripy.ast.BV]:
|
|
231
248
|
end = offset + length
|
|
232
249
|
result = MultiValues(claripy.BVV(b""))
|
|
233
250
|
for obj_offset, values in self.items():
|
|
@@ -240,16 +257,19 @@ class MultiValues:
|
|
|
240
257
|
|
|
241
258
|
slice_start = max(0, offset - obj_offset)
|
|
242
259
|
slice_end = min(obj_length, end - obj_offset)
|
|
243
|
-
|
|
260
|
+
bv_value: claripy.ast.BV = claripy.fpToIEEEBV(value) if isinstance(value, claripy.ast.FP) else value
|
|
261
|
+
sliced = bv_slice(bv_value, slice_start, slice_end - slice_start, endness == archinfo.Endness.LE, 8)
|
|
244
262
|
if len(sliced):
|
|
245
263
|
result.add_value(max(0, obj_offset - offset), sliced)
|
|
246
264
|
|
|
247
265
|
return result
|
|
248
266
|
|
|
249
|
-
def concat(
|
|
250
|
-
|
|
267
|
+
def concat(
|
|
268
|
+
self: MultiValues[claripy.ast.BV], other: MultiValues[claripy.ast.BV] | claripy.ast.BV | bytes
|
|
269
|
+
) -> MultiValues[claripy.ast.BV]:
|
|
270
|
+
if isinstance(other, (bytes, bytearray, memoryview)):
|
|
251
271
|
other = claripy.BVV(other)
|
|
252
|
-
if isinstance(other, claripy.ast.
|
|
272
|
+
if isinstance(other, claripy.ast.BV):
|
|
253
273
|
other = MultiValues(other)
|
|
254
274
|
offset = len(self) // 8
|
|
255
275
|
result = MultiValues(self)
|
|
@@ -283,3 +303,17 @@ class MultiValues:
|
|
|
283
303
|
# we missed it...
|
|
284
304
|
return None
|
|
285
305
|
return None
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def mv_is_bv(mv: MultiValues[Any]) -> TypeGuard[MultiValues[claripy.ast.BV]]:
|
|
309
|
+
if mv._single_value is not None:
|
|
310
|
+
return isinstance(mv._single_value, claripy.ast.BV)
|
|
311
|
+
assert mv._values is not None
|
|
312
|
+
return all(isinstance(value, claripy.ast.BV) for valueset in mv._values.values() for value in valueset)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def mv_is_fp(mv: MultiValues[Any]) -> TypeGuard[MultiValues[claripy.ast.FP]]:
|
|
316
|
+
if mv._single_value is not None:
|
|
317
|
+
return isinstance(mv._single_value, claripy.ast.FP)
|
|
318
|
+
assert mv._values is not None
|
|
319
|
+
return all(isinstance(value, claripy.ast.FP) for valueset in mv._values.values() for value in valueset)
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
from typing import Union, Any
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
|
|
7
|
+
from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
7
8
|
from angr.utils.dynamic_dictlist import DynamicDictList
|
|
8
9
|
from angr.storage.memory_object import SimMemoryObject, SimLabeledMemoryObject
|
|
9
10
|
from . import PageBase
|
|
@@ -20,10 +21,9 @@ class MVListPage(
|
|
|
20
21
|
PageBase,
|
|
21
22
|
):
|
|
22
23
|
"""
|
|
23
|
-
MVListPage allows storing multiple values at the same location
|
|
24
|
+
MVListPage allows storing multiple values at the same location.
|
|
24
25
|
|
|
25
|
-
Each store() may take a value or multiple values
|
|
26
|
-
or not.
|
|
26
|
+
Each store() may take a value or multiple values.
|
|
27
27
|
Each load() returns an iterator of all values stored at that location.
|
|
28
28
|
"""
|
|
29
29
|
|
|
@@ -104,8 +104,8 @@ class MVListPage(
|
|
|
104
104
|
self.stored_offset.add(subaddr)
|
|
105
105
|
result[-1] = (global_start_addr, new_item)
|
|
106
106
|
|
|
107
|
-
def store(self, addr, data, size=None, endness=None, memory=None, cooperate=False,
|
|
108
|
-
super().store(addr, data, size=size, endness=endness, memory=memory, cooperate=cooperate,
|
|
107
|
+
def store(self, addr, data, size=None, endness=None, memory=None, cooperate=False, **kwargs):
|
|
108
|
+
super().store(addr, data, size=size, endness=endness, memory=memory, cooperate=cooperate, **kwargs)
|
|
109
109
|
|
|
110
110
|
if not cooperate:
|
|
111
111
|
data = self._force_store_cooperation(addr, data, size, endness, memory=memory, **kwargs)
|
|
@@ -117,22 +117,12 @@ class MVListPage(
|
|
|
117
117
|
self.content = DynamicDictList(max_size=len(self.content))
|
|
118
118
|
self.stored_offset = set()
|
|
119
119
|
else:
|
|
120
|
-
if
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
self.stored_offset.add(subaddr)
|
|
127
|
-
else:
|
|
128
|
-
for subaddr in range(addr, addr + size):
|
|
129
|
-
if self.content[subaddr] is None:
|
|
130
|
-
self.content[subaddr] = data
|
|
131
|
-
elif type(self.content[subaddr]) is set:
|
|
132
|
-
self.content[subaddr] |= data
|
|
133
|
-
else:
|
|
134
|
-
self.content[subaddr] = {self.content[subaddr]} | data
|
|
135
|
-
self.stored_offset.add(subaddr)
|
|
120
|
+
if len(data) == 1:
|
|
121
|
+
# unpack
|
|
122
|
+
data: _MOTYPE = next(iter(data))
|
|
123
|
+
for subaddr in range(addr, addr + size):
|
|
124
|
+
self.content[subaddr] = data
|
|
125
|
+
self.stored_offset.add(subaddr)
|
|
136
126
|
|
|
137
127
|
def erase(self, addr, size=None, **kwargs) -> None:
|
|
138
128
|
for off in range(size):
|
|
@@ -143,8 +133,9 @@ class MVListPage(
|
|
|
143
133
|
others: list[MVListPage],
|
|
144
134
|
merge_conditions,
|
|
145
135
|
common_ancestor=None,
|
|
146
|
-
|
|
147
|
-
|
|
136
|
+
*,
|
|
137
|
+
page_addr: int,
|
|
138
|
+
memory: MemoryMixin,
|
|
148
139
|
changed_offsets: set[int] | None = None,
|
|
149
140
|
):
|
|
150
141
|
if changed_offsets is None:
|
|
@@ -230,7 +221,7 @@ class MVListPage(
|
|
|
230
221
|
# new_object = self._replace_memory_object(our_mo, merged_val, page_addr, memory.page_size)
|
|
231
222
|
|
|
232
223
|
new_mos = {SimMemoryObject(v, mo_base, endness=the_endness) for v in merged_val}
|
|
233
|
-
self.store(b, new_mos, size=size, cooperate=True
|
|
224
|
+
self.store(b, new_mos, size=size, cooperate=True)
|
|
234
225
|
|
|
235
226
|
merged_offsets.add(b)
|
|
236
227
|
|
|
@@ -271,7 +262,7 @@ class MVListPage(
|
|
|
271
262
|
continue
|
|
272
263
|
|
|
273
264
|
new_mos = {SimMemoryObject(v, page_addr + b, endness="Iend_BE") for v in merged_val}
|
|
274
|
-
self.store(b, new_mos, size=min_size, cooperate=True
|
|
265
|
+
self.store(b, new_mos, size=min_size, cooperate=True)
|
|
275
266
|
merged_offsets.add(b)
|
|
276
267
|
|
|
277
268
|
self.stored_offset |= merged_offsets
|
|
@@ -6,29 +6,31 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
|
6
6
|
|
|
7
7
|
class PermissionsMixin(MemoryMixin):
|
|
8
8
|
"""
|
|
9
|
-
This mixin adds a
|
|
10
|
-
permissions checking.
|
|
9
|
+
This mixin adds a permissions_bits field and properties for extracting the read/write/exec permissions. It does NOT
|
|
10
|
+
add permissions checking.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
def __init__(self, permissions=None, **kwargs):
|
|
13
|
+
def __init__(self, permissions: int | claripy.ast.BV | None = None, **kwargs):
|
|
14
14
|
super().__init__(**kwargs)
|
|
15
|
-
if
|
|
15
|
+
if permissions is None:
|
|
16
|
+
permissions = 7
|
|
17
|
+
if isinstance(permissions, int):
|
|
16
18
|
permissions = claripy.BVV(permissions, 3)
|
|
17
|
-
self.
|
|
19
|
+
self.permission_bits = permissions
|
|
18
20
|
|
|
19
21
|
def copy(self, memo):
|
|
20
22
|
o = super().copy(memo)
|
|
21
|
-
o.
|
|
23
|
+
o.permission_bits = self.permission_bits
|
|
22
24
|
return o
|
|
23
25
|
|
|
24
26
|
@property
|
|
25
27
|
def perm_read(self):
|
|
26
|
-
return self.
|
|
28
|
+
return self.permission_bits & 1
|
|
27
29
|
|
|
28
30
|
@property
|
|
29
31
|
def perm_write(self):
|
|
30
|
-
return self.
|
|
32
|
+
return self.permission_bits & 2
|
|
31
33
|
|
|
32
34
|
@property
|
|
33
35
|
def perm_exec(self):
|
|
34
|
-
return self.
|
|
36
|
+
return self.permission_bits & 4
|
|
@@ -343,13 +343,26 @@ class UltraPage(MemoryObjectMixin, PageBase):
|
|
|
343
343
|
|
|
344
344
|
return merged_offsets
|
|
345
345
|
|
|
346
|
-
def concrete_load(self, addr, size, **kwargs): # pylint: disable=arguments-differ
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
)
|
|
352
|
-
|
|
346
|
+
def concrete_load(self, addr, size, writing=False, with_bitmap=False, **kwargs): # pylint: disable=arguments-differ
|
|
347
|
+
assert self.concrete_data is not None
|
|
348
|
+
assert self.symbolic_bitmap is not None
|
|
349
|
+
mv_data = (
|
|
350
|
+
self.concrete_data
|
|
351
|
+
if isinstance(self.concrete_data, (memoryview, NotMemoryview))
|
|
352
|
+
else memoryview(self.concrete_data)
|
|
353
|
+
)
|
|
354
|
+
mv_bitm = (
|
|
355
|
+
self.symbolic_bitmap
|
|
356
|
+
if isinstance(self.symbolic_bitmap, (memoryview, NotMemoryview))
|
|
357
|
+
else memoryview(self.symbolic_bitmap)
|
|
358
|
+
)
|
|
359
|
+
result = (
|
|
360
|
+
mv_data[addr : addr + size],
|
|
361
|
+
mv_bitm[addr : addr + size],
|
|
362
|
+
)
|
|
363
|
+
if with_bitmap:
|
|
364
|
+
return result
|
|
365
|
+
return result[0]
|
|
353
366
|
|
|
354
367
|
def changed_bytes(self, other, page_addr=None) -> set[int]:
|
|
355
368
|
changed_candidates = super().changed_bytes(other)
|
|
@@ -489,3 +502,6 @@ class UltraPage(MemoryObjectMixin, PageBase):
|
|
|
489
502
|
self._update_mappings(b, old.object, new.object, memory=memory)
|
|
490
503
|
|
|
491
504
|
return new
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
from angr.storage.memory_mixins.paged_memory.page_backer_mixins import NotMemoryview
|
|
@@ -26,7 +26,7 @@ class PrivilegedPagingMixin(PagedMemoryMixin):
|
|
|
26
26
|
|
|
27
27
|
return page
|
|
28
28
|
|
|
29
|
-
def _initialize_page(self, pageno: int, priv: bool = False, **kwargs):
|
|
29
|
+
def _initialize_page(self, pageno: int, *, priv: bool = False, **kwargs):
|
|
30
30
|
if self.category == "mem" and not priv and o.STRICT_PAGE_ACCESS in self.state.options:
|
|
31
31
|
raise SimSegfaultException(pageno * self.page_size, "unmapped")
|
|
32
32
|
|
|
@@ -148,7 +148,7 @@ class MemoryRegionMetaMixin(MemoryMixin):
|
|
|
148
148
|
|
|
149
149
|
@MemoryMixin.memo
|
|
150
150
|
def copy(self, memo):
|
|
151
|
-
r
|
|
151
|
+
r = super().copy(memo)
|
|
152
152
|
r.alocs = copy.deepcopy(self.alocs)
|
|
153
153
|
r._related_function_addr = self._related_function_addr
|
|
154
154
|
r._is_stack = self._is_stack
|
|
@@ -187,7 +187,7 @@ class MemoryRegionMetaMixin(MemoryMixin):
|
|
|
187
187
|
|
|
188
188
|
return ret
|
|
189
189
|
|
|
190
|
-
def store(self, addr, data, bbl_addr=None, stmt_id=None, ins_addr=None, endness=None, **kwargs):
|
|
190
|
+
def store(self, addr, data, size=None, *, bbl_addr=None, stmt_id=None, ins_addr=None, endness=None, **kwargs):
|
|
191
191
|
# It comes from a SimProcedure. We'll use bbl_addr as the aloc_id
|
|
192
192
|
aloc_id = ins_addr if ins_addr is not None else bbl_addr
|
|
193
193
|
|
|
@@ -195,13 +195,13 @@ class MemoryRegionMetaMixin(MemoryMixin):
|
|
|
195
195
|
self.alocs[aloc_id] = AbstractLocation(
|
|
196
196
|
bbl_addr, stmt_id, self.id, region_offset=addr, size=len(data) // self.state.arch.byte_width
|
|
197
197
|
)
|
|
198
|
-
return super().store(addr, data, endness=endness, **kwargs)
|
|
198
|
+
return super().store(addr, data, size=size, endness=endness, **kwargs)
|
|
199
199
|
if self.alocs[aloc_id].update(addr, len(data) // self.state.arch.byte_width):
|
|
200
|
-
return super().store(addr, data, endness=endness, **kwargs)
|
|
201
|
-
return super().store(addr, data, endness=endness, **kwargs)
|
|
200
|
+
return super().store(addr, data, size=size, endness=endness, **kwargs)
|
|
201
|
+
return super().store(addr, data, size=size, endness=endness, **kwargs)
|
|
202
202
|
|
|
203
203
|
def load(
|
|
204
|
-
self, addr, size=None, bbl_addr=None, stmt_idx=None, ins_addr=None, **kwargs
|
|
204
|
+
self, addr, size=None, *, bbl_addr=None, stmt_idx=None, ins_addr=None, **kwargs
|
|
205
205
|
): # pylint:disable=unused-argument
|
|
206
206
|
# if bbl_addr is not None and stmt_id is not None:
|
|
207
207
|
return super().load(addr, size=size, **kwargs)
|
|
@@ -228,9 +228,11 @@ class MemoryRegionMetaMixin(MemoryMixin):
|
|
|
228
228
|
return r
|
|
229
229
|
|
|
230
230
|
def widen(self, others):
|
|
231
|
+
result = False
|
|
231
232
|
for other_region in others:
|
|
232
233
|
self._merge_alocs(other_region)
|
|
233
|
-
super().widen([other_region.memory])
|
|
234
|
+
result |= super().widen([other_region.memory])
|
|
235
|
+
return result
|
|
234
236
|
|
|
235
237
|
def dbg_print(self, indent=0):
|
|
236
238
|
"""
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
import logging
|
|
3
3
|
from itertools import count
|
|
4
4
|
from typing import Optional, TYPE_CHECKING
|
|
5
|
-
from collections.abc import Generator
|
|
5
|
+
from collections.abc import Generator
|
|
6
6
|
|
|
7
7
|
import claripy
|
|
8
8
|
from claripy.annotation import RegionAnnotation
|
|
@@ -74,7 +74,7 @@ class RegionedMemoryMixin(MemoryMixin):
|
|
|
74
74
|
|
|
75
75
|
@MemoryMixin.memo
|
|
76
76
|
def copy(self, memo):
|
|
77
|
-
o
|
|
77
|
+
o = super().copy(memo)
|
|
78
78
|
o._write_targets_limit = self._write_targets_limit
|
|
79
79
|
o._read_targets_limit = self._read_targets_limit
|
|
80
80
|
o._stack_size = self._stack_size
|
|
@@ -91,7 +91,7 @@ class RegionedMemoryMixin(MemoryMixin):
|
|
|
91
91
|
|
|
92
92
|
return o
|
|
93
93
|
|
|
94
|
-
def load(self, addr, size: BV | int | None = None, endness=None, condition: Bool | None = None, **kwargs):
|
|
94
|
+
def load(self, addr, size: BV | int | None = None, *, endness=None, condition: Bool | None = None, **kwargs):
|
|
95
95
|
if isinstance(size, BV) and size.has_annotation_type(RegionAnnotation):
|
|
96
96
|
_l.critical("load(): size %s is a ValueSet. Something is wrong.", size)
|
|
97
97
|
if self.state.scratch.ins_addr is not None:
|
|
@@ -132,7 +132,7 @@ class RegionedMemoryMixin(MemoryMixin):
|
|
|
132
132
|
|
|
133
133
|
return val
|
|
134
134
|
|
|
135
|
-
def store(self, addr, data, size: int | None = None, endness=None, **kwargs): # pylint:disable=unused-argument
|
|
135
|
+
def store(self, addr, data, size: int | None = None, *, endness=None, **kwargs): # pylint:disable=unused-argument
|
|
136
136
|
regioned_addrs_desc = self._normalize_address(addr)
|
|
137
137
|
if (
|
|
138
138
|
regioned_addrs_desc.cardinality >= self._write_targets_limit
|
|
@@ -144,7 +144,7 @@ class RegionedMemoryMixin(MemoryMixin):
|
|
|
144
144
|
for aw in gen:
|
|
145
145
|
self._region_store(aw.address, data, aw.region, endness, related_function_addr=aw.function_address)
|
|
146
146
|
|
|
147
|
-
def merge(self, others
|
|
147
|
+
def merge(self, others, merge_conditions, common_ancestor=None) -> bool:
|
|
148
148
|
r = False
|
|
149
149
|
for o in others:
|
|
150
150
|
for region_id, region in o._regions.items():
|
|
@@ -300,7 +300,7 @@ class RegionedMemoryMixin(MemoryMixin):
|
|
|
300
300
|
),
|
|
301
301
|
)
|
|
302
302
|
|
|
303
|
-
return self._regions[key].load(addr, size, bbl_addr, stmt_id, ins_addr, **kwargs)
|
|
303
|
+
return self._regions[key].load(addr, size, bbl_addr=bbl_addr, stmt_idx=stmt_id, ins_addr=ins_addr, **kwargs)
|
|
304
304
|
|
|
305
305
|
def _region_store(self, addr, data, key: str, endness, related_function_addr: int | None = None, **kwargs):
|
|
306
306
|
if key not in self._regions:
|
|
@@ -320,9 +320,9 @@ class RegionedMemoryMixin(MemoryMixin):
|
|
|
320
320
|
self._regions[key].store(
|
|
321
321
|
addr,
|
|
322
322
|
data,
|
|
323
|
-
self.state.scratch.bbl_addr,
|
|
324
|
-
self.state.scratch.stmt_idx,
|
|
325
|
-
self.state.scratch.ins_addr,
|
|
323
|
+
bbl_addr=self.state.scratch.bbl_addr,
|
|
324
|
+
stmt_id=self.state.scratch.stmt_idx,
|
|
325
|
+
ins_addr=self.state.scratch.ins_addr,
|
|
326
326
|
endness=endness,
|
|
327
327
|
**kwargs,
|
|
328
328
|
)
|
|
@@ -7,7 +7,7 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class SimpleInterfaceMixin(MemoryMixin):
|
|
10
|
-
def load(self, addr, size=None, endness=None, condition=None, fallback=None, **kwargs):
|
|
10
|
+
def load(self, addr, size=None, *, endness=None, condition=None, fallback=None, **kwargs):
|
|
11
11
|
tsize = self._translate_size(size, None)
|
|
12
12
|
return super().load(
|
|
13
13
|
self._translate_addr(addr),
|
|
@@ -18,7 +18,7 @@ class SimpleInterfaceMixin(MemoryMixin):
|
|
|
18
18
|
**kwargs,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
-
def store(self, addr, data, size=None, endness=None, condition=None, **kwargs):
|
|
21
|
+
def store(self, addr, data, size=None, *, endness=None, condition=None, **kwargs):
|
|
22
22
|
tsize = self._translate_size(size, data)
|
|
23
23
|
super().store(
|
|
24
24
|
self._translate_addr(addr),
|
|
@@ -5,11 +5,11 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class SimplificationMixin(MemoryMixin):
|
|
8
|
-
def store(self, addr, data, **kwargs):
|
|
8
|
+
def store(self, addr, data, size=None, **kwargs):
|
|
9
9
|
if (self.category == "mem" and options.SIMPLIFY_MEMORY_WRITES in self.state.options) or (
|
|
10
10
|
self.category == "reg" and options.SIMPLIFY_REGISTER_WRITES in self.state.options
|
|
11
11
|
):
|
|
12
12
|
real_data = self.state.solver.simplify(data)
|
|
13
13
|
else:
|
|
14
14
|
real_data = data
|
|
15
|
-
super().store(addr, real_data, **kwargs)
|
|
15
|
+
super().store(addr, real_data, size, **kwargs)
|
|
@@ -96,7 +96,7 @@ class SizeConcretizationMixin(MemoryMixin):
|
|
|
96
96
|
out_size = self.state.solver.max(size)
|
|
97
97
|
return super().load(addr, size=out_size, **kwargs)
|
|
98
98
|
|
|
99
|
-
def store(self, addr, data, size=None, condition=None, **kwargs):
|
|
99
|
+
def store(self, addr, data, size=None, *, condition=None, **kwargs):
|
|
100
100
|
if getattr(size, "op", "BVV") == "BVV":
|
|
101
101
|
super().store(addr, data, size=size, condition=condition, **kwargs)
|
|
102
102
|
return
|
|
@@ -81,7 +81,7 @@ class SlottedMemoryMixin(MemoryMixin):
|
|
|
81
81
|
try:
|
|
82
82
|
d = self.contents[addr]
|
|
83
83
|
except KeyError:
|
|
84
|
-
d = self._default_value(addr, self.width, (*self.variable_key_prefix, addr), **kwargs)
|
|
84
|
+
d = self._default_value(addr, self.width, key=(*self.variable_key_prefix, addr), **kwargs)
|
|
85
85
|
self.contents[addr] = d
|
|
86
86
|
|
|
87
87
|
if offset == 0 and size == self.width:
|
|
@@ -107,7 +107,7 @@ class SlottedMemoryMixin(MemoryMixin):
|
|
|
107
107
|
end = cur.get_bytes(offset + size, self.width - offset - size)
|
|
108
108
|
self.contents[addr] = start.concat(data, end)
|
|
109
109
|
|
|
110
|
-
def load(self, addr, size=None, endness=None, **kwargs):
|
|
110
|
+
def load(self, addr, size=None, *, endness=None, **kwargs):
|
|
111
111
|
accesses = self._resolve_access(addr, size)
|
|
112
112
|
|
|
113
113
|
value = claripy.Concat(*(self._single_load(addr, offset, size) for addr, offset, size in accesses))
|
|
@@ -116,7 +116,7 @@ class SlottedMemoryMixin(MemoryMixin):
|
|
|
116
116
|
|
|
117
117
|
return value
|
|
118
118
|
|
|
119
|
-
def store(self, addr, data, size=None, endness=None, **kwargs):
|
|
119
|
+
def store(self, addr, data, size=None, *, endness=None, **kwargs):
|
|
120
120
|
if endness != self.endness:
|
|
121
121
|
data = data.reversed
|
|
122
122
|
|