angr 9.2.96__py3-none-manylinux2014_x86_64.whl → 9.2.98__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/cfg/cfg_base.py +14 -1
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +10 -6
- angr/analyses/complete_calling_conventions.py +27 -11
- angr/analyses/decompiler/ail_simplifier.py +20 -8
- angr/analyses/decompiler/condition_processor.py +2 -0
- angr/analyses/decompiler/optimization_passes/__init__.py +2 -0
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +380 -0
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +71 -3
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +162 -0
- angr/analyses/decompiler/structured_codegen/__init__.py +1 -1
- angr/analyses/decompiler/structured_codegen/c.py +72 -99
- angr/analyses/decompiler/utils.py +5 -1
- angr/analyses/find_objects_static.py +15 -10
- angr/analyses/forward_analysis/forward_analysis.py +15 -1
- angr/analyses/propagator/engine_ail.py +2 -0
- angr/analyses/propagator/engine_vex.py +15 -0
- angr/analyses/propagator/propagator.py +6 -3
- angr/analyses/reaching_definitions/engine_vex.py +6 -0
- angr/analyses/reaching_definitions/rd_state.py +14 -1
- angr/analyses/reaching_definitions/reaching_definitions.py +19 -2
- angr/analyses/variable_recovery/engine_ail.py +6 -6
- angr/analyses/variable_recovery/engine_vex.py +6 -0
- angr/analyses/variable_recovery/irsb_scanner.py +12 -0
- angr/analyses/variable_recovery/variable_recovery_base.py +4 -1
- angr/engines/light/engine.py +134 -16
- angr/knowledge_plugins/functions/function.py +4 -0
- angr/knowledge_plugins/key_definitions/environment.py +11 -0
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -8
- angr/knowledge_plugins/key_definitions/uses.py +18 -4
- angr/knowledge_plugins/propagations/states.py +22 -3
- angr/knowledge_plugins/types.py +6 -0
- angr/knowledge_plugins/variables/variable_manager.py +31 -5
- angr/simos/simos.py +2 -0
- angr/storage/memory_mixins/__init__.py +3 -0
- angr/storage/memory_mixins/multi_value_merger_mixin.py +22 -11
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +20 -2
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +20 -5
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +82 -44
- angr/storage/memory_mixins/simple_interface_mixin.py +4 -0
- angr/utils/cowdict.py +4 -2
- angr/utils/funcid.py +6 -0
- angr/utils/mp.py +1 -1
- {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/METADATA +6 -6
- {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/RECORD +51 -49
- {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/LICENSE +0 -0
- {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/WHEEL +0 -0
- {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/entry_points.txt +0 -0
- {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/top_level.txt +0 -0
|
@@ -49,11 +49,12 @@ class DefinitionAnnotation(Annotation):
|
|
|
49
49
|
An annotation that attaches a `Definition` to an AST.
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
|
-
__slots__ = ("definition",)
|
|
52
|
+
__slots__ = ("definition", "_hash")
|
|
53
53
|
|
|
54
54
|
def __init__(self, definition):
|
|
55
55
|
super().__init__()
|
|
56
56
|
self.definition = definition
|
|
57
|
+
self._hash = hash((DefinitionAnnotation, self.definition))
|
|
57
58
|
|
|
58
59
|
@property
|
|
59
60
|
def relocatable(self):
|
|
@@ -64,15 +65,11 @@ class DefinitionAnnotation(Annotation):
|
|
|
64
65
|
return False
|
|
65
66
|
|
|
66
67
|
def __hash__(self):
|
|
67
|
-
return
|
|
68
|
+
return self._hash
|
|
68
69
|
|
|
69
70
|
def __eq__(self, other: "object"):
|
|
70
|
-
if
|
|
71
|
-
return
|
|
72
|
-
self.definition == other.definition
|
|
73
|
-
and self.relocatable == other.relocatable
|
|
74
|
-
and self.eliminatable == other.eliminatable
|
|
75
|
-
)
|
|
71
|
+
if type(other) is DefinitionAnnotation:
|
|
72
|
+
return self.definition == other.definition
|
|
76
73
|
else:
|
|
77
74
|
return False
|
|
78
75
|
|
|
@@ -129,6 +126,7 @@ class LiveDefinitions:
|
|
|
129
126
|
memory_uses=None,
|
|
130
127
|
tmp_uses=None,
|
|
131
128
|
other_uses=None,
|
|
129
|
+
element_limit=5,
|
|
132
130
|
):
|
|
133
131
|
self.project: Optional["Project"] = None
|
|
134
132
|
self.arch = arch
|
|
@@ -139,9 +137,11 @@ class LiveDefinitions:
|
|
|
139
137
|
MultiValuedMemory(
|
|
140
138
|
memory_id="reg",
|
|
141
139
|
top_func=self.top,
|
|
140
|
+
is_top_func=self.is_top,
|
|
142
141
|
skip_missing_values_during_merging=False,
|
|
143
142
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
144
143
|
endness=self.arch.register_endness,
|
|
144
|
+
element_limit=element_limit,
|
|
145
145
|
)
|
|
146
146
|
if registers is None
|
|
147
147
|
else registers
|
|
@@ -150,8 +150,10 @@ class LiveDefinitions:
|
|
|
150
150
|
MultiValuedMemory(
|
|
151
151
|
memory_id="mem",
|
|
152
152
|
top_func=self.top,
|
|
153
|
+
is_top_func=self.is_top,
|
|
153
154
|
skip_missing_values_during_merging=False,
|
|
154
155
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
156
|
+
element_limit=element_limit,
|
|
155
157
|
)
|
|
156
158
|
if stack is None
|
|
157
159
|
else stack
|
|
@@ -160,8 +162,10 @@ class LiveDefinitions:
|
|
|
160
162
|
MultiValuedMemory(
|
|
161
163
|
memory_id="mem",
|
|
162
164
|
top_func=self.top,
|
|
165
|
+
is_top_func=self.is_top,
|
|
163
166
|
skip_missing_values_during_merging=False,
|
|
164
167
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
168
|
+
element_limit=element_limit,
|
|
165
169
|
)
|
|
166
170
|
if memory is None
|
|
167
171
|
else memory
|
|
@@ -170,8 +174,10 @@ class LiveDefinitions:
|
|
|
170
174
|
MultiValuedMemory(
|
|
171
175
|
memory_id="mem",
|
|
172
176
|
top_func=self.top,
|
|
177
|
+
is_top_func=self.is_top,
|
|
173
178
|
skip_missing_values_during_merging=False,
|
|
174
179
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
180
|
+
element_limit=element_limit,
|
|
175
181
|
)
|
|
176
182
|
if heap is None
|
|
177
183
|
else heap
|
|
@@ -464,6 +470,33 @@ class LiveDefinitions:
|
|
|
464
470
|
|
|
465
471
|
return state, merge_occurred
|
|
466
472
|
|
|
473
|
+
def compare(self, other: "LiveDefinitions") -> bool:
|
|
474
|
+
r0 = self.registers.compare(other.registers)
|
|
475
|
+
if r0 is False:
|
|
476
|
+
return False
|
|
477
|
+
r1 = self.heap.compare(other.heap)
|
|
478
|
+
if r1 is False:
|
|
479
|
+
return False
|
|
480
|
+
r2 = self.memory.compare(other.memory)
|
|
481
|
+
if r2 is False:
|
|
482
|
+
return False
|
|
483
|
+
r3 = self.stack.compare(other.stack)
|
|
484
|
+
if r3 is False:
|
|
485
|
+
return False
|
|
486
|
+
|
|
487
|
+
r4 = True
|
|
488
|
+
for k in other.others:
|
|
489
|
+
if k in self.others:
|
|
490
|
+
thing = self.others[k].merge(other.others[k])
|
|
491
|
+
if thing != self.others[k]:
|
|
492
|
+
r4 = False
|
|
493
|
+
break
|
|
494
|
+
else:
|
|
495
|
+
r4 = False
|
|
496
|
+
break
|
|
497
|
+
|
|
498
|
+
return r0 and r1 and r2 and r3 and r4
|
|
499
|
+
|
|
467
500
|
def kill_definitions(self, atom: Atom) -> None:
|
|
468
501
|
"""
|
|
469
502
|
Overwrite existing definitions w.r.t 'atom' with a dummy definition instance. A dummy definition will not be
|
|
@@ -21,10 +21,14 @@ class Uses:
|
|
|
21
21
|
uses_by_location: Optional[DefaultChainMapCOW] = None,
|
|
22
22
|
):
|
|
23
23
|
self._uses_by_definition: DefaultChainMapCOW["Definition", Set[Tuple[CodeLocation, Optional[Any]]]] = (
|
|
24
|
-
DefaultChainMapCOW(set, collapse_threshold=25)
|
|
24
|
+
DefaultChainMapCOW(default_factory=set, collapse_threshold=25)
|
|
25
|
+
if uses_by_definition is None
|
|
26
|
+
else uses_by_definition
|
|
25
27
|
)
|
|
26
28
|
self._uses_by_location: DefaultChainMapCOW[CodeLocation, Set[Tuple["Definition", Optional[Any]]]] = (
|
|
27
|
-
DefaultChainMapCOW(set, collapse_threshold=25)
|
|
29
|
+
DefaultChainMapCOW(default_factory=set, collapse_threshold=25)
|
|
30
|
+
if uses_by_location is None
|
|
31
|
+
else uses_by_location
|
|
28
32
|
)
|
|
29
33
|
|
|
30
34
|
def add_use(self, definition: "Definition", codeloc: CodeLocation, expr: Optional[Any] = None):
|
|
@@ -35,7 +39,9 @@ class Uses:
|
|
|
35
39
|
:param codeloc: The code location where the use occurs.
|
|
36
40
|
:param expr: The expression that uses the specified definition at this location.
|
|
37
41
|
"""
|
|
42
|
+
self._uses_by_definition = self._uses_by_definition.clean()
|
|
38
43
|
self._uses_by_definition[definition].add((codeloc, expr))
|
|
44
|
+
self._uses_by_location = self._uses_by_location.clean()
|
|
39
45
|
self._uses_by_location[codeloc].add((definition, expr))
|
|
40
46
|
|
|
41
47
|
def get_uses(self, definition: "Definition") -> Set[CodeLocation]:
|
|
@@ -65,6 +71,7 @@ class Uses:
|
|
|
65
71
|
"""
|
|
66
72
|
if definition in self._uses_by_definition:
|
|
67
73
|
if codeloc in self._uses_by_definition[definition]:
|
|
74
|
+
self._uses_by_definition = self._uses_by_definition.clean()
|
|
68
75
|
if expr is None:
|
|
69
76
|
for codeloc_, expr_ in list(self._uses_by_definition[definition]):
|
|
70
77
|
if codeloc_ == codeloc:
|
|
@@ -73,6 +80,7 @@ class Uses:
|
|
|
73
80
|
self._uses_by_definition[definition].remove((codeloc, expr))
|
|
74
81
|
|
|
75
82
|
if codeloc in self._uses_by_location:
|
|
83
|
+
self._uses_by_location = self._uses_by_location.clean()
|
|
76
84
|
for item in list(self._uses_by_location[codeloc]):
|
|
77
85
|
if item[0] == definition:
|
|
78
86
|
self._uses_by_location[codeloc].remove(item)
|
|
@@ -85,9 +93,11 @@ class Uses:
|
|
|
85
93
|
:return: None
|
|
86
94
|
"""
|
|
87
95
|
if definition in self._uses_by_definition:
|
|
96
|
+
self._uses_by_definition = self._uses_by_definition.clean()
|
|
88
97
|
codeloc_and_ids = self._uses_by_definition[definition]
|
|
89
98
|
del self._uses_by_definition[definition]
|
|
90
99
|
|
|
100
|
+
self._uses_by_location = self._uses_by_location.clean()
|
|
91
101
|
for codeloc, _ in codeloc_and_ids:
|
|
92
102
|
for item in list(self._uses_by_location[codeloc]):
|
|
93
103
|
if item[0] == definition:
|
|
@@ -149,18 +159,22 @@ class Uses:
|
|
|
149
159
|
|
|
150
160
|
for k, v in other._uses_by_definition.items():
|
|
151
161
|
if k not in self._uses_by_definition:
|
|
162
|
+
self._uses_by_definition = self._uses_by_definition.clean()
|
|
152
163
|
self._uses_by_definition[k] = v
|
|
153
164
|
merge_occurred = True
|
|
154
165
|
elif not v.issubset(self._uses_by_definition[k]):
|
|
155
166
|
merge_occurred = True
|
|
156
|
-
self._uses_by_definition
|
|
167
|
+
self._uses_by_definition = self._uses_by_definition.clean()
|
|
168
|
+
self._uses_by_definition[k] = self._uses_by_definition[k] | v
|
|
157
169
|
|
|
158
170
|
for k, v in other._uses_by_location.items():
|
|
159
171
|
if k not in self._uses_by_location:
|
|
172
|
+
self._uses_by_location = self._uses_by_location.clean()
|
|
160
173
|
self._uses_by_location[k] = v
|
|
161
174
|
merge_occurred = True
|
|
162
175
|
elif not v.issubset(self._uses_by_location[k]):
|
|
163
176
|
merge_occurred = True
|
|
164
|
-
self._uses_by_location
|
|
177
|
+
self._uses_by_location = self._uses_by_location.clean()
|
|
178
|
+
self._uses_by_location[k] = self._uses_by_location[k] | v
|
|
165
179
|
|
|
166
180
|
return merge_occurred
|
|
@@ -221,9 +221,10 @@ class PropagatorState:
|
|
|
221
221
|
merge_occurred = True
|
|
222
222
|
else:
|
|
223
223
|
if PropagatorState.is_top(repl) or PropagatorState.is_top(replacements_0[loc][var]):
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
if not PropagatorState.is_top(replacements_0[loc][var]):
|
|
225
|
+
t = PropagatorState.top(_get_repl_size(repl))
|
|
226
|
+
replacements_0[loc][var] = t
|
|
227
|
+
merge_occurred = True
|
|
227
228
|
elif (
|
|
228
229
|
isinstance(replacements_0[loc][var], claripy.ast.Base) or isinstance(repl, claripy.ast.Base)
|
|
229
230
|
) and replacements_0[loc][var] is not repl:
|
|
@@ -316,6 +317,12 @@ class RegisterAnnotation(claripy.Annotation):
|
|
|
316
317
|
def relocatable(self) -> bool:
|
|
317
318
|
return True
|
|
318
319
|
|
|
320
|
+
def __hash__(self):
|
|
321
|
+
return hash((RegisterAnnotation, self.offset, self.size))
|
|
322
|
+
|
|
323
|
+
def __eq__(self, other):
|
|
324
|
+
return type(other) is RegisterAnnotation and self.offset == other.offset and self.size == other.size
|
|
325
|
+
|
|
319
326
|
|
|
320
327
|
class RegisterComparisonAnnotation(claripy.Annotation):
|
|
321
328
|
"""
|
|
@@ -336,6 +343,18 @@ class RegisterComparisonAnnotation(claripy.Annotation):
|
|
|
336
343
|
def relocatable(self) -> bool:
|
|
337
344
|
return True
|
|
338
345
|
|
|
346
|
+
def __hash__(self):
|
|
347
|
+
return hash((RegisterComparisonAnnotation, self.offset, self.size, self.cmp_op, self.value))
|
|
348
|
+
|
|
349
|
+
def __eq__(self, other):
|
|
350
|
+
return (
|
|
351
|
+
type(other) is RegisterAnnotation
|
|
352
|
+
and self.offset == other.offset
|
|
353
|
+
and self.size == other.size
|
|
354
|
+
and self.cmp_op == other.cmp_op
|
|
355
|
+
and self.value == other.value
|
|
356
|
+
)
|
|
357
|
+
|
|
339
358
|
|
|
340
359
|
class PropagatorVEXState(PropagatorState):
|
|
341
360
|
"""
|
angr/knowledge_plugins/types.py
CHANGED
|
@@ -56,6 +56,12 @@ class TypesStore(KnowledgeBasePlugin, UserDict):
|
|
|
56
56
|
yield from super().__iter__()
|
|
57
57
|
yield from iter(ALL_TYPES)
|
|
58
58
|
|
|
59
|
+
def __getstate__(self):
|
|
60
|
+
return self.data # do not pickle self.kb
|
|
61
|
+
|
|
62
|
+
def __setstate__(self, state):
|
|
63
|
+
self.data = state
|
|
64
|
+
|
|
59
65
|
def iter_own(self):
|
|
60
66
|
"""
|
|
61
67
|
Iterate over all the names which are stored in this object - i.e. ``values()`` without ``ALL_TYPES``
|
|
@@ -122,7 +122,32 @@ class VariableManagerInternal(Serializable):
|
|
|
122
122
|
self.__dict__.update(state)
|
|
123
123
|
|
|
124
124
|
def __getstate__(self):
|
|
125
|
-
|
|
125
|
+
attributes = [
|
|
126
|
+
"func_addr",
|
|
127
|
+
"_variables",
|
|
128
|
+
"_global_region",
|
|
129
|
+
"_stack_region",
|
|
130
|
+
"_register_region",
|
|
131
|
+
"_live_variables",
|
|
132
|
+
"_variable_accesses",
|
|
133
|
+
"_insn_to_variable",
|
|
134
|
+
"_stmt_to_variable",
|
|
135
|
+
"_variable_to_stmt",
|
|
136
|
+
"_atom_to_variable",
|
|
137
|
+
"_ident_to_variable",
|
|
138
|
+
"_variable_counters",
|
|
139
|
+
"_unified_variables",
|
|
140
|
+
"_variables_to_unified_variables",
|
|
141
|
+
"_phi_variables",
|
|
142
|
+
"_variables_to_phivars",
|
|
143
|
+
"_phi_variables_by_block",
|
|
144
|
+
"types",
|
|
145
|
+
"variable_to_types",
|
|
146
|
+
"variables_with_manual_types",
|
|
147
|
+
"_variables_without_writes",
|
|
148
|
+
"ret_val_size",
|
|
149
|
+
]
|
|
150
|
+
d = {k: getattr(self, k) for k in attributes}
|
|
126
151
|
d["manager"] = None
|
|
127
152
|
d["types"].kb = None
|
|
128
153
|
return d
|
|
@@ -759,10 +784,11 @@ class VariableManagerInternal(Serializable):
|
|
|
759
784
|
if variable in self._phi_variables:
|
|
760
785
|
# a phi variable is definitely not an input variable
|
|
761
786
|
continue
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
if
|
|
765
|
-
|
|
787
|
+
if variable in self._variable_accesses:
|
|
788
|
+
accesses = self._variable_accesses[variable]
|
|
789
|
+
if has_read_access(accesses):
|
|
790
|
+
if not exclude_specials or not variable.category:
|
|
791
|
+
input_variables.append(variable)
|
|
766
792
|
|
|
767
793
|
return input_variables
|
|
768
794
|
|
angr/simos/simos.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
# pylint:disable=missing-class-docstring
|
|
1
2
|
from typing import Iterable, Tuple, Any, Callable, Optional
|
|
2
3
|
|
|
3
4
|
from . import MemoryMixin
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class MultiValueMergerMixin(MemoryMixin):
|
|
7
|
-
def __init__(
|
|
8
|
+
def __init__(
|
|
9
|
+
self, *args, element_limit=5, annotation_limit=256, top_func=None, is_top_func=None, phi_maker=None, **kwargs
|
|
10
|
+
):
|
|
8
11
|
self._element_limit = element_limit
|
|
9
12
|
self._annotation_limit = annotation_limit
|
|
10
13
|
self._top_func: Callable = top_func
|
|
14
|
+
self._is_top_func: Callable = is_top_func
|
|
11
15
|
self._phi_maker: Optional[Callable] = phi_maker
|
|
12
16
|
|
|
13
17
|
super().__init__(*args, **kwargs)
|
|
@@ -20,18 +24,23 @@ class MultiValueMergerMixin(MemoryMixin):
|
|
|
20
24
|
return {phi_var}
|
|
21
25
|
|
|
22
26
|
# try to merge it in the traditional way
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# python implicitly calls __eq__ to determine if the two objects are actually the same
|
|
27
|
-
# and that just results in a new AST for a BV. Python then tries to convert that AST to a bool
|
|
28
|
-
# which fails with the safeguard in claripy.ast.bool.Bool.__bool__.
|
|
29
|
-
stripped_values_set = {v._apply_to_annotations(lambda alist: None).cache_key for v in values_set}
|
|
30
|
-
if len(stripped_values_set) > 1:
|
|
27
|
+
has_top = any(self._is_top_func(v) for v in values_set)
|
|
28
|
+
if has_top or len(values_set) > self._element_limit:
|
|
29
|
+
if has_top:
|
|
31
30
|
ret_val = self._top_func(merged_size * self.state.arch.byte_width)
|
|
32
31
|
else:
|
|
33
|
-
#
|
|
34
|
-
|
|
32
|
+
# strip annotations from each value and see how many raw values there are in total
|
|
33
|
+
# We have to use cache_key to determine uniqueness here, because if __hash__ collides,
|
|
34
|
+
# python implicitly calls __eq__ to determine if the two objects are actually the same
|
|
35
|
+
# and that just results in a new AST for a BV. Python then tries to convert that AST to a bool
|
|
36
|
+
# which fails with the safeguard in claripy.ast.bool.Bool.__bool__.
|
|
37
|
+
stripped_values_set = {v._apply_to_annotations(lambda alist: None).cache_key for v in values_set}
|
|
38
|
+
if len(stripped_values_set) > 1:
|
|
39
|
+
ret_val = self._top_func(merged_size * self.state.arch.byte_width)
|
|
40
|
+
else:
|
|
41
|
+
# Get the AST back from the cache_key
|
|
42
|
+
ret_val = next(iter(stripped_values_set)).ast
|
|
43
|
+
|
|
35
44
|
# migrate annotations
|
|
36
45
|
annotations = []
|
|
37
46
|
annotations_set = set()
|
|
@@ -41,6 +50,7 @@ class MultiValueMergerMixin(MemoryMixin):
|
|
|
41
50
|
annotations.append(anno)
|
|
42
51
|
annotations_set.add(anno)
|
|
43
52
|
if annotations:
|
|
53
|
+
annotations = sorted(annotations, key=str)
|
|
44
54
|
ret_val = ret_val.annotate(*annotations[: self._annotation_limit])
|
|
45
55
|
merged_val = {ret_val}
|
|
46
56
|
else:
|
|
@@ -52,5 +62,6 @@ class MultiValueMergerMixin(MemoryMixin):
|
|
|
52
62
|
copied._element_limit = self._element_limit
|
|
53
63
|
copied._annotation_limit = self._annotation_limit
|
|
54
64
|
copied._top_func = self._top_func
|
|
65
|
+
copied._is_top_func = self._is_top_func
|
|
55
66
|
copied._phi_maker = self._phi_maker
|
|
56
67
|
return copied
|
|
@@ -294,6 +294,24 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
294
294
|
|
|
295
295
|
return bool(merged_bytes)
|
|
296
296
|
|
|
297
|
+
def compare(self, other: "PagedMemoryMixin") -> bool:
|
|
298
|
+
changed_pages_and_offsets: Dict[int, Optional[Set[int]]] = dict(self.changed_pages(other))
|
|
299
|
+
|
|
300
|
+
for page_no in sorted(changed_pages_and_offsets):
|
|
301
|
+
page = self._get_page(page_no, False)
|
|
302
|
+
page_addr = page_no * self.page_size
|
|
303
|
+
if page_no in other._pages:
|
|
304
|
+
r = page.compare(
|
|
305
|
+
other._pages[page_no],
|
|
306
|
+
page_addr=page_addr,
|
|
307
|
+
memory=self,
|
|
308
|
+
changed_offsets=changed_pages_and_offsets[page_no],
|
|
309
|
+
)
|
|
310
|
+
if r is False:
|
|
311
|
+
return False
|
|
312
|
+
|
|
313
|
+
return True
|
|
314
|
+
|
|
297
315
|
def permissions(self, addr, permissions=None, **kwargs):
|
|
298
316
|
if type(addr) is not int:
|
|
299
317
|
raise TypeError("addr must be an int in paged memory")
|
|
@@ -643,10 +661,10 @@ class LabeledPagesMixin(PagedMemoryMixin):
|
|
|
643
661
|
if endness is None:
|
|
644
662
|
endness = self.endness
|
|
645
663
|
|
|
646
|
-
if
|
|
664
|
+
if not isinstance(size, int):
|
|
647
665
|
raise TypeError("Need size to be resolved to an int by this point")
|
|
648
666
|
|
|
649
|
-
if
|
|
667
|
+
if not isinstance(addr, int):
|
|
650
668
|
raise TypeError("Need addr to be resolved to an int by this point")
|
|
651
669
|
|
|
652
670
|
pageno, pageoff = self._divide_addr(addr)
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import logging
|
|
3
3
|
from typing import Optional, List, Set, Tuple
|
|
4
4
|
|
|
5
|
+
import claripy
|
|
6
|
+
|
|
5
7
|
from angr.utils.dynamic_dictlist import DynamicDictList
|
|
6
8
|
from angr.storage.memory_object import SimMemoryObject, SimLabeledMemoryObject
|
|
7
9
|
from . import PageBase
|
|
@@ -192,9 +194,14 @@ class ListPage(MemoryObjectMixin, PageBase):
|
|
|
192
194
|
merged_offsets.add(b)
|
|
193
195
|
|
|
194
196
|
else:
|
|
195
|
-
# get the size that we can merge easily. This is the minimum of
|
|
196
|
-
#
|
|
197
|
-
min_size =
|
|
197
|
+
# get the size that we can merge easily. This is the minimum of the size of all memory objects and
|
|
198
|
+
# unallocated spaces.
|
|
199
|
+
min_size = None
|
|
200
|
+
mask = (1 << memory.state.arch.bits) - 1
|
|
201
|
+
for mo, _ in memory_objects:
|
|
202
|
+
mo_size = mo.length - ((b + page_addr - mo.base) & mask)
|
|
203
|
+
if min_size is None or mo_size < min_size:
|
|
204
|
+
min_size = mo_size
|
|
198
205
|
for um, _ in unconstrained_in:
|
|
199
206
|
for i in range(0, min_size):
|
|
200
207
|
if um._contains(b + i, page_addr):
|
|
@@ -263,15 +270,23 @@ class ListPage(MemoryObjectMixin, PageBase):
|
|
|
263
270
|
differences.add(c)
|
|
264
271
|
else:
|
|
265
272
|
if self.content[c] is None:
|
|
273
|
+
if self.sinkhole is None:
|
|
274
|
+
v = claripy.BVV(0, 8)
|
|
275
|
+
else:
|
|
276
|
+
v = (self.sinkhole.bytes_at(page_addr + c, 1),)
|
|
266
277
|
self.content[c] = SimMemoryObject(
|
|
267
|
-
|
|
278
|
+
v,
|
|
268
279
|
page_addr + c,
|
|
269
280
|
byte_width=byte_width,
|
|
270
281
|
endness="Iend_BE",
|
|
271
282
|
)
|
|
272
283
|
if other.content[c] is None:
|
|
284
|
+
if other.sinkhole is None:
|
|
285
|
+
v = claripy.BVV(0, 8)
|
|
286
|
+
else:
|
|
287
|
+
v = (other.sinkhole.bytes_at(page_addr + c, 1),)
|
|
273
288
|
other.content[c] = SimMemoryObject(
|
|
274
|
-
|
|
289
|
+
v,
|
|
275
290
|
page_addr + c,
|
|
276
291
|
byte_width=byte_width,
|
|
277
292
|
endness="Iend_BE",
|