angr 9.2.123__py3-none-win_amd64.whl → 9.2.125__py3-none-win_amd64.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/__init__.py +9 -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/codecave.py +77 -0
- 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 +58 -2
- angr/analyses/decompiler/condition_processor.py +10 -3
- angr/analyses/decompiler/decompilation_cache.py +2 -0
- angr/analyses/decompiler/decompiler.py +54 -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/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +13 -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/tag_slicer.py +41 -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/constant_derefs.py +2 -2
- 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/patchfinder.py +137 -0
- angr/analyses/pathfinder.py +282 -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/smc.py +159 -0
- angr/analyses/variable_recovery/engine_ail.py +14 -0
- angr/analyses/variable_recovery/engine_base.py +11 -0
- angr/angrdb/models.py +1 -2
- angr/engines/light/engine.py +12 -0
- angr/engines/vex/heavy/heavy.py +2 -0
- angr/exploration_techniques/spiller_db.py +1 -2
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/decompilation.py +45 -0
- angr/knowledge_plugins/functions/function.py +4 -0
- angr/knowledge_plugins/functions/function_manager.py +18 -9
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +1 -0
- angr/knowledge_plugins/key_definitions/atoms.py +8 -0
- angr/lib/angr_native.dll +0 -0
- angr/misc/ux.py +2 -2
- angr/procedures/definitions/parse_win32json.py +2 -1
- angr/project.py +17 -1
- angr/state_plugins/history.py +6 -4
- 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/bits.py +4 -0
- angr/utils/constants.py +1 -1
- angr/utils/graph.py +15 -0
- angr/utils/tagged_interval_map.py +112 -0
- angr/vaults.py +2 -2
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/METADATA +6 -6
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/RECORD +104 -97
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/WHEEL +1 -1
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/LICENSE +0 -0
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/entry_points.txt +0 -0
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
|
@@ -22,15 +22,15 @@ class UnderconstrainedMixin(MemoryMixin):
|
|
|
22
22
|
out._unconstrained_range = self._unconstrained_range
|
|
23
23
|
return out
|
|
24
24
|
|
|
25
|
-
def load(self, addr, **kwargs):
|
|
25
|
+
def load(self, addr, size=None, **kwargs):
|
|
26
26
|
self._constrain_underconstrained_index(addr)
|
|
27
|
-
return super().load(addr, **kwargs)
|
|
27
|
+
return super().load(addr, size, **kwargs)
|
|
28
28
|
|
|
29
|
-
def store(self, addr, data, **kwargs):
|
|
29
|
+
def store(self, addr, data, size=None, **kwargs):
|
|
30
30
|
self._constrain_underconstrained_index(addr)
|
|
31
|
-
super().store(addr, data, **kwargs)
|
|
31
|
+
super().store(addr, data, size, **kwargs)
|
|
32
32
|
|
|
33
|
-
def _default_value(self, addr, size, name=None, key=None, inspect=True, events=True, **kwargs):
|
|
33
|
+
def _default_value(self, addr, size, *, name=None, key=None, inspect=True, events=True, **kwargs):
|
|
34
34
|
if o.UNDER_CONSTRAINED_SYMEXEC in self.state.options and type(addr) is int:
|
|
35
35
|
if self.category == "mem":
|
|
36
36
|
alloc_depth = self.state.uc_manager.get_alloc_depth(addr)
|
|
@@ -8,18 +8,18 @@ class UnwrapperMixin(MemoryMixin):
|
|
|
8
8
|
This mixin processes SimActionObjects by passing on their .ast field.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
def store(self, addr, data, size=None, condition=None, **kwargs):
|
|
11
|
+
def store(self, addr, data, size=None, *, condition=None, **kwargs):
|
|
12
12
|
return super().store(
|
|
13
13
|
_raw_ast(addr), _raw_ast(data), size=_raw_ast(size), condition=_raw_ast(condition), **kwargs
|
|
14
14
|
)
|
|
15
15
|
|
|
16
|
-
def load(self, addr, size=None, condition=None, fallback=None, **kwargs):
|
|
16
|
+
def load(self, addr, size=None, *, condition=None, fallback=None, **kwargs):
|
|
17
17
|
return super().load(
|
|
18
18
|
_raw_ast(addr), size=_raw_ast(size), condition=_raw_ast(condition), fallback=_raw_ast(fallback), **kwargs
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
-
def find(self, addr,
|
|
22
|
-
return super().find(_raw_ast(addr), _raw_ast(
|
|
21
|
+
def find(self, addr, data, max_search, *, default=None, **kwargs):
|
|
22
|
+
return super().find(_raw_ast(addr), _raw_ast(data), max_search, default=_raw_ast(default), **kwargs)
|
|
23
23
|
|
|
24
24
|
def copy_contents(self, dst, src, size, condition=None, **kwargs):
|
|
25
25
|
return super().copy_contents(_raw_ast(dst), _raw_ast(src), _raw_ast(size), _raw_ast(condition), **kwargs)
|
angr/storage/memory_object.py
CHANGED
|
@@ -42,7 +42,7 @@ class SimMemoryObject:
|
|
|
42
42
|
raise SimMemoryError("bytes can only be stored big-endian")
|
|
43
43
|
self._byte_width = byte_width
|
|
44
44
|
self.base = base
|
|
45
|
-
self.object = obj
|
|
45
|
+
self.object: claripy.ast.BV | claripy.ast.FP = obj
|
|
46
46
|
self.length = obj_bit_size(obj) // self._byte_width if length is None else length
|
|
47
47
|
self.endness = endness
|
|
48
48
|
self._concrete_bytes: bytes | None = None
|
|
@@ -98,8 +98,9 @@ class SimMemoryObject:
|
|
|
98
98
|
return o if allow_concrete else claripy.BVV(o)
|
|
99
99
|
|
|
100
100
|
offset = addr - self.base
|
|
101
|
+
bv_obj = claripy.fpToIEEEBV(self.object) if isinstance(self.object, claripy.ast.FP) else self.object
|
|
101
102
|
try:
|
|
102
|
-
thing = bv_slice(
|
|
103
|
+
thing = bv_slice(bv_obj, offset, length, self.endness == "Iend_LE", self._byte_width)
|
|
103
104
|
except claripy.ClaripyOperationError:
|
|
104
105
|
# hacks to handle address space wrapping
|
|
105
106
|
if offset >= 0:
|
|
@@ -110,7 +111,7 @@ class SimMemoryObject:
|
|
|
110
111
|
offset += 2**64
|
|
111
112
|
else:
|
|
112
113
|
raise
|
|
113
|
-
thing = bv_slice(
|
|
114
|
+
thing = bv_slice(bv_obj, offset, length, self.endness == "Iend_LE", self._byte_width)
|
|
114
115
|
|
|
115
116
|
if self.endness != endness:
|
|
116
117
|
thing = thing.reversed
|
angr/utils/bits.py
CHANGED
angr/utils/constants.py
CHANGED
angr/utils/graph.py
CHANGED
|
@@ -414,6 +414,7 @@ class Dominators:
|
|
|
414
414
|
container_nodes = {}
|
|
415
415
|
|
|
416
416
|
traversed_nodes = set()
|
|
417
|
+
endnode_encountered = False
|
|
417
418
|
while queue:
|
|
418
419
|
node = queue.pop()
|
|
419
420
|
|
|
@@ -433,9 +434,11 @@ class Dominators:
|
|
|
433
434
|
# may end with a loop.
|
|
434
435
|
if self._reverse:
|
|
435
436
|
# Add an edge between the start node and this node
|
|
437
|
+
endnode_encountered = True
|
|
436
438
|
new_graph.add_edge(start_node, container_node)
|
|
437
439
|
else:
|
|
438
440
|
# Add an edge between our this node and end node
|
|
441
|
+
endnode_encountered = True
|
|
439
442
|
new_graph.add_edge(container_node, end_node)
|
|
440
443
|
|
|
441
444
|
for s in successors:
|
|
@@ -451,6 +454,18 @@ class Dominators:
|
|
|
451
454
|
if container_s not in traversed_nodes:
|
|
452
455
|
queue.append(s)
|
|
453
456
|
|
|
457
|
+
if not endnode_encountered:
|
|
458
|
+
# the graph is a circle with no end node. we run it with DFS to identify an end node
|
|
459
|
+
nn = next((nn for nn in networkx.dfs_postorder_nodes(graph) if nn in container_nodes), None)
|
|
460
|
+
if nn is not None:
|
|
461
|
+
if self._reverse:
|
|
462
|
+
new_graph.add_edge(start_node, container_nodes[nn])
|
|
463
|
+
else:
|
|
464
|
+
new_graph.add_edge(container_nodes[nn], end_node)
|
|
465
|
+
else:
|
|
466
|
+
# the graph must be empty - totally unexpected!
|
|
467
|
+
raise RuntimeError("Cannot find any end node candidates in the graph. Is the graph empty?")
|
|
468
|
+
|
|
454
469
|
if self._reverse:
|
|
455
470
|
# Add the end node
|
|
456
471
|
new_graph.add_edge(container_nodes[n], end_node)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from collections.abc import Iterator
|
|
3
|
+
|
|
4
|
+
from sortedcontainers import SortedDict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TaggedIntervalMap:
|
|
8
|
+
"""
|
|
9
|
+
Catalogs features of intervals.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, nbits: int = 0):
|
|
13
|
+
"""
|
|
14
|
+
:param nbits: Number of binning bits. Higher values reduce detail. 0 for no binning.
|
|
15
|
+
"""
|
|
16
|
+
self._nbits: int = nbits
|
|
17
|
+
self._map: SortedDict = SortedDict() # SortedDict[int, int]
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def nbits(self) -> int:
|
|
21
|
+
return self._nbits
|
|
22
|
+
|
|
23
|
+
def add(self, addr: int, size: int, tags: int) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Add interval starting at `addr` of `size` bytes.
|
|
26
|
+
|
|
27
|
+
When binning, intervals endpoints are aligned to 2^nbits. Gaps between added intervals are populated with
|
|
28
|
+
implicit intervals having tag value of 0. Overlapping intervals will have tag bits OR'd together.
|
|
29
|
+
|
|
30
|
+
Adjacent intervals in the interval map have unique tags. When intervals are added to the map, any adjacent stops
|
|
31
|
+
with identical tags will be eliminated so the map retains this property.
|
|
32
|
+
|
|
33
|
+
For example: if an interval(addr=0, size=100, tags=1) is added, followed by (100, 100, 1), the resulting
|
|
34
|
+
interval in the map will be (0, 200, 1).
|
|
35
|
+
"""
|
|
36
|
+
assert addr >= 0
|
|
37
|
+
assert size >= 0
|
|
38
|
+
assert tags != 0
|
|
39
|
+
|
|
40
|
+
if size == 0:
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
max_bin_offset = (1 << self._nbits) - 1
|
|
44
|
+
mask = ~max_bin_offset
|
|
45
|
+
|
|
46
|
+
start_addr = addr & mask # Round down to bin alignment
|
|
47
|
+
end_addr = (addr + size + max_bin_offset) & mask # Round up to bin alignment
|
|
48
|
+
|
|
49
|
+
if self._is_already_covered(start_addr, end_addr, tags):
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
self._insert_stop(start_addr)
|
|
53
|
+
self._insert_stop(end_addr)
|
|
54
|
+
for affected_addr in self._map.irange(start_addr, end_addr, inclusive=(True, False)):
|
|
55
|
+
self._map[affected_addr] |= tags
|
|
56
|
+
self._eliminate_extraneous_stops(start_addr, end_addr)
|
|
57
|
+
|
|
58
|
+
def _insert_stop(self, addr: int) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Insert a new interval stop point at `addr`, if one is not already present in the map. Tags are copied from
|
|
61
|
+
nearest stop before `addr`.
|
|
62
|
+
"""
|
|
63
|
+
if addr not in self._map:
|
|
64
|
+
idx = self._map.bisect(addr) - 1
|
|
65
|
+
self._map[addr] = self._map.peekitem(idx)[1] if idx >= 0 else 0
|
|
66
|
+
|
|
67
|
+
def _is_already_covered(self, min_addr: int, end_addr: int, tags: int) -> bool:
|
|
68
|
+
"""
|
|
69
|
+
Determine if interval [min_addr, end_addr) is covered by an existing range with identical tags.
|
|
70
|
+
"""
|
|
71
|
+
idx = self._map.bisect(min_addr) - 1
|
|
72
|
+
if idx >= 0 and len(self._map) > idx + 1:
|
|
73
|
+
e_addr, e_tags = self._map.peekitem(idx)
|
|
74
|
+
e_addr_next, _ = self._map.peekitem(idx + 1)
|
|
75
|
+
return (e_addr <= min_addr) and (end_addr <= e_addr_next) and (e_tags == tags)
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
def _eliminate_extraneous_stops(self, min_addr: int, max_addr: int) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Canonicalize the map by eliminating adjacent stops with identical tags both inside and directly outside of
|
|
81
|
+
[min_addr, max_addr].
|
|
82
|
+
"""
|
|
83
|
+
keys_to_drop = []
|
|
84
|
+
prev_tags = None
|
|
85
|
+
for addr, _, tags in self.irange(min_addr, max_addr):
|
|
86
|
+
if tags == prev_tags:
|
|
87
|
+
keys_to_drop.append(addr)
|
|
88
|
+
else:
|
|
89
|
+
prev_tags = tags
|
|
90
|
+
|
|
91
|
+
for addr in keys_to_drop:
|
|
92
|
+
del self._map[addr]
|
|
93
|
+
|
|
94
|
+
def irange(self, min_addr: int | None = None, max_addr: int | None = None) -> Iterator[tuple[int, int, int]]:
|
|
95
|
+
"""
|
|
96
|
+
Iterate over intervals intersecting [min_addr, max_addr], yielding interval (addr, size, tags) tuples. Implicit
|
|
97
|
+
gap intervals (with tags=0) are also returned.
|
|
98
|
+
|
|
99
|
+
:param min_addr: Minimum address (inclusive) to begin iterating from. If None, iterate from start of map.
|
|
100
|
+
:param max_addr: Maximum address (inclusive) to iterate to. If None, iterate to end of map.
|
|
101
|
+
"""
|
|
102
|
+
if not self._map:
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
start_idx = 0 if min_addr is None else max(0, self._map.bisect_left(min_addr) - 1)
|
|
106
|
+
stop_idx = None if max_addr is None else (self._map.bisect(max_addr) + 1)
|
|
107
|
+
|
|
108
|
+
start_addr, tags = self._map.peekitem(start_idx)
|
|
109
|
+
for addr in self._map.islice(start_idx + 1, stop_idx):
|
|
110
|
+
yield (start_addr, addr - start_addr, tags)
|
|
111
|
+
tags = self._map[addr]
|
|
112
|
+
start_addr = addr
|
angr/vaults.py
CHANGED
|
@@ -311,7 +311,7 @@ class VaultShelf(VaultDict):
|
|
|
311
311
|
|
|
312
312
|
def __init__(self, path=None):
|
|
313
313
|
self._path = tempfile.mktemp() if path is None else path
|
|
314
|
-
s = shelve.open(self._path, protocol=-1)
|
|
314
|
+
s = shelve.open(self._path, protocol=-1) # noqa: SIM115
|
|
315
315
|
super().__init__(s)
|
|
316
316
|
|
|
317
317
|
def close(self):
|
|
@@ -334,7 +334,7 @@ class VaultDirShelf(VaultDict):
|
|
|
334
334
|
@contextlib.contextmanager
|
|
335
335
|
def _locked_shelve(self, shelve_path):
|
|
336
336
|
with self._lock:
|
|
337
|
-
self._dict = shelve.open(shelve_path, protocol=-1)
|
|
337
|
+
self._dict = shelve.open(shelve_path, protocol=-1) # noqa: SIM115
|
|
338
338
|
yield
|
|
339
339
|
self._dict.close()
|
|
340
340
|
self._dict = None
|