angr 9.2.123__py3-none-manylinux2014_x86_64.whl → 9.2.124__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/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/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 +83 -82
- {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
|
@@ -13,7 +13,7 @@ l = logging.getLogger(__name__)
|
|
|
13
13
|
|
|
14
14
|
class DefaultFillerMixin(MemoryMixin):
|
|
15
15
|
def _default_value(
|
|
16
|
-
self, addr, size, name=None, inspect=True, events=True, key=None, fill_missing: bool = True, **kwargs
|
|
16
|
+
self, addr, size, *, name=None, inspect=True, events=True, key=None, fill_missing: bool = True, **kwargs
|
|
17
17
|
):
|
|
18
18
|
if self.state.project and self.state.project.concrete_target:
|
|
19
19
|
mem = self.state.project.concrete_target.read_memory(addr, size)
|
|
@@ -115,7 +115,7 @@ class SpecialFillerMixin(MemoryMixin):
|
|
|
115
115
|
super().__init__(**kwargs)
|
|
116
116
|
self._special_memory_filler = special_memory_filler
|
|
117
117
|
|
|
118
|
-
def _default_value(self, addr, size, name=None, **kwargs):
|
|
118
|
+
def _default_value(self, addr, size, *, name=None, **kwargs):
|
|
119
119
|
if (
|
|
120
120
|
options.SPECIAL_MEMORY_FILL in self.state.options
|
|
121
121
|
and self.state._special_memory_filler is not None
|
|
@@ -135,7 +135,7 @@ class ExplicitFillerMixin(MemoryMixin):
|
|
|
135
135
|
super().__init__(**kwargs)
|
|
136
136
|
self._uninitialized_read_handler = uninitialized_read_handler
|
|
137
137
|
|
|
138
|
-
def _default_value(self, addr, size, inspect=True, events=True, **kwargs):
|
|
138
|
+
def _default_value(self, addr, size, *, inspect=True, events=True, **kwargs):
|
|
139
139
|
if self._uninitialized_read_handler is not None:
|
|
140
140
|
return self._uninitialized_read_handler(addr, size, inspect=inspect, events=events)
|
|
141
141
|
return super()._default_value(addr, size, inspect=inspect, events=events, **kwargs)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Iterable
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Generic, TypeVar
|
|
5
|
+
from typing_extensions import Self
|
|
5
6
|
|
|
6
7
|
import claripy
|
|
7
8
|
|
|
@@ -9,33 +10,44 @@ from angr.errors import SimMemoryError
|
|
|
9
10
|
from angr.state_plugins.plugin import SimStatePlugin
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
InData = TypeVar("InData")
|
|
14
|
+
OutData = TypeVar("OutData")
|
|
15
|
+
Addr = TypeVar("Addr")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MemoryMixin(Generic[InData, OutData, Addr], SimStatePlugin):
|
|
13
19
|
"""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
memory
|
|
20
|
+
MemoryMixin is the base class for the memory model in angr. It provides a
|
|
21
|
+
set of methods that should be implemented by memory models. This is done
|
|
22
|
+
using mixins, where each mixin handles some specific feature of the memory
|
|
23
|
+
model, only overriding methods that it needs to implement its function. The
|
|
24
|
+
memory model class itself then combines a set of mixins using inheritence to
|
|
25
|
+
form the final memory model class.
|
|
17
26
|
"""
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
# pylint: disable=no-self-use,unused-argument
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
SUPPORTS_CONCRETE_LOAD: bool = False
|
|
31
|
+
|
|
32
|
+
def __init__(self, memory_id: str | None = None, endness: str = "Iend_BE"):
|
|
22
33
|
super().__init__()
|
|
23
34
|
self.id = memory_id
|
|
24
35
|
self.endness = endness
|
|
25
36
|
|
|
26
|
-
def copy(self, memo)
|
|
37
|
+
def copy(self, memo) -> Self:
|
|
27
38
|
o = type(self).__new__(type(self))
|
|
28
39
|
o.id = self.id
|
|
29
40
|
o.endness = self.endness
|
|
30
41
|
return o
|
|
31
42
|
|
|
32
43
|
@property
|
|
33
|
-
def category(self):
|
|
44
|
+
def category(self) -> str:
|
|
34
45
|
"""
|
|
35
46
|
Return the category of this SimMemory instance. It can be one of the three following categories: reg, mem,
|
|
36
47
|
or file.
|
|
37
48
|
"""
|
|
38
49
|
|
|
50
|
+
assert isinstance(self.id, str)
|
|
39
51
|
if self.id in ("reg", "mem"):
|
|
40
52
|
return self.id
|
|
41
53
|
|
|
@@ -48,46 +60,46 @@ class MemoryMixin(SimStatePlugin):
|
|
|
48
60
|
raise SimMemoryError(f'Unknown SimMemory category for memory_id "{self.id}"')
|
|
49
61
|
|
|
50
62
|
@property
|
|
51
|
-
def variable_key_prefix(self):
|
|
63
|
+
def variable_key_prefix(self) -> tuple[Any, ...]:
|
|
52
64
|
s = self.category
|
|
53
65
|
if s == "file":
|
|
54
66
|
return (s, self.id)
|
|
55
67
|
return (s,)
|
|
56
68
|
|
|
57
|
-
def find(
|
|
58
|
-
|
|
69
|
+
def find(
|
|
70
|
+
self, addr: Addr, data: InData, max_search: int, **kwargs
|
|
71
|
+
) -> tuple[Addr, list[claripy.ast.Bool], list[int]]: ...
|
|
59
72
|
|
|
60
|
-
def _add_constraints(self, c, add_constraints=True, condition=None, **kwargs):
|
|
73
|
+
def _add_constraints(self, c, *, add_constraints=True, condition=None, **kwargs):
|
|
61
74
|
if add_constraints:
|
|
62
75
|
to_add = c & condition | ~condition if condition is not None else c
|
|
63
76
|
self.state.add_constraints(to_add)
|
|
64
77
|
|
|
65
|
-
def load(self, addr, size=None, **kwargs):
|
|
66
|
-
pass
|
|
78
|
+
def load(self, addr: Addr, size: InData | None = None, **kwargs) -> OutData: ...
|
|
67
79
|
|
|
68
|
-
def store(self, addr, data, **kwargs):
|
|
69
|
-
pass
|
|
80
|
+
def store(self, addr: Addr, data: InData, size: InData | None = None, **kwargs) -> None: ...
|
|
70
81
|
|
|
71
|
-
def merge(
|
|
72
|
-
|
|
82
|
+
def merge(
|
|
83
|
+
self, others: list[Self], merge_conditions: list[claripy.ast.Bool], common_ancestor: Self | None = None
|
|
84
|
+
) -> bool: ...
|
|
73
85
|
|
|
74
|
-
def compare(self, other) -> bool:
|
|
75
|
-
pass
|
|
86
|
+
def compare(self, other: Self) -> bool: ...
|
|
76
87
|
|
|
77
|
-
def widen(self, others):
|
|
78
|
-
pass
|
|
88
|
+
def widen(self, others: list[Self]) -> bool: ...
|
|
79
89
|
|
|
80
|
-
def permissions(self, addr, permissions=None, **kwargs):
|
|
81
|
-
pass
|
|
90
|
+
def permissions(self, addr: Addr, permissions: int | claripy.ast.BV | None = None, **kwargs) -> claripy.ast.BV: ...
|
|
82
91
|
|
|
83
|
-
def map_region(
|
|
92
|
+
def map_region(
|
|
93
|
+
self, addr: Addr, length: int, permissions: int | claripy.ast.BV, *, init_zero: bool = False, **kwargs
|
|
94
|
+
):
|
|
84
95
|
pass
|
|
85
96
|
|
|
86
|
-
def unmap_region(self, addr, length, **kwargs):
|
|
97
|
+
def unmap_region(self, addr: Addr, length: int, **kwargs):
|
|
87
98
|
pass
|
|
88
99
|
|
|
89
100
|
# Optional interface:
|
|
90
|
-
|
|
101
|
+
# TODO type this correctly. maybe split the bitmap version into another function?
|
|
102
|
+
def concrete_load(self, addr, size, writing=False, **kwargs) -> Any:
|
|
91
103
|
"""
|
|
92
104
|
Set SUPPORTS_CONCRETE_LOAD to True and implement concrete_load if reading concrete bytes is faster in this
|
|
93
105
|
memory model.
|
|
@@ -99,7 +111,7 @@ class MemoryMixin(SimStatePlugin):
|
|
|
99
111
|
"""
|
|
100
112
|
raise NotImplementedError
|
|
101
113
|
|
|
102
|
-
def erase(self, addr, size=None, **kwargs) -> None:
|
|
114
|
+
def erase(self, addr: Addr, size: int | None = None, **kwargs) -> None:
|
|
103
115
|
"""
|
|
104
116
|
Set [addr:addr+size) to uninitialized. In many cases this will be faster than overwriting those locations with
|
|
105
117
|
new values. This is commonly used during static data flow analysis.
|
|
@@ -110,9 +122,7 @@ class MemoryMixin(SimStatePlugin):
|
|
|
110
122
|
"""
|
|
111
123
|
raise NotImplementedError
|
|
112
124
|
|
|
113
|
-
def _default_value(
|
|
114
|
-
self, addr, size, name=None, inspect=True, events=True, key=None, **kwargs
|
|
115
|
-
):
|
|
125
|
+
def _default_value(self, addr, size, *, name=None, inspect=True, events=True, key=None, **kwargs) -> OutData:
|
|
116
126
|
"""
|
|
117
127
|
Override this method to provide default values for a variety of edge cases and base cases.
|
|
118
128
|
|
|
@@ -123,8 +133,9 @@ class MemoryMixin(SimStatePlugin):
|
|
|
123
133
|
|
|
124
134
|
The ``inspect``, ``events``, and ``key`` parameters are for ``state.solver.Unconstrained``, if it is used.
|
|
125
135
|
"""
|
|
136
|
+
raise NotImplementedError
|
|
126
137
|
|
|
127
|
-
def _merge_values(self, values: Iterable[tuple[Any, Any]], merged_size: int, **kwargs) ->
|
|
138
|
+
def _merge_values(self, values: Iterable[tuple[Any, Any]], merged_size: int, **kwargs) -> OutData | None:
|
|
128
139
|
"""
|
|
129
140
|
Override this method to provide value merging support.
|
|
130
141
|
|
|
@@ -149,7 +160,7 @@ class MemoryMixin(SimStatePlugin):
|
|
|
149
160
|
def _replace_all(self, addrs: Iterable[int], old: claripy.ast.BV, new: claripy.ast.BV):
|
|
150
161
|
raise NotImplementedError
|
|
151
162
|
|
|
152
|
-
def copy_contents(self, dst, src, size, condition=None, **kwargs):
|
|
163
|
+
def copy_contents(self, dst: Addr, src: Addr, size: InData, condition: claripy.ast.Bool | None = None, **kwargs):
|
|
153
164
|
"""
|
|
154
165
|
Override this method to provide faster copying of large chunks of data.
|
|
155
166
|
|
|
@@ -7,8 +7,6 @@ import logging
|
|
|
7
7
|
import claripy
|
|
8
8
|
import cle
|
|
9
9
|
|
|
10
|
-
from .paged_memory_mixin import PagedMemoryMixin
|
|
11
|
-
|
|
12
10
|
l = logging.getLogger(__name__)
|
|
13
11
|
|
|
14
12
|
BackerType = Union[bytes, bytearray, list[int]]
|
|
@@ -29,6 +27,9 @@ class NotMemoryview:
|
|
|
29
27
|
memoryview(self.obj)[self.offset : self.offset + self.size][k] = v
|
|
30
28
|
|
|
31
29
|
|
|
30
|
+
from .paged_memory_mixin import PagedMemoryMixin
|
|
31
|
+
|
|
32
|
+
|
|
32
33
|
class ClemoryBackerMixin(PagedMemoryMixin):
|
|
33
34
|
def __init__(self, cle_memory_backer: None | cle.Loader | cle.Clemory = None, **kwargs):
|
|
34
35
|
super().__init__(**kwargs)
|
|
@@ -49,9 +50,9 @@ class ClemoryBackerMixin(PagedMemoryMixin):
|
|
|
49
50
|
o._cle_loader = self._cle_loader
|
|
50
51
|
return o
|
|
51
52
|
|
|
52
|
-
def _initialize_page(self, pageno, force_default=False, **kwargs):
|
|
53
|
+
def _initialize_page(self, pageno, permissions=None, *, force_default=False, **kwargs):
|
|
53
54
|
if self._clemory_backer is None or force_default:
|
|
54
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
55
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
55
56
|
|
|
56
57
|
addr = pageno * self.page_size
|
|
57
58
|
|
|
@@ -59,10 +60,10 @@ class ClemoryBackerMixin(PagedMemoryMixin):
|
|
|
59
60
|
backer_iter: BackerIterType = self._clemory_backer.backers(addr)
|
|
60
61
|
backer_start, backer = next(backer_iter)
|
|
61
62
|
except StopIteration:
|
|
62
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
63
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
63
64
|
|
|
64
65
|
if backer_start >= addr + self.page_size:
|
|
65
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
66
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
66
67
|
|
|
67
68
|
# Load data from backere
|
|
68
69
|
data = self._data_from_backer(addr, backer, backer_start, backer_iter)
|
|
@@ -184,9 +185,9 @@ class ClemoryBackerMixin(PagedMemoryMixin):
|
|
|
184
185
|
|
|
185
186
|
|
|
186
187
|
class ConcreteBackerMixin(ClemoryBackerMixin):
|
|
187
|
-
def _initialize_page(self, pageno, force_default=False, **kwargs):
|
|
188
|
+
def _initialize_page(self, pageno, permissions=None, *, force_default=False, **kwargs):
|
|
188
189
|
if self._clemory_backer is None or force_default:
|
|
189
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
190
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
190
191
|
|
|
191
192
|
addr = pageno * self.page_size
|
|
192
193
|
|
|
@@ -194,10 +195,10 @@ class ConcreteBackerMixin(ClemoryBackerMixin):
|
|
|
194
195
|
backer_iter = self._clemory_backer.backers(addr)
|
|
195
196
|
backer_start, backer = next(backer_iter)
|
|
196
197
|
except StopIteration:
|
|
197
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
198
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
198
199
|
|
|
199
200
|
if backer_start >= addr + self.page_size:
|
|
200
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
201
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
201
202
|
|
|
202
203
|
if self.state.project.concrete_target:
|
|
203
204
|
l.debug("Fetching data from concrete target")
|
|
@@ -207,7 +208,7 @@ class ConcreteBackerMixin(ClemoryBackerMixin):
|
|
|
207
208
|
)
|
|
208
209
|
else:
|
|
209
210
|
# the concrete backer only is here to support concrete loading, defer back to the CleMemoryBacker
|
|
210
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
211
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
211
212
|
|
|
212
213
|
permissions = self._cle_permissions_lookup(addr)
|
|
213
214
|
|
|
@@ -237,11 +238,11 @@ class DictBackerMixin(PagedMemoryMixin):
|
|
|
237
238
|
o._dict_memory_backer = self._dict_memory_backer
|
|
238
239
|
return o
|
|
239
240
|
|
|
240
|
-
def _initialize_page(self, pageno: int, force_default=False, **kwargs):
|
|
241
|
+
def _initialize_page(self, pageno: int, permissions=None, *, force_default=False, **kwargs):
|
|
241
242
|
page_addr = pageno * self.page_size
|
|
242
243
|
|
|
243
244
|
if self._dict_memory_backer is None or force_default:
|
|
244
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
245
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
245
246
|
|
|
246
247
|
new_page = None
|
|
247
248
|
|
|
@@ -261,6 +262,6 @@ class DictBackerMixin(PagedMemoryMixin):
|
|
|
261
262
|
)
|
|
262
263
|
|
|
263
264
|
if new_page is None:
|
|
264
|
-
return super()._initialize_page(pageno, **kwargs)
|
|
265
|
+
return super()._initialize_page(pageno, permissions=permissions, **kwargs)
|
|
265
266
|
|
|
266
267
|
return new_page
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import cffi
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any, Generic, Literal, overload
|
|
4
4
|
from collections.abc import Iterable
|
|
5
5
|
import logging
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
|
|
8
8
|
import claripy
|
|
9
9
|
|
|
10
|
+
from angr.state_plugins.sim_action_object import SimActionObject
|
|
10
11
|
from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
11
12
|
from angr.storage.memory_mixins.paged_memory.pages import PageType, ListPage, UltraPage, MVListPage
|
|
12
13
|
from angr.errors import SimMemoryError
|
|
@@ -17,14 +18,17 @@ ffi = cffi.FFI()
|
|
|
17
18
|
l = logging.getLogger(__name__)
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
class PagedMemoryMixin(
|
|
21
|
+
class PagedMemoryMixin(
|
|
22
|
+
Generic[PageType],
|
|
23
|
+
MemoryMixin[int | claripy.ast.BV | SimActionObject, claripy.ast.BV, int | claripy.ast.BV | SimActionObject],
|
|
24
|
+
):
|
|
21
25
|
"""
|
|
22
26
|
A bottom-level storage mechanism. Dispatches reads to individual pages, the type of which is the PAGE_TYPE class
|
|
23
27
|
variable.
|
|
24
28
|
"""
|
|
25
29
|
|
|
26
30
|
SUPPORTS_CONCRETE_LOAD = True
|
|
27
|
-
PAGE_TYPE: type[PageType]
|
|
31
|
+
PAGE_TYPE: type[PageType] # must be provided in subclass
|
|
28
32
|
|
|
29
33
|
def __init__(self, page_size=0x1000, default_permissions=3, permissions_map=None, page_kwargs=None, **kwargs):
|
|
30
34
|
super().__init__(**kwargs)
|
|
@@ -84,7 +88,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
84
88
|
kwargs["allow_default"] = True
|
|
85
89
|
return PagedMemoryMixin._initialize_page(self, pageno, permissions=permissions, **kwargs)
|
|
86
90
|
|
|
87
|
-
def _initialize_page(self, pageno: int, permissions=None, allow_default=True, **kwargs) -> PageType:
|
|
91
|
+
def _initialize_page(self, pageno: int, permissions=None, *, allow_default=True, **kwargs) -> PageType:
|
|
88
92
|
if not allow_default:
|
|
89
93
|
raise SimMemoryError("I have been instructed not to create a default page")
|
|
90
94
|
|
|
@@ -110,7 +114,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
110
114
|
def _divide_addr(self, addr: int) -> tuple[int, int]:
|
|
111
115
|
return divmod(addr, self.page_size)
|
|
112
116
|
|
|
113
|
-
def load(self, addr: int, size: int | None = None, endness=None, **kwargs):
|
|
117
|
+
def load(self, addr: int, size: int | None = None, *, endness=None, **kwargs):
|
|
114
118
|
if endness is None:
|
|
115
119
|
endness = self.endness
|
|
116
120
|
|
|
@@ -164,7 +168,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
164
168
|
l.debug("%s.load(%#x, %d, %s) = %s", self.id, addr, size, endness, out)
|
|
165
169
|
return out
|
|
166
170
|
|
|
167
|
-
def store(self, addr: int, data, size: int | None = None, endness=None, **kwargs):
|
|
171
|
+
def store(self, addr: int, data, size: int | None = None, *, endness=None, **kwargs):
|
|
168
172
|
if endness is None:
|
|
169
173
|
endness = self.endness
|
|
170
174
|
|
|
@@ -253,7 +257,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
253
257
|
pageno = (pageno + 1) % max_pageno
|
|
254
258
|
pageoff = 0
|
|
255
259
|
|
|
256
|
-
def merge(self, others
|
|
260
|
+
def merge(self, others, merge_conditions, common_ancestor=None):
|
|
257
261
|
changed_pages_and_offsets: dict[int, set[int] | None] = {}
|
|
258
262
|
for o in others:
|
|
259
263
|
for changed_page, changed_offsets in self.changed_pages(o).items():
|
|
@@ -315,7 +319,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
315
319
|
return True
|
|
316
320
|
|
|
317
321
|
def permissions(self, addr, permissions=None, **kwargs):
|
|
318
|
-
if
|
|
322
|
+
if not isinstance(addr, int):
|
|
319
323
|
raise TypeError("addr must be an int in paged memory")
|
|
320
324
|
pageno, _ = self._divide_addr(addr)
|
|
321
325
|
try:
|
|
@@ -323,15 +327,15 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
323
327
|
except SimMemoryError as e:
|
|
324
328
|
raise SimMemoryError(f"{addr:#x} is not mapped") from e
|
|
325
329
|
|
|
326
|
-
if
|
|
330
|
+
if isinstance(permissions, int):
|
|
327
331
|
permissions = claripy.BVV(permissions, 3)
|
|
328
332
|
|
|
329
|
-
result = page.
|
|
333
|
+
result = page.permission_bits
|
|
330
334
|
if permissions is not None:
|
|
331
|
-
page.
|
|
335
|
+
page.permission_bits = permissions
|
|
332
336
|
return result
|
|
333
337
|
|
|
334
|
-
def map_region(self, addr, length, permissions, init_zero=False, **kwargs):
|
|
338
|
+
def map_region(self, addr, length, permissions, *, init_zero=False, **kwargs):
|
|
335
339
|
if type(addr) is not int:
|
|
336
340
|
raise TypeError("addr must be an int in paged memory")
|
|
337
341
|
pageno, pageoff = self._divide_addr(addr)
|
|
@@ -399,6 +403,11 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
399
403
|
else:
|
|
400
404
|
return True
|
|
401
405
|
|
|
406
|
+
@overload
|
|
407
|
+
def _load_to_memoryview(self, addr, size, with_bitmap: Literal[True]) -> tuple[memoryview, memoryview]: ...
|
|
408
|
+
@overload
|
|
409
|
+
def _load_to_memoryview(self, addr, size, with_bitmap: Literal[False]) -> memoryview: ...
|
|
410
|
+
|
|
402
411
|
def _load_to_memoryview(self, addr, size, with_bitmap):
|
|
403
412
|
result = self.load(addr, size, endness="Iend_BE")
|
|
404
413
|
if result.op == "BVV":
|
|
@@ -469,7 +478,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
469
478
|
return memoryview(bytes(size)), memoryview(b"\x01" * size)
|
|
470
479
|
return memoryview(b"")
|
|
471
480
|
|
|
472
|
-
def concrete_load(self, addr, size, writing=False, with_bitmap=False, **kwargs):
|
|
481
|
+
def concrete_load(self, addr, size, writing=False, *, with_bitmap: bool = False, **kwargs):
|
|
473
482
|
pageno, offset = self._divide_addr(addr)
|
|
474
483
|
subsize = min(size, self.page_size - offset)
|
|
475
484
|
try:
|
|
@@ -481,9 +490,11 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
481
490
|
|
|
482
491
|
if not page.SUPPORTS_CONCRETE_LOAD:
|
|
483
492
|
# the page does not support concrete_load
|
|
484
|
-
|
|
493
|
+
if with_bitmap:
|
|
494
|
+
return self._load_to_memoryview(addr, size, True)
|
|
495
|
+
return self._load_to_memoryview(addr, size, False)
|
|
485
496
|
|
|
486
|
-
data, bitmap = page.concrete_load(offset, subsize, **kwargs)
|
|
497
|
+
data, bitmap = page.concrete_load(offset, subsize, with_bitmap=True, **kwargs)
|
|
487
498
|
if with_bitmap:
|
|
488
499
|
return data, bitmap
|
|
489
500
|
|
|
@@ -513,7 +524,7 @@ class PagedMemoryMixin(MemoryMixin):
|
|
|
513
524
|
except (SimMemoryError, AttributeError):
|
|
514
525
|
break
|
|
515
526
|
else:
|
|
516
|
-
newdata, bitmap = concrete_load(offset, subsize, **kwargs)
|
|
527
|
+
newdata, bitmap = concrete_load(offset, subsize, with_bitmap=True, **kwargs)
|
|
517
528
|
for i, byte in enumerate(bitmap):
|
|
518
529
|
if byte != 0:
|
|
519
530
|
break
|
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from typing import Generic, TypeVar
|
|
4
|
+
from collections.abc import Generator
|
|
3
5
|
|
|
4
6
|
import claripy
|
|
5
7
|
|
|
6
8
|
from angr.storage.memory_object import SimMemoryObject, SimLabeledMemoryObject
|
|
7
9
|
from .multi_values import MultiValues
|
|
8
10
|
|
|
11
|
+
T = TypeVar("T")
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
class CooperationBase(Generic[T]):
|
|
11
15
|
"""
|
|
12
16
|
Any given subclass of this class which is not a subclass of MemoryMixin should have the property that any subclass
|
|
13
17
|
it which *is* a subclass of MemoryMixin should all work with the same datatypes
|
|
14
18
|
"""
|
|
15
19
|
|
|
16
20
|
@classmethod
|
|
17
|
-
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def _compose_objects(cls, objects: list[list[tuple[int, T]]], size: str, endness: str, **kwargs) -> T:
|
|
18
23
|
"""
|
|
19
24
|
Provide this a list of the result of several load calls, and it will compose them into a single result.
|
|
20
25
|
"""
|
|
21
26
|
|
|
22
27
|
@classmethod
|
|
23
|
-
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def _decompose_objects(cls, addr, data, endness, **kwargs) -> Generator[tuple[T, int, int], int]:
|
|
24
30
|
"""
|
|
25
31
|
A bidirectional generator. No idea if this is overengineered. Usage is that you send it a size to use
|
|
26
32
|
and it yields a tuple of three elements: the object to store for the next n bytes, the base address of the
|
|
@@ -28,13 +34,14 @@ class CooperationBase:
|
|
|
28
34
|
"""
|
|
29
35
|
|
|
30
36
|
@classmethod
|
|
31
|
-
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def _zero_objects(cls, addr, size, **kwargs) -> Generator[tuple[T, int, int], int]:
|
|
32
39
|
"""
|
|
33
40
|
Like decompose objects, but with a size to zero-fill instead of explicit data
|
|
34
41
|
"""
|
|
35
42
|
|
|
36
43
|
@classmethod
|
|
37
|
-
def _force_store_cooperation(cls, addr, data, size, endness, **kwargs):
|
|
44
|
+
def _force_store_cooperation(cls, addr: int, data: T, size: int, endness: str, **kwargs):
|
|
38
45
|
if data is not None:
|
|
39
46
|
sub_gen = cls._decompose_objects(addr, data, endness, **kwargs)
|
|
40
47
|
else:
|
|
@@ -50,7 +57,7 @@ class CooperationBase:
|
|
|
50
57
|
return cls._compose_objects([results], size, endness, **kwargs)
|
|
51
58
|
|
|
52
59
|
|
|
53
|
-
class MemoryObjectMixin(CooperationBase):
|
|
60
|
+
class MemoryObjectMixin(CooperationBase[SimMemoryObject]):
|
|
54
61
|
"""
|
|
55
62
|
Uses SimMemoryObjects in region storage.
|
|
56
63
|
With this, load will return a list of tuple (address, MO) and store will take a MO.
|
|
@@ -123,11 +130,12 @@ class MemoryObjectMixin(CooperationBase):
|
|
|
123
130
|
else:
|
|
124
131
|
memory_object = SimLabeledMemoryObject(data, cur_addr, endness, byte_width=byte_width, label=label)
|
|
125
132
|
|
|
133
|
+
next_elem_size_left = 0
|
|
134
|
+
next_elem_index = 0
|
|
126
135
|
if data.symbolic and data.op == "Concat":
|
|
127
136
|
next_elem_size_left = data.args[0].size() // 8
|
|
128
|
-
next_elem_index = 0
|
|
129
137
|
|
|
130
|
-
size = yield
|
|
138
|
+
size = yield NotImplemented, NotImplemented, NotImplemented
|
|
131
139
|
max_size = kwargs.get("max_size", size)
|
|
132
140
|
while True:
|
|
133
141
|
if data.symbolic and data.op == "Concat" and data.size() > max_size:
|
|
@@ -235,6 +243,7 @@ class MemoryObjectSetMixin(CooperationBase):
|
|
|
235
243
|
mv.add_value(start_offset, prev_value)
|
|
236
244
|
prev_value = ...
|
|
237
245
|
|
|
246
|
+
assert next(mv.values(), None) is not None, "MultiValues may not be empty"
|
|
238
247
|
return mv
|
|
239
248
|
|
|
240
249
|
@classmethod
|
|
@@ -14,7 +14,7 @@ class ISPOMixin(MemoryMixin):
|
|
|
14
14
|
def set_state(self, state):
|
|
15
15
|
raise Exception("Cannot set state on this stateless object")
|
|
16
16
|
|
|
17
|
-
def _default_value(self, *args, memory
|
|
17
|
+
def _default_value(self, *args, memory, **kwargs):
|
|
18
18
|
try:
|
|
19
19
|
func = memory._default_value
|
|
20
20
|
except AttributeError as e:
|
|
@@ -22,7 +22,7 @@ class ISPOMixin(MemoryMixin):
|
|
|
22
22
|
else:
|
|
23
23
|
return func(*args, **kwargs)
|
|
24
24
|
|
|
25
|
-
def _add_constraints(self, *args, memory
|
|
25
|
+
def _add_constraints(self, *args, memory, **kwargs):
|
|
26
26
|
try:
|
|
27
27
|
func = memory._add_constraints
|
|
28
28
|
except AttributeError as e:
|
|
@@ -30,7 +30,7 @@ class ISPOMixin(MemoryMixin):
|
|
|
30
30
|
else:
|
|
31
31
|
return func(*args, **kwargs)
|
|
32
32
|
|
|
33
|
-
def _merge_values(self, *args, memory
|
|
33
|
+
def _merge_values(self, *args, memory, **kwargs):
|
|
34
34
|
try:
|
|
35
35
|
func = memory._merge_values
|
|
36
36
|
except AttributeError as ex:
|
|
@@ -38,7 +38,7 @@ class ISPOMixin(MemoryMixin):
|
|
|
38
38
|
else:
|
|
39
39
|
return func(*args, **kwargs)
|
|
40
40
|
|
|
41
|
-
def _merge_labels(self, *args, memory
|
|
41
|
+
def _merge_labels(self, *args, memory, **kwargs):
|
|
42
42
|
try:
|
|
43
43
|
func = memory._merge_labels
|
|
44
44
|
except AttributeError as ex:
|
|
@@ -46,7 +46,7 @@ class ISPOMixin(MemoryMixin):
|
|
|
46
46
|
else:
|
|
47
47
|
return func(*args, **kwargs)
|
|
48
48
|
|
|
49
|
-
def _update_mappings(self, *args, memory
|
|
49
|
+
def _update_mappings(self, *args, memory, **kwargs):
|
|
50
50
|
try:
|
|
51
51
|
func = memory._update_mappings
|
|
52
52
|
except AttributeError as ex:
|