angr 9.2.64__py3-none-win_amd64.whl → 9.2.66__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 +55 -2
- angr/analyses/calling_convention.py +4 -3
- angr/analyses/cfg/cfg_base.py +2 -2
- angr/analyses/cfg/cfg_fast.py +128 -60
- angr/analyses/decompiler/ail_simplifier.py +1 -2
- angr/analyses/decompiler/block_simplifier.py +4 -3
- angr/analyses/decompiler/callsite_maker.py +1 -1
- angr/analyses/decompiler/condition_processor.py +5 -3
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +51 -8
- angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +92 -0
- angr/analyses/decompiler/structured_codegen/c.py +59 -6
- angr/analyses/decompiler/utils.py +1 -1
- angr/analyses/find_objects_static.py +4 -4
- angr/analyses/propagator/engine_ail.py +2 -1
- angr/analyses/reaching_definitions/__init__.py +1 -3
- angr/analyses/reaching_definitions/dep_graph.py +33 -4
- angr/analyses/reaching_definitions/engine_ail.py +5 -6
- angr/analyses/reaching_definitions/engine_vex.py +6 -7
- angr/analyses/reaching_definitions/external_codeloc.py +0 -27
- angr/analyses/reaching_definitions/function_handler.py +145 -23
- angr/analyses/reaching_definitions/rd_initializer.py +221 -0
- angr/analyses/reaching_definitions/rd_state.py +95 -153
- angr/analyses/reaching_definitions/reaching_definitions.py +15 -3
- angr/calling_conventions.py +2 -2
- angr/code_location.py +24 -0
- angr/exploration_techniques/__init__.py +28 -0
- angr/knowledge_plugins/cfg/cfg_model.py +1 -1
- angr/knowledge_plugins/key_definitions/__init__.py +12 -1
- angr/knowledge_plugins/key_definitions/atoms.py +9 -0
- angr/knowledge_plugins/key_definitions/definition.py +13 -18
- angr/knowledge_plugins/key_definitions/live_definitions.py +350 -106
- angr/lib/angr_native.dll +0 -0
- angr/project.py +1 -1
- angr/sim_manager.py +15 -0
- angr/sim_state.py +3 -3
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +56 -8
- angr/storage/memory_object.py +3 -1
- angr/utils/typing.py +16 -0
- {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/METADATA +8 -8
- {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/RECORD +44 -42
- {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/WHEEL +1 -1
- angr/analyses/decompiler/peephole_optimizations/conv_const_mull_a_shift.py +0 -75
- {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/LICENSE +0 -0
- {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from typing import Optional, Iterable, Dict, Set, Generator, Tuple, Union, Any, TYPE_CHECKING, overload, Type
|
|
1
2
|
import weakref
|
|
2
|
-
from typing import Optional, Iterable, Dict, Set, Generator, Tuple, Union, Any, TYPE_CHECKING
|
|
3
3
|
import logging
|
|
4
|
+
from enum import Enum, auto
|
|
4
5
|
|
|
5
6
|
from collections import defaultdict
|
|
6
7
|
|
|
@@ -8,23 +9,36 @@ import claripy
|
|
|
8
9
|
from claripy.annotation import Annotation
|
|
9
10
|
import archinfo
|
|
10
11
|
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
12
|
+
from angr.misc.ux import deprecated
|
|
13
|
+
from angr.errors import SimMemoryMissingError, SimMemoryError
|
|
14
|
+
from angr.storage.memory_mixins import MultiValuedMemory
|
|
15
|
+
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
|
|
16
|
+
from angr.engines.light import SpOffset
|
|
17
|
+
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
16
18
|
from .atoms import Atom, Register, MemoryLocation, Tmp, ConstantSrc
|
|
17
19
|
from .definition import Definition, Tag
|
|
18
20
|
from .heap_address import HeapAddress
|
|
19
21
|
from .uses import Uses
|
|
20
22
|
|
|
21
23
|
if TYPE_CHECKING:
|
|
24
|
+
from angr.project import Project
|
|
22
25
|
from angr.storage import SimMemoryObject
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
l = logging.getLogger(name=__name__)
|
|
26
29
|
|
|
27
30
|
|
|
31
|
+
class DerefSize(Enum):
|
|
32
|
+
"""
|
|
33
|
+
An enum for specialized kinds of dereferences
|
|
34
|
+
|
|
35
|
+
NULL_TERMINATE - Dereference until the first byte which could be a literal null. Return a value including the
|
|
36
|
+
terminator.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
NULL_TERMINATE = auto()
|
|
40
|
+
|
|
41
|
+
|
|
28
42
|
#
|
|
29
43
|
# Annotations
|
|
30
44
|
#
|
|
@@ -81,11 +95,13 @@ class LiveDefinitions:
|
|
|
81
95
|
"project",
|
|
82
96
|
"arch",
|
|
83
97
|
"track_tmps",
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
98
|
+
"registers",
|
|
99
|
+
"stack",
|
|
100
|
+
"heap",
|
|
101
|
+
"memory",
|
|
88
102
|
"tmps",
|
|
103
|
+
"others",
|
|
104
|
+
"other_uses",
|
|
89
105
|
"register_uses",
|
|
90
106
|
"stack_uses",
|
|
91
107
|
"heap_uses",
|
|
@@ -101,23 +117,25 @@ class LiveDefinitions:
|
|
|
101
117
|
arch: archinfo.Arch,
|
|
102
118
|
track_tmps: bool = False,
|
|
103
119
|
canonical_size=8,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
registers=None,
|
|
121
|
+
stack=None,
|
|
122
|
+
memory=None,
|
|
123
|
+
heap=None,
|
|
108
124
|
tmps=None,
|
|
125
|
+
others=None,
|
|
109
126
|
register_uses=None,
|
|
110
127
|
stack_uses=None,
|
|
111
128
|
heap_uses=None,
|
|
112
129
|
memory_uses=None,
|
|
113
130
|
tmp_uses=None,
|
|
131
|
+
other_uses=None,
|
|
114
132
|
):
|
|
115
|
-
self.project = None
|
|
133
|
+
self.project: Optional["Project"] = None
|
|
116
134
|
self.arch = arch
|
|
117
135
|
self.track_tmps = track_tmps
|
|
118
136
|
self._canonical_size: int = canonical_size # TODO: Drop canonical_size
|
|
119
137
|
|
|
120
|
-
self.
|
|
138
|
+
self.registers: MultiValuedMemory = (
|
|
121
139
|
MultiValuedMemory(
|
|
122
140
|
memory_id="reg",
|
|
123
141
|
top_func=self.top,
|
|
@@ -125,70 +143,76 @@ class LiveDefinitions:
|
|
|
125
143
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
126
144
|
endness=self.arch.register_endness,
|
|
127
145
|
)
|
|
128
|
-
if
|
|
129
|
-
else
|
|
146
|
+
if registers is None
|
|
147
|
+
else registers
|
|
130
148
|
)
|
|
131
|
-
self.
|
|
149
|
+
self.stack: MultiValuedMemory = (
|
|
132
150
|
MultiValuedMemory(
|
|
133
151
|
memory_id="mem",
|
|
134
152
|
top_func=self.top,
|
|
135
153
|
skip_missing_values_during_merging=False,
|
|
136
154
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
137
155
|
)
|
|
138
|
-
if
|
|
139
|
-
else
|
|
156
|
+
if stack is None
|
|
157
|
+
else stack
|
|
140
158
|
)
|
|
141
|
-
self.
|
|
159
|
+
self.memory: MultiValuedMemory = (
|
|
142
160
|
MultiValuedMemory(
|
|
143
161
|
memory_id="mem",
|
|
144
162
|
top_func=self.top,
|
|
145
163
|
skip_missing_values_during_merging=False,
|
|
146
164
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
147
165
|
)
|
|
148
|
-
if
|
|
149
|
-
else
|
|
166
|
+
if memory is None
|
|
167
|
+
else memory
|
|
150
168
|
)
|
|
151
|
-
self.
|
|
169
|
+
self.heap: MultiValuedMemory = (
|
|
152
170
|
MultiValuedMemory(
|
|
153
171
|
memory_id="mem",
|
|
154
172
|
top_func=self.top,
|
|
155
173
|
skip_missing_values_during_merging=False,
|
|
156
174
|
page_kwargs={"mo_cmp": self._mo_cmp},
|
|
157
175
|
)
|
|
158
|
-
if
|
|
159
|
-
else
|
|
176
|
+
if heap is None
|
|
177
|
+
else heap
|
|
160
178
|
)
|
|
161
179
|
self.tmps: Dict[int, Set[Definition]] = {} if tmps is None else tmps
|
|
180
|
+
self.others: Dict[Atom, MultiValues] = others if others is not None else {}
|
|
162
181
|
|
|
163
182
|
# set state
|
|
164
|
-
self.
|
|
165
|
-
self.
|
|
166
|
-
self.
|
|
167
|
-
self.
|
|
183
|
+
self.registers.set_state(self)
|
|
184
|
+
self.stack.set_state(self)
|
|
185
|
+
self.memory.set_state(self)
|
|
186
|
+
self.heap.set_state(self)
|
|
168
187
|
|
|
169
188
|
self.register_uses = Uses() if register_uses is None else register_uses
|
|
170
189
|
self.stack_uses = Uses() if stack_uses is None else stack_uses
|
|
171
190
|
self.heap_uses = Uses() if heap_uses is None else heap_uses
|
|
172
191
|
self.memory_uses = Uses() if memory_uses is None else memory_uses
|
|
173
192
|
self.tmp_uses: Dict[int, Set[CodeLocation]] = defaultdict(set) if tmp_uses is None else tmp_uses
|
|
193
|
+
self.other_uses = Uses() if other_uses is None else other_uses
|
|
174
194
|
|
|
175
195
|
self.uses_by_codeloc: Dict[CodeLocation, Set[Definition]] = defaultdict(set)
|
|
176
196
|
|
|
177
197
|
@property
|
|
178
|
-
|
|
179
|
-
|
|
198
|
+
@deprecated("registers")
|
|
199
|
+
def register_definitions(self) -> MultiValuedMemory:
|
|
200
|
+
return self.registers
|
|
180
201
|
|
|
181
202
|
@property
|
|
182
|
-
|
|
183
|
-
|
|
203
|
+
@deprecated("stack")
|
|
204
|
+
def stack_definitions(self) -> MultiValuedMemory:
|
|
205
|
+
return self.stack
|
|
184
206
|
|
|
185
207
|
@property
|
|
186
|
-
|
|
187
|
-
|
|
208
|
+
@deprecated("memory")
|
|
209
|
+
def memory_definitions(self) -> MultiValuedMemory:
|
|
210
|
+
return self.memory
|
|
188
211
|
|
|
189
212
|
@property
|
|
190
|
-
|
|
191
|
-
|
|
213
|
+
@deprecated("heap")
|
|
214
|
+
def heap_definitions(self) -> MultiValuedMemory:
|
|
215
|
+
return self.heap
|
|
192
216
|
|
|
193
217
|
def __repr__(self):
|
|
194
218
|
ctnt = "LiveDefs"
|
|
@@ -201,18 +225,21 @@ class LiveDefinitions:
|
|
|
201
225
|
self.arch,
|
|
202
226
|
track_tmps=self.track_tmps,
|
|
203
227
|
canonical_size=self._canonical_size,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
228
|
+
registers=self.registers.copy(),
|
|
229
|
+
stack=self.stack.copy(),
|
|
230
|
+
heap=self.heap.copy(),
|
|
231
|
+
memory=self.memory.copy(),
|
|
208
232
|
tmps=self.tmps.copy() if not discard_tmpdefs else None,
|
|
233
|
+
others=dict(self.others),
|
|
209
234
|
register_uses=self.register_uses.copy(),
|
|
210
235
|
stack_uses=self.stack_uses.copy(),
|
|
211
236
|
heap_uses=self.heap_uses.copy(),
|
|
212
237
|
memory_uses=self.memory_uses.copy(),
|
|
213
238
|
tmp_uses=self.tmp_uses.copy() if not discard_tmpdefs else None,
|
|
239
|
+
other_uses=self.other_uses.copy(),
|
|
214
240
|
)
|
|
215
241
|
|
|
242
|
+
rd.project = self.project
|
|
216
243
|
return rd
|
|
217
244
|
|
|
218
245
|
def reset_uses(self):
|
|
@@ -220,6 +247,7 @@ class LiveDefinitions:
|
|
|
220
247
|
self.register_uses = Uses()
|
|
221
248
|
self.memory_uses = Uses()
|
|
222
249
|
self.heap_uses = Uses()
|
|
250
|
+
self.other_uses = Uses()
|
|
223
251
|
|
|
224
252
|
def _get_weakref(self):
|
|
225
253
|
return weakref.proxy(self)
|
|
@@ -283,7 +311,7 @@ class LiveDefinitions:
|
|
|
283
311
|
return True
|
|
284
312
|
return False
|
|
285
313
|
|
|
286
|
-
def stack_address(self, offset: int) -> claripy.ast.
|
|
314
|
+
def stack_address(self, offset: int) -> Optional[claripy.ast.bv.BV]:
|
|
287
315
|
base = claripy.BVS("stack_base", self.arch.bits, explicit_name=True)
|
|
288
316
|
if offset:
|
|
289
317
|
return base + offset
|
|
@@ -353,7 +381,7 @@ class LiveDefinitions:
|
|
|
353
381
|
Return the concrete value contained by the stack pointer.
|
|
354
382
|
"""
|
|
355
383
|
assert self.arch.sp_offset is not None
|
|
356
|
-
sp_values: MultiValues = self.
|
|
384
|
+
sp_values: MultiValues = self.registers.load(self.arch.sp_offset, size=self.arch.bytes)
|
|
357
385
|
sp_v = sp_values.one_value()
|
|
358
386
|
if sp_v is None:
|
|
359
387
|
# multiple values of sp exists. still return a value if there is only one value (maybe with different
|
|
@@ -373,7 +401,7 @@ class LiveDefinitions:
|
|
|
373
401
|
Return the offset of the stack pointer.
|
|
374
402
|
"""
|
|
375
403
|
assert self.arch.sp_offset is not None
|
|
376
|
-
sp_values: MultiValues = self.
|
|
404
|
+
sp_values: MultiValues = self.registers.load(self.arch.sp_offset, size=self.arch.bytes)
|
|
377
405
|
sp_v = sp_values.one_value()
|
|
378
406
|
if sp_v is None:
|
|
379
407
|
values = [v for v in next(iter(sp_values.values())) if self.get_stack_offset(v) is not None]
|
|
@@ -401,21 +429,30 @@ class LiveDefinitions:
|
|
|
401
429
|
raise ValueError("Unsupported architecture word size %d" % self.arch.bits)
|
|
402
430
|
return (base_v + offset) & mask
|
|
403
431
|
|
|
404
|
-
def merge(self, *others) -> Tuple["LiveDefinitions", bool]:
|
|
432
|
+
def merge(self, *others: "LiveDefinitions") -> Tuple["LiveDefinitions", bool]:
|
|
405
433
|
state = self.copy()
|
|
406
434
|
|
|
407
|
-
merge_occurred = state.
|
|
408
|
-
merge_occurred |= state.
|
|
409
|
-
merge_occurred |= state.
|
|
410
|
-
merge_occurred |= state.
|
|
435
|
+
merge_occurred = state.registers.merge([other.registers for other in others], None)
|
|
436
|
+
merge_occurred |= state.heap.merge([other.heap for other in others], None)
|
|
437
|
+
merge_occurred |= state.memory.merge([other.memory for other in others], None)
|
|
438
|
+
merge_occurred |= state.stack.merge([other.stack for other in others], None)
|
|
411
439
|
|
|
412
440
|
for other in others:
|
|
413
|
-
other:
|
|
441
|
+
for k in other.others:
|
|
442
|
+
if k in self.others:
|
|
443
|
+
thing = self.others[k].merge(other.others[k])
|
|
444
|
+
if thing != self.others[k]:
|
|
445
|
+
merge_occurred = True
|
|
446
|
+
self.others[k] = thing
|
|
447
|
+
else:
|
|
448
|
+
self.others[k] = other.others[k]
|
|
449
|
+
merge_occurred = True
|
|
414
450
|
|
|
415
451
|
merge_occurred |= state.register_uses.merge(other.register_uses)
|
|
416
452
|
merge_occurred |= state.stack_uses.merge(other.stack_uses)
|
|
417
453
|
merge_occurred |= state.heap_uses.merge(other.heap_uses)
|
|
418
454
|
merge_occurred |= state.memory_uses.merge(other.memory_uses)
|
|
455
|
+
merge_occurred |= state.other_uses.merge(other.other_uses)
|
|
419
456
|
|
|
420
457
|
return state, merge_occurred
|
|
421
458
|
|
|
@@ -429,21 +466,21 @@ class LiveDefinitions:
|
|
|
429
466
|
"""
|
|
430
467
|
|
|
431
468
|
if isinstance(atom, Register):
|
|
432
|
-
self.
|
|
469
|
+
self.registers.erase(atom.reg_offset, size=atom.size)
|
|
433
470
|
elif isinstance(atom, MemoryLocation):
|
|
434
471
|
if isinstance(atom.addr, SpOffset):
|
|
435
472
|
if atom.addr.offset is not None:
|
|
436
473
|
stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
|
|
437
|
-
self.
|
|
474
|
+
self.stack.erase(stack_addr, size=atom.size)
|
|
438
475
|
else:
|
|
439
476
|
l.warning("Skip stack storing since the stack offset is None.")
|
|
440
477
|
elif isinstance(atom.addr, HeapAddress):
|
|
441
|
-
self.
|
|
478
|
+
self.heap.erase(atom.addr.value, size=atom.size)
|
|
442
479
|
elif isinstance(atom.addr, int):
|
|
443
|
-
self.
|
|
480
|
+
self.memory.erase(atom.addr, size=atom.size)
|
|
444
481
|
elif isinstance(atom.addr, claripy.ast.Base):
|
|
445
482
|
if atom.addr.concrete:
|
|
446
|
-
self.
|
|
483
|
+
self.memory.erase(atom.addr._model_concrete.value, size=atom.size)
|
|
447
484
|
elif self.is_stack_address(atom.addr):
|
|
448
485
|
stack_addr = self.get_stack_address(atom.addr)
|
|
449
486
|
if stack_addr is None:
|
|
@@ -451,7 +488,7 @@ class LiveDefinitions:
|
|
|
451
488
|
"Failed to convert stack address %s to a concrete stack address. Skip the store.", atom.addr
|
|
452
489
|
)
|
|
453
490
|
else:
|
|
454
|
-
self.
|
|
491
|
+
self.stack.erase(stack_addr, size=atom.size)
|
|
455
492
|
else:
|
|
456
493
|
return
|
|
457
494
|
else:
|
|
@@ -459,7 +496,7 @@ class LiveDefinitions:
|
|
|
459
496
|
elif isinstance(atom, Tmp):
|
|
460
497
|
del self.tmps[atom.tmp_idx]
|
|
461
498
|
else:
|
|
462
|
-
|
|
499
|
+
del self.others[atom]
|
|
463
500
|
|
|
464
501
|
def kill_and_add_definition(
|
|
465
502
|
self,
|
|
@@ -486,7 +523,7 @@ class LiveDefinitions:
|
|
|
486
523
|
# set_object() replaces kill (not implemented) and add (add) in one step
|
|
487
524
|
if isinstance(atom, Register):
|
|
488
525
|
try:
|
|
489
|
-
self.
|
|
526
|
+
self.registers.store(
|
|
490
527
|
atom.reg_offset,
|
|
491
528
|
d,
|
|
492
529
|
size=atom.size,
|
|
@@ -501,16 +538,16 @@ class LiveDefinitions:
|
|
|
501
538
|
if isinstance(atom.addr, SpOffset):
|
|
502
539
|
if atom.addr.offset is not None:
|
|
503
540
|
stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
|
|
504
|
-
self.
|
|
541
|
+
self.stack.store(stack_addr, d, size=atom.size, endness=endness)
|
|
505
542
|
else:
|
|
506
543
|
l.warning("Skip stack storing since the stack offset is None.")
|
|
507
544
|
elif isinstance(atom.addr, HeapAddress):
|
|
508
|
-
self.
|
|
545
|
+
self.heap.store(atom.addr.value, d, size=atom.size, endness=endness)
|
|
509
546
|
elif isinstance(atom.addr, int):
|
|
510
|
-
self.
|
|
547
|
+
self.memory.store(atom.addr, d, size=atom.size, endness=endness)
|
|
511
548
|
elif isinstance(atom.addr, claripy.ast.Base):
|
|
512
549
|
if atom.addr.concrete:
|
|
513
|
-
self.
|
|
550
|
+
self.memory.store(atom.addr.concrete_value, d, size=atom.size, endness=endness)
|
|
514
551
|
elif self.is_stack_address(atom.addr):
|
|
515
552
|
stack_addr = self.get_stack_address(atom.addr)
|
|
516
553
|
if stack_addr is None:
|
|
@@ -518,7 +555,7 @@ class LiveDefinitions:
|
|
|
518
555
|
"Failed to convert stack address %s to a concrete stack address. Skip the store.", atom.addr
|
|
519
556
|
)
|
|
520
557
|
else:
|
|
521
|
-
self.
|
|
558
|
+
self.stack.store(stack_addr, d, size=atom.size, endness=endness)
|
|
522
559
|
else:
|
|
523
560
|
return None
|
|
524
561
|
else:
|
|
@@ -530,7 +567,7 @@ class LiveDefinitions:
|
|
|
530
567
|
self.tmps[atom.tmp_idx] = self.uses_by_codeloc[code_loc]
|
|
531
568
|
return None
|
|
532
569
|
else:
|
|
533
|
-
|
|
570
|
+
self.others[atom] = d
|
|
534
571
|
|
|
535
572
|
return d
|
|
536
573
|
|
|
@@ -550,7 +587,9 @@ class LiveDefinitions:
|
|
|
550
587
|
elif isinstance(atom, Tmp):
|
|
551
588
|
self.add_tmp_use(atom, code_loc)
|
|
552
589
|
else:
|
|
553
|
-
|
|
590
|
+
for defn in self.get_definitions(atom):
|
|
591
|
+
self.other_uses.add_use(defn, code_loc, expr)
|
|
592
|
+
self.uses_by_codeloc[code_loc].add(defn)
|
|
554
593
|
|
|
555
594
|
def add_use_by_def(self, definition: Definition, code_loc: CodeLocation, expr: Any = None) -> None:
|
|
556
595
|
if isinstance(definition.atom, Register):
|
|
@@ -571,24 +610,44 @@ class LiveDefinitions:
|
|
|
571
610
|
# ignore constants
|
|
572
611
|
pass
|
|
573
612
|
else:
|
|
574
|
-
|
|
613
|
+
self.other_uses.add_use(definition, code_loc, expr)
|
|
575
614
|
|
|
576
|
-
def get_definitions(
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
615
|
+
def get_definitions(
|
|
616
|
+
self, thing: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]], MultiValues]
|
|
617
|
+
) -> Iterable[Definition[Atom]]:
|
|
618
|
+
if isinstance(thing, MultiValues):
|
|
619
|
+
for vs in thing.values():
|
|
620
|
+
for v in vs:
|
|
621
|
+
for anno in v.annotations:
|
|
622
|
+
if isinstance(anno, DefinitionAnnotation):
|
|
623
|
+
yield anno.definition
|
|
624
|
+
return
|
|
625
|
+
elif isinstance(thing, Atom):
|
|
626
|
+
pass
|
|
627
|
+
elif isinstance(thing, Definition):
|
|
628
|
+
thing = thing.atom
|
|
629
|
+
else:
|
|
630
|
+
for atom2 in thing:
|
|
631
|
+
yield from self.get_definitions(atom2)
|
|
632
|
+
return
|
|
633
|
+
|
|
634
|
+
if isinstance(thing, Register):
|
|
635
|
+
yield from self.get_register_definitions(thing.reg_offset, thing.size)
|
|
636
|
+
elif isinstance(thing, MemoryLocation):
|
|
637
|
+
if isinstance(thing.addr, SpOffset):
|
|
638
|
+
yield from self.get_stack_definitions(thing.addr.offset, thing.size, thing.endness)
|
|
639
|
+
elif isinstance(thing.addr, HeapAddress):
|
|
640
|
+
yield from self.get_heap_definitions(thing.addr.value, size=thing.size, endness=thing.endness)
|
|
641
|
+
elif isinstance(thing.addr, int):
|
|
642
|
+
yield from self.get_memory_definitions(thing.addr, thing.size, thing.endness)
|
|
586
643
|
else:
|
|
587
644
|
return
|
|
588
|
-
elif isinstance(
|
|
589
|
-
yield from self.get_tmp_definitions(
|
|
645
|
+
elif isinstance(thing, Tmp):
|
|
646
|
+
yield from self.get_tmp_definitions(thing.tmp_idx)
|
|
590
647
|
else:
|
|
591
|
-
|
|
648
|
+
for mvs in self.others.get(thing, {}).values():
|
|
649
|
+
for mv in mvs:
|
|
650
|
+
yield from self.get_definitions(mv)
|
|
592
651
|
|
|
593
652
|
def get_tmp_definitions(self, tmp_idx: int) -> Iterable[Definition]:
|
|
594
653
|
if tmp_idx in self.tmps:
|
|
@@ -598,7 +657,7 @@ class LiveDefinitions:
|
|
|
598
657
|
|
|
599
658
|
def get_register_definitions(self, reg_offset: int, size: int, endness=None) -> Iterable[Definition]:
|
|
600
659
|
try:
|
|
601
|
-
values: MultiValues = self.
|
|
660
|
+
values: MultiValues = self.registers.load(
|
|
602
661
|
reg_offset,
|
|
603
662
|
size=size,
|
|
604
663
|
endness=endness,
|
|
@@ -606,7 +665,7 @@ class LiveDefinitions:
|
|
|
606
665
|
except SimMemoryMissingError as ex:
|
|
607
666
|
# load values and stop at the missing location
|
|
608
667
|
if ex.missing_addr > reg_offset:
|
|
609
|
-
values: MultiValues = self.
|
|
668
|
+
values: MultiValues = self.registers.load(
|
|
610
669
|
reg_offset, size=ex.missing_addr - reg_offset, endness=endness
|
|
611
670
|
)
|
|
612
671
|
else:
|
|
@@ -617,7 +676,7 @@ class LiveDefinitions:
|
|
|
617
676
|
def get_stack_values(self, stack_offset: int, size: int, endness: str) -> Optional[MultiValues]:
|
|
618
677
|
stack_addr = self.stack_offset_to_stack_addr(stack_offset)
|
|
619
678
|
try:
|
|
620
|
-
return self.
|
|
679
|
+
return self.stack.load(stack_addr, size=size, endness=endness)
|
|
621
680
|
except SimMemoryMissingError:
|
|
622
681
|
return None
|
|
623
682
|
|
|
@@ -629,54 +688,59 @@ class LiveDefinitions:
|
|
|
629
688
|
|
|
630
689
|
def get_heap_definitions(self, heap_addr: int, size: int, endness) -> Iterable[Definition]:
|
|
631
690
|
try:
|
|
632
|
-
mv: MultiValues = self.
|
|
691
|
+
mv: MultiValues = self.heap.load(heap_addr, size=size, endness=endness)
|
|
633
692
|
except SimMemoryMissingError:
|
|
634
693
|
return
|
|
635
694
|
yield from LiveDefinitions.extract_defs_from_mv(mv)
|
|
636
695
|
|
|
637
696
|
def get_memory_definitions(self, addr: int, size: int, endness) -> Iterable[Definition]:
|
|
638
697
|
try:
|
|
639
|
-
values = self.
|
|
698
|
+
values = self.memory.load(addr, size=size, endness=endness)
|
|
640
699
|
except SimMemoryMissingError:
|
|
641
700
|
return
|
|
642
701
|
yield from LiveDefinitions.extract_defs_from_mv(values)
|
|
643
702
|
|
|
703
|
+
@deprecated("get_definitions")
|
|
644
704
|
def get_definitions_from_atoms(self, atoms: Iterable[Atom]) -> Iterable[Definition]:
|
|
645
705
|
result = set()
|
|
646
706
|
for atom in atoms:
|
|
647
707
|
result |= set(self.get_definitions(atom))
|
|
648
708
|
return result
|
|
649
709
|
|
|
710
|
+
@deprecated("get_values")
|
|
650
711
|
def get_value_from_definition(self, definition: Definition) -> Optional[MultiValues]:
|
|
651
712
|
return self.get_value_from_atom(definition.atom)
|
|
652
713
|
|
|
653
|
-
|
|
714
|
+
@deprecated("get_one_value")
|
|
715
|
+
def get_one_value_from_definition(self, definition: Definition) -> Optional[claripy.ast.bv.BV]:
|
|
654
716
|
return self.get_one_value_from_atom(definition.atom)
|
|
655
717
|
|
|
718
|
+
@deprecated("get_concrete_value")
|
|
656
719
|
def get_concrete_value_from_definition(self, definition: Definition) -> Optional[int]:
|
|
657
720
|
return self.get_concrete_value_from_atom(definition.atom)
|
|
658
721
|
|
|
722
|
+
@deprecated("get_values")
|
|
659
723
|
def get_value_from_atom(self, atom: Atom) -> Optional[MultiValues]:
|
|
660
724
|
if isinstance(atom, Register):
|
|
661
725
|
try:
|
|
662
|
-
return self.
|
|
726
|
+
return self.registers.load(atom.reg_offset, size=atom.size)
|
|
663
727
|
except SimMemoryMissingError:
|
|
664
728
|
return None
|
|
665
729
|
elif isinstance(atom, MemoryLocation):
|
|
666
730
|
if isinstance(atom.addr, SpOffset):
|
|
667
731
|
stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
|
|
668
732
|
try:
|
|
669
|
-
return self.
|
|
733
|
+
return self.stack.load(stack_addr, size=atom.size, endness=atom.endness)
|
|
670
734
|
except SimMemoryMissingError:
|
|
671
735
|
return None
|
|
672
736
|
elif isinstance(atom.addr, HeapAddress):
|
|
673
737
|
try:
|
|
674
|
-
return self.
|
|
738
|
+
return self.heap.load(atom.addr.value, size=atom.size, endness=atom.endness)
|
|
675
739
|
except SimMemoryMissingError:
|
|
676
740
|
return None
|
|
677
741
|
elif isinstance(atom.addr, int):
|
|
678
742
|
try:
|
|
679
|
-
return self.
|
|
743
|
+
return self.memory.load(atom.addr, size=atom.size, endness=atom.endness)
|
|
680
744
|
except SimMemoryMissingError:
|
|
681
745
|
return None
|
|
682
746
|
else:
|
|
@@ -685,12 +749,14 @@ class LiveDefinitions:
|
|
|
685
749
|
else:
|
|
686
750
|
return None
|
|
687
751
|
|
|
688
|
-
|
|
752
|
+
@deprecated("get_one_value")
|
|
753
|
+
def get_one_value_from_atom(self, atom: Atom) -> Optional[claripy.ast.bv.BV]:
|
|
689
754
|
r = self.get_value_from_atom(atom)
|
|
690
755
|
if r is None:
|
|
691
756
|
return None
|
|
692
757
|
return r.one_value()
|
|
693
758
|
|
|
759
|
+
@deprecated("get_concrete_value")
|
|
694
760
|
def get_concrete_value_from_atom(self, atom: Atom) -> Optional[int]:
|
|
695
761
|
r = self.get_one_value_from_atom(atom)
|
|
696
762
|
if r is None:
|
|
@@ -699,28 +765,106 @@ class LiveDefinitions:
|
|
|
699
765
|
return None
|
|
700
766
|
return r.concrete_value
|
|
701
767
|
|
|
702
|
-
def get_values(
|
|
703
|
-
|
|
704
|
-
|
|
768
|
+
def get_values(
|
|
769
|
+
self, spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]]
|
|
770
|
+
) -> Optional[MultiValues]:
|
|
771
|
+
if isinstance(spec, Definition):
|
|
772
|
+
atom = spec.atom
|
|
773
|
+
elif isinstance(spec, Atom):
|
|
774
|
+
atom = spec
|
|
705
775
|
else:
|
|
706
|
-
|
|
776
|
+
result = None
|
|
777
|
+
for atom in spec:
|
|
778
|
+
r = self.get_values(atom)
|
|
779
|
+
if r is None:
|
|
780
|
+
continue
|
|
781
|
+
if result is None:
|
|
782
|
+
result = r
|
|
783
|
+
else:
|
|
784
|
+
result = result.merge(r)
|
|
785
|
+
return result
|
|
707
786
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
787
|
+
if isinstance(atom, Register):
|
|
788
|
+
try:
|
|
789
|
+
return self.registers.load(atom.reg_offset, size=atom.size)
|
|
790
|
+
except SimMemoryMissingError:
|
|
791
|
+
return None
|
|
792
|
+
elif isinstance(atom, MemoryLocation):
|
|
793
|
+
if isinstance(atom.addr, SpOffset):
|
|
794
|
+
stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
|
|
795
|
+
try:
|
|
796
|
+
return self.stack.load(stack_addr, size=atom.size, endness=atom.endness)
|
|
797
|
+
except SimMemoryMissingError:
|
|
798
|
+
return None
|
|
799
|
+
elif isinstance(atom.addr, HeapAddress):
|
|
800
|
+
try:
|
|
801
|
+
return self.heap.load(atom.addr.value, size=atom.size, endness=atom.endness)
|
|
802
|
+
except SimMemoryMissingError:
|
|
803
|
+
return None
|
|
804
|
+
elif isinstance(atom.addr, int):
|
|
805
|
+
try:
|
|
806
|
+
return self.memory.load(atom.addr, size=atom.size, endness=atom.endness)
|
|
807
|
+
except SimMemoryMissingError:
|
|
808
|
+
pass
|
|
809
|
+
if self.project is not None:
|
|
810
|
+
try:
|
|
811
|
+
bytestring = self.project.loader.memory.load(atom.addr, atom.size)
|
|
812
|
+
if atom.endness == archinfo.Endness.LE:
|
|
813
|
+
bytestring = bytes(reversed(bytestring))
|
|
814
|
+
mv = MultiValues(
|
|
815
|
+
self.annotate_with_def(claripy.BVV(bytestring), Definition(atom, ExternalCodeLocation()))
|
|
816
|
+
)
|
|
817
|
+
return mv
|
|
818
|
+
except KeyError:
|
|
819
|
+
pass
|
|
820
|
+
return None
|
|
821
|
+
else:
|
|
822
|
+
# ignore RegisterOffset
|
|
823
|
+
return None
|
|
711
824
|
else:
|
|
712
|
-
return self.
|
|
825
|
+
return self.others.get(atom, None)
|
|
713
826
|
|
|
714
|
-
def
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
827
|
+
def get_one_value(
|
|
828
|
+
self, spec: Union[Atom, Definition, Iterable[Atom], Iterable[Definition[Atom]]]
|
|
829
|
+
) -> Optional[claripy.ast.bv.BV]:
|
|
830
|
+
r = self.get_values(spec)
|
|
831
|
+
if r is None:
|
|
832
|
+
return None
|
|
833
|
+
return r.one_value()
|
|
834
|
+
|
|
835
|
+
@overload
|
|
836
|
+
def get_concrete_value(
|
|
837
|
+
self, spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]], cast_to: Type[int] = ...
|
|
838
|
+
) -> Optional[int]:
|
|
839
|
+
...
|
|
840
|
+
|
|
841
|
+
@overload
|
|
842
|
+
def get_concrete_value(
|
|
843
|
+
self,
|
|
844
|
+
spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]],
|
|
845
|
+
cast_to: Type[bytes] = ...,
|
|
846
|
+
) -> Optional[bytes]:
|
|
847
|
+
...
|
|
848
|
+
|
|
849
|
+
def get_concrete_value(
|
|
850
|
+
self,
|
|
851
|
+
spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]],
|
|
852
|
+
cast_to: Union[Type[int], Type[bytes]] = int,
|
|
853
|
+
) -> Union[int, bytes, None]:
|
|
854
|
+
r = self.get_one_value(spec)
|
|
855
|
+
if r is None:
|
|
856
|
+
return None
|
|
857
|
+
if r.symbolic:
|
|
858
|
+
return None
|
|
859
|
+
result = r.concrete_value
|
|
860
|
+
if issubclass(cast_to, bytes):
|
|
861
|
+
return result.to_bytes(len(r) // 8, "big")
|
|
862
|
+
return result
|
|
719
863
|
|
|
720
864
|
def add_register_use(self, reg_offset: int, size: int, code_loc: CodeLocation, expr: Optional[Any] = None) -> None:
|
|
721
865
|
# get all current definitions
|
|
722
866
|
try:
|
|
723
|
-
mvs: MultiValues = self.
|
|
867
|
+
mvs: MultiValues = self.registers.load(reg_offset, size=size)
|
|
724
868
|
except SimMemoryMissingError:
|
|
725
869
|
return
|
|
726
870
|
|
|
@@ -787,3 +931,103 @@ class LiveDefinitions:
|
|
|
787
931
|
|
|
788
932
|
self.tmp_uses[def_.atom.tmp_idx].add(code_loc)
|
|
789
933
|
self.uses_by_codeloc[code_loc].add(def_)
|
|
934
|
+
|
|
935
|
+
@overload
|
|
936
|
+
def deref(
|
|
937
|
+
self,
|
|
938
|
+
pointer: Union[MultiValues, Atom, Definition, Iterable[Atom], Iterable[Definition]],
|
|
939
|
+
size: Union[int, DerefSize],
|
|
940
|
+
endness: archinfo.Endness = ...,
|
|
941
|
+
) -> Set[MemoryLocation]:
|
|
942
|
+
...
|
|
943
|
+
|
|
944
|
+
@overload
|
|
945
|
+
def deref(
|
|
946
|
+
self,
|
|
947
|
+
pointer: Union[int, claripy.ast.BV, HeapAddress, SpOffset],
|
|
948
|
+
size: Union[int, DerefSize],
|
|
949
|
+
endness: archinfo.Endness = ...,
|
|
950
|
+
) -> Optional[MemoryLocation]:
|
|
951
|
+
...
|
|
952
|
+
|
|
953
|
+
def deref(self, pointer, size, endness=archinfo.Endness.BE):
|
|
954
|
+
if isinstance(pointer, (Atom, Definition)):
|
|
955
|
+
pointer = self.get_values(pointer)
|
|
956
|
+
if pointer is None:
|
|
957
|
+
return set()
|
|
958
|
+
|
|
959
|
+
if isinstance(pointer, set):
|
|
960
|
+
result = set()
|
|
961
|
+
for ptr_atom in pointer:
|
|
962
|
+
result.update(self.deref(ptr_atom, size, endness))
|
|
963
|
+
return result
|
|
964
|
+
|
|
965
|
+
if isinstance(pointer, MultiValues):
|
|
966
|
+
result = set()
|
|
967
|
+
for vs in pointer.values():
|
|
968
|
+
for value in vs:
|
|
969
|
+
atom = self.deref(value, size, endness)
|
|
970
|
+
if atom is not None:
|
|
971
|
+
result.add(atom)
|
|
972
|
+
return result
|
|
973
|
+
|
|
974
|
+
if isinstance(pointer, (HeapAddress, SpOffset, int)):
|
|
975
|
+
addr = pointer
|
|
976
|
+
else:
|
|
977
|
+
assert isinstance(pointer, claripy.ast.BV)
|
|
978
|
+
if self.is_top(pointer):
|
|
979
|
+
return None
|
|
980
|
+
|
|
981
|
+
# TODO this can be simplified with the walrus operator
|
|
982
|
+
stack_offset = self.get_stack_offset(pointer)
|
|
983
|
+
if stack_offset is not None:
|
|
984
|
+
addr = SpOffset(len(pointer), stack_offset)
|
|
985
|
+
else:
|
|
986
|
+
heap_offset = self.get_heap_offset(pointer)
|
|
987
|
+
if heap_offset is not None:
|
|
988
|
+
addr = HeapAddress(heap_offset)
|
|
989
|
+
elif pointer.op == "BVV":
|
|
990
|
+
addr = pointer.args[0]
|
|
991
|
+
else:
|
|
992
|
+
# cannot resolve
|
|
993
|
+
return None
|
|
994
|
+
|
|
995
|
+
if isinstance(size, DerefSize):
|
|
996
|
+
assert size == DerefSize.NULL_TERMINATE
|
|
997
|
+
for sz in range(4096): # arbitrary
|
|
998
|
+
# truly evil that this is an abstraction we have to contend with
|
|
999
|
+
mv = self.get_values(MemoryLocation(addr + sz, 1, endness))
|
|
1000
|
+
if mv is not None and 0 in mv and any(one.op == "BVV" and one.args[0] == 0 for one in mv[0]):
|
|
1001
|
+
size = sz + 1
|
|
1002
|
+
break
|
|
1003
|
+
else:
|
|
1004
|
+
l.warning(
|
|
1005
|
+
"Could not resolve cstring dereference at %s to a concrete size",
|
|
1006
|
+
hex(addr) if isinstance(addr, int) else addr,
|
|
1007
|
+
)
|
|
1008
|
+
size = 4096
|
|
1009
|
+
|
|
1010
|
+
return MemoryLocation(addr, size, endness)
|
|
1011
|
+
|
|
1012
|
+
@staticmethod
|
|
1013
|
+
def is_heap_address(addr: claripy.ast.Base) -> bool:
|
|
1014
|
+
return "heap_base" in addr.variables
|
|
1015
|
+
|
|
1016
|
+
@staticmethod
|
|
1017
|
+
def get_heap_offset(addr: claripy.ast.Base) -> Optional[int]:
|
|
1018
|
+
if "heap_base" in addr.variables:
|
|
1019
|
+
if addr.op == "BVS":
|
|
1020
|
+
return 0
|
|
1021
|
+
elif addr.op == "__add__" and len(addr.args) == 2 and addr.args[1].op == "BVV":
|
|
1022
|
+
return addr.args[1]._model_concrete.value
|
|
1023
|
+
return None
|
|
1024
|
+
|
|
1025
|
+
def heap_address(self, offset: Union[int, HeapAddress]) -> claripy.ast.BV:
|
|
1026
|
+
if isinstance(offset, HeapAddress):
|
|
1027
|
+
if not isinstance(offset.value, int):
|
|
1028
|
+
raise TypeError("TODO: what's this? contact @rhelmot")
|
|
1029
|
+
offset = offset.value
|
|
1030
|
+
base = claripy.BVS("heap_base", self.arch.bits, explicit_name=True)
|
|
1031
|
+
if offset:
|
|
1032
|
+
return base + offset
|
|
1033
|
+
return base
|