angr 9.2.130__py3-none-macosx_11_0_arm64.whl → 9.2.132__py3-none-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/analysis.py +6 -2
- angr/analyses/cfg/cfg_emulated.py +5 -5
- angr/analyses/cfg/cfg_fast.py +2 -2
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +139 -94
- angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +1 -1
- angr/analyses/ddg.py +14 -11
- angr/analyses/decompiler/ail_simplifier.py +3 -2
- angr/analyses/decompiler/block_simplifier.py +10 -21
- angr/analyses/decompiler/clinic.py +361 -8
- angr/analyses/decompiler/condition_processor.py +12 -10
- angr/analyses/decompiler/dephication/graph_rewriting.py +1 -1
- angr/analyses/decompiler/dephication/rewriting_engine.py +169 -45
- angr/analyses/decompiler/dephication/seqnode_dephication.py +5 -4
- angr/analyses/decompiler/optimization_passes/__init__.py +0 -3
- angr/analyses/decompiler/optimization_passes/const_derefs.py +1 -0
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +41 -16
- angr/analyses/decompiler/optimization_passes/engine_base.py +261 -83
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +173 -35
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +5 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +39 -19
- angr/analyses/decompiler/peephole_optimizations/__init__.py +5 -1
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +34 -0
- angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +3 -1
- angr/analyses/decompiler/peephole_optimizations/bswap.py +10 -6
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +100 -19
- angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +17 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +42 -3
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +4 -2
- angr/analyses/decompiler/peephole_optimizations/rol_ror.py +37 -10
- angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +25 -0
- angr/analyses/decompiler/peephole_optimizations/utils.py +18 -0
- angr/analyses/decompiler/presets/fast.py +0 -2
- angr/analyses/decompiler/presets/full.py +0 -2
- angr/analyses/decompiler/ssailification/rewriting.py +1 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +140 -57
- angr/analyses/decompiler/ssailification/ssailification.py +2 -1
- angr/analyses/decompiler/ssailification/traversal.py +4 -6
- angr/analyses/decompiler/ssailification/traversal_engine.py +125 -42
- angr/analyses/decompiler/structured_codegen/c.py +79 -16
- angr/analyses/decompiler/structuring/phoenix.py +40 -14
- angr/analyses/decompiler/structuring/structurer_nodes.py +9 -0
- angr/analyses/deobfuscator/irsb_reg_collector.py +29 -60
- angr/analyses/deobfuscator/string_obf_finder.py +2 -2
- angr/analyses/init_finder.py +47 -22
- angr/analyses/propagator/engine_base.py +21 -14
- angr/analyses/propagator/engine_vex.py +149 -179
- angr/analyses/propagator/propagator.py +10 -28
- angr/analyses/propagator/top_checker_mixin.py +211 -5
- angr/analyses/propagator/vex_vars.py +1 -1
- angr/analyses/reaching_definitions/dep_graph.py +1 -1
- angr/analyses/reaching_definitions/engine_ail.py +304 -329
- angr/analyses/reaching_definitions/engine_vex.py +243 -229
- angr/analyses/reaching_definitions/function_handler.py +3 -3
- angr/analyses/reaching_definitions/rd_state.py +37 -32
- angr/analyses/s_propagator.py +38 -5
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +9 -5
- angr/analyses/typehoon/simple_solver.py +16 -7
- angr/analyses/typehoon/translator.py +8 -0
- angr/analyses/typehoon/typeconsts.py +10 -2
- angr/analyses/typehoon/typehoon.py +4 -1
- angr/analyses/typehoon/typevars.py +9 -7
- angr/analyses/variable_recovery/engine_ail.py +296 -256
- angr/analyses/variable_recovery/engine_base.py +137 -116
- angr/analyses/variable_recovery/engine_vex.py +175 -185
- angr/analyses/variable_recovery/irsb_scanner.py +49 -38
- angr/analyses/variable_recovery/variable_recovery.py +28 -5
- angr/analyses/variable_recovery/variable_recovery_base.py +32 -33
- angr/analyses/variable_recovery/variable_recovery_fast.py +2 -2
- angr/analyses/xrefs.py +46 -19
- angr/annocfg.py +19 -14
- angr/block.py +4 -9
- angr/calling_conventions.py +1 -1
- angr/engines/engine.py +30 -14
- angr/engines/light/__init__.py +11 -3
- angr/engines/light/engine.py +1003 -1185
- angr/engines/pcode/cc.py +2 -0
- angr/engines/successors.py +13 -9
- angr/engines/vex/claripy/datalayer.py +1 -1
- angr/engines/vex/claripy/irop.py +14 -3
- angr/engines/vex/light/slicing.py +2 -2
- angr/exploration_techniques/__init__.py +1 -124
- angr/exploration_techniques/base.py +126 -0
- angr/exploration_techniques/bucketizer.py +1 -1
- angr/exploration_techniques/dfs.py +3 -1
- angr/exploration_techniques/director.py +2 -3
- angr/exploration_techniques/driller_core.py +1 -1
- angr/exploration_techniques/explorer.py +4 -2
- angr/exploration_techniques/lengthlimiter.py +2 -1
- angr/exploration_techniques/local_loop_seer.py +2 -1
- angr/exploration_techniques/loop_seer.py +5 -5
- angr/exploration_techniques/manual_mergepoint.py +2 -1
- angr/exploration_techniques/memory_watcher.py +3 -1
- angr/exploration_techniques/oppologist.py +4 -5
- angr/exploration_techniques/slicecutor.py +4 -2
- angr/exploration_techniques/spiller.py +1 -1
- angr/exploration_techniques/stochastic.py +2 -1
- angr/exploration_techniques/stub_stasher.py +2 -1
- angr/exploration_techniques/suggestions.py +3 -1
- angr/exploration_techniques/symbion.py +3 -1
- angr/exploration_techniques/tech_builder.py +2 -1
- angr/exploration_techniques/threading.py +4 -7
- angr/exploration_techniques/timeout.py +4 -2
- angr/exploration_techniques/tracer.py +4 -3
- angr/exploration_techniques/unique.py +3 -2
- angr/exploration_techniques/veritesting.py +1 -1
- angr/knowledge_plugins/key_definitions/atoms.py +2 -2
- angr/knowledge_plugins/key_definitions/live_definitions.py +16 -13
- angr/knowledge_plugins/propagations/states.py +13 -8
- angr/knowledge_plugins/variables/variable_manager.py +23 -9
- angr/lib/angr_native.dylib +0 -0
- angr/sim_manager.py +1 -3
- angr/sim_state.py +39 -41
- angr/sim_type.py +5 -0
- angr/sim_variable.py +29 -28
- angr/utils/bits.py +17 -0
- angr/utils/formatting.py +4 -1
- angr/utils/orderedset.py +4 -1
- angr/utils/ssa/__init__.py +21 -3
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/METADATA +6 -6
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/RECORD +125 -124
- angr/analyses/decompiler/optimization_passes/multi_simplifier.py +0 -223
- angr/analyses/propagator/engine_ail.py +0 -1562
- angr/storage/memory_mixins/__init__.pyi +0 -48
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/LICENSE +0 -0
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/WHEEL +0 -0
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/entry_points.txt +0 -0
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/top_level.txt +0 -0
|
@@ -86,7 +86,7 @@ class FunctionCallData:
|
|
|
86
86
|
|
|
87
87
|
callsite_codeloc: CodeLocation
|
|
88
88
|
function_codeloc: CodeLocation
|
|
89
|
-
address_multi: MultiValues | None
|
|
89
|
+
address_multi: MultiValues[claripy.ast.BV | claripy.ast.FP] | None
|
|
90
90
|
address: int | None = None
|
|
91
91
|
symbol: Symbol | None = None
|
|
92
92
|
function: Function | None = None
|
|
@@ -94,12 +94,12 @@ class FunctionCallData:
|
|
|
94
94
|
cc: SimCC | None = None
|
|
95
95
|
prototype: SimTypeFunction | None = None
|
|
96
96
|
args_atoms: list[set[Atom]] | None = None
|
|
97
|
-
args_values: list[MultiValues] | None = None
|
|
97
|
+
args_values: list[MultiValues[claripy.ast.BV | claripy.ast.FP]] | None = None
|
|
98
98
|
ret_atoms: set[Atom] | None = None
|
|
99
99
|
redefine_locals: bool = True
|
|
100
100
|
visited_blocks: set[int] | None = None
|
|
101
101
|
effects: list[FunctionEffect] = field(default_factory=list)
|
|
102
|
-
ret_values: MultiValues | None = None
|
|
102
|
+
ret_values: MultiValues[claripy.ast.BV | claripy.ast.FP] | None = None
|
|
103
103
|
ret_values_deps: set[Definition] | None = None
|
|
104
104
|
caller_will_handle_single_ret: bool = False
|
|
105
105
|
guessed_cc: bool = False
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Any, TYPE_CHECKING, overload
|
|
2
|
+
from typing import Any, TYPE_CHECKING, cast, overload
|
|
3
3
|
from collections.abc import Iterable, Iterator
|
|
4
4
|
import logging
|
|
5
|
+
from typing_extensions import Self
|
|
5
6
|
|
|
6
7
|
import archinfo
|
|
7
8
|
import claripy
|
|
@@ -13,7 +14,7 @@ from angr.knowledge_plugins.key_definitions.heap_address import HeapAddress
|
|
|
13
14
|
from angr.knowledge_plugins.key_definitions.definition import A
|
|
14
15
|
from angr.engines.light import SpOffset
|
|
15
16
|
from angr.code_location import CodeLocation
|
|
16
|
-
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
|
|
17
|
+
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MVType, MultiValues
|
|
17
18
|
from angr.storage.memory_mixins import MultiValuedMemory
|
|
18
19
|
from angr.knowledge_plugins.key_definitions import LiveDefinitions, DerefSize, Definition
|
|
19
20
|
from angr.knowledge_plugins.key_definitions.atoms import Atom, GuardUse, Register, MemoryLocation, ConstantSrc
|
|
@@ -77,14 +78,14 @@ class ReachingDefinitionsState:
|
|
|
77
78
|
codeloc: CodeLocation,
|
|
78
79
|
arch: archinfo.Arch,
|
|
79
80
|
subject: Subject,
|
|
81
|
+
analysis: ReachingDefinitionsAnalysis,
|
|
80
82
|
track_tmps: bool = False,
|
|
81
83
|
track_consts: bool = False,
|
|
82
|
-
analysis: ReachingDefinitionsAnalysis | None = None,
|
|
83
84
|
rtoc_value=None,
|
|
84
85
|
live_definitions: LiveDefinitions | None = None,
|
|
85
86
|
canonical_size: int = 8,
|
|
86
|
-
heap_allocator: HeapAllocator = None,
|
|
87
|
-
environment: Environment = None,
|
|
87
|
+
heap_allocator: HeapAllocator | None = None,
|
|
88
|
+
environment: Environment | None = None,
|
|
88
89
|
sp_adjusted: bool = False,
|
|
89
90
|
all_definitions: set[Definition[A]] | None = None,
|
|
90
91
|
initializer: RDAStateInitializer | None = None,
|
|
@@ -102,12 +103,12 @@ class ReachingDefinitionsState:
|
|
|
102
103
|
self._sp_adjusted: bool = sp_adjusted
|
|
103
104
|
self._element_limit: int = element_limit
|
|
104
105
|
|
|
105
|
-
self.all_definitions: set[Definition[
|
|
106
|
+
self.all_definitions: set[Definition[Any]] = set() if all_definitions is None else all_definitions
|
|
106
107
|
|
|
107
108
|
self.heap_allocator = heap_allocator or HeapAllocator(canonical_size)
|
|
108
109
|
self._environment: Environment = environment or Environment()
|
|
109
110
|
|
|
110
|
-
self.codeloc_uses: set[Definition[
|
|
111
|
+
self.codeloc_uses: set[Definition[Any]] = set()
|
|
111
112
|
|
|
112
113
|
# have we observed an exit statement or not during the analysis of the *last instruction* of a block? we should
|
|
113
114
|
# not perform any sp updates if it is the case. this is for handling conditional returns in ARM binaries.
|
|
@@ -184,7 +185,7 @@ class ReachingDefinitionsState:
|
|
|
184
185
|
return n - 2**self.arch.bits
|
|
185
186
|
return n
|
|
186
187
|
|
|
187
|
-
def annotate_with_def(self, symvar:
|
|
188
|
+
def annotate_with_def(self, symvar: MVType, definition: Definition[Any]) -> MVType:
|
|
188
189
|
"""
|
|
189
190
|
|
|
190
191
|
:param symvar:
|
|
@@ -193,14 +194,14 @@ class ReachingDefinitionsState:
|
|
|
193
194
|
"""
|
|
194
195
|
return self.live_definitions.annotate_with_def(symvar, definition)
|
|
195
196
|
|
|
196
|
-
def annotate_mv_with_def(self, mv: MultiValues, definition: Definition[A]) -> MultiValues:
|
|
197
|
+
def annotate_mv_with_def(self, mv: MultiValues[MVType], definition: Definition[A]) -> MultiValues[MVType]:
|
|
197
198
|
return MultiValues(
|
|
198
199
|
offset_to_values={
|
|
199
200
|
offset: {self.annotate_with_def(value, definition) for value in values} for offset, values in mv.items()
|
|
200
201
|
}
|
|
201
202
|
)
|
|
202
203
|
|
|
203
|
-
def extract_defs(self, symvar: claripy.ast.Base) -> Iterator[Definition[
|
|
204
|
+
def extract_defs(self, symvar: claripy.ast.Base) -> Iterator[Definition[Any]]:
|
|
204
205
|
yield from self.live_definitions.extract_defs(symvar)
|
|
205
206
|
|
|
206
207
|
#
|
|
@@ -254,7 +255,7 @@ class ReachingDefinitionsState:
|
|
|
254
255
|
def get_sp(self) -> int:
|
|
255
256
|
return self.live_definitions.get_sp()
|
|
256
257
|
|
|
257
|
-
def get_stack_address(self, offset: claripy.ast.Base) -> int:
|
|
258
|
+
def get_stack_address(self, offset: claripy.ast.Base) -> int | None:
|
|
258
259
|
return self.live_definitions.get_stack_address(offset)
|
|
259
260
|
|
|
260
261
|
@property
|
|
@@ -300,8 +301,8 @@ class ReachingDefinitionsState:
|
|
|
300
301
|
|
|
301
302
|
return self
|
|
302
303
|
|
|
303
|
-
def copy(self, discard_tmpdefs=False) ->
|
|
304
|
-
return
|
|
304
|
+
def copy(self, discard_tmpdefs=False) -> Self:
|
|
305
|
+
return type(self)(
|
|
305
306
|
self.codeloc,
|
|
306
307
|
self.arch,
|
|
307
308
|
self._subject,
|
|
@@ -317,9 +318,8 @@ class ReachingDefinitionsState:
|
|
|
317
318
|
element_limit=self._element_limit,
|
|
318
319
|
)
|
|
319
320
|
|
|
320
|
-
def merge(self, *others) -> tuple[
|
|
321
|
+
def merge(self, *others: Self) -> tuple[Self, bool]:
|
|
321
322
|
state = self.copy()
|
|
322
|
-
others: Iterable[ReachingDefinitionsState]
|
|
323
323
|
|
|
324
324
|
state.live_definitions, merged_0 = state.live_definitions.merge(*[other.live_definitions for other in others])
|
|
325
325
|
state._environment, merged_1 = state.environment.merge(*[other.environment for other in others])
|
|
@@ -419,10 +419,12 @@ class ReachingDefinitionsState:
|
|
|
419
419
|
for def_ in defs:
|
|
420
420
|
if not def_.dummy:
|
|
421
421
|
self._dep_graph.add_edge(used, def_)
|
|
422
|
+
|
|
423
|
+
cfg = self.analysis.project.kb.cfgs.get_most_accurate()
|
|
422
424
|
self._dep_graph.add_dependencies_for_concrete_pointers_of(
|
|
423
425
|
values,
|
|
424
426
|
used,
|
|
425
|
-
|
|
427
|
+
cfg,
|
|
426
428
|
self.analysis.project.loader,
|
|
427
429
|
)
|
|
428
430
|
else:
|
|
@@ -491,7 +493,9 @@ class ReachingDefinitionsState:
|
|
|
491
493
|
self.codeloc_uses.add(definition)
|
|
492
494
|
self.live_definitions.add_memory_use_by_def(definition, self.codeloc, expr=expr)
|
|
493
495
|
|
|
494
|
-
def get_definitions(
|
|
496
|
+
def get_definitions(
|
|
497
|
+
self, atom: Atom | Definition[Atom] | Iterable[Atom] | Iterable[Definition[Atom]]
|
|
498
|
+
) -> set[Definition[Atom]]:
|
|
495
499
|
return self.live_definitions.get_definitions(atom)
|
|
496
500
|
|
|
497
501
|
def get_values(self, spec: A | Definition[A] | Iterable[A]) -> MultiValues | None:
|
|
@@ -503,13 +507,15 @@ class ReachingDefinitionsState:
|
|
|
503
507
|
return self.live_definitions.get_one_value(spec, strip_annotations=strip_annotations)
|
|
504
508
|
|
|
505
509
|
@overload
|
|
506
|
-
def get_concrete_value(self, spec:
|
|
510
|
+
def get_concrete_value(self, spec: Atom | Definition[Atom] | Iterable[Atom], cast_to: type[int]) -> int | None: ...
|
|
507
511
|
|
|
508
512
|
@overload
|
|
509
|
-
def get_concrete_value(
|
|
513
|
+
def get_concrete_value(
|
|
514
|
+
self, spec: Atom | Definition[Atom] | Iterable[Atom], cast_to: type[bytes]
|
|
515
|
+
) -> bytes | None: ...
|
|
510
516
|
|
|
511
517
|
def get_concrete_value(
|
|
512
|
-
self, spec:
|
|
518
|
+
self, spec: Atom | Definition[Atom] | Iterable[Atom], cast_to: type[int] | type[bytes] = int
|
|
513
519
|
) -> int | bytes | None:
|
|
514
520
|
return self.live_definitions.get_concrete_value(spec, cast_to)
|
|
515
521
|
|
|
@@ -551,11 +557,10 @@ class ReachingDefinitionsState:
|
|
|
551
557
|
return result
|
|
552
558
|
|
|
553
559
|
@deprecated("deref")
|
|
554
|
-
def pointer_to_atom(self, value: claripy.ast.
|
|
560
|
+
def pointer_to_atom(self, value: claripy.ast.BV, size: int, endness: str) -> MemoryLocation | None:
|
|
555
561
|
if self.is_top(value):
|
|
556
562
|
return None
|
|
557
563
|
|
|
558
|
-
# TODO this can be simplified with the walrus operator
|
|
559
564
|
stack_offset = self.get_stack_offset(value)
|
|
560
565
|
if stack_offset is not None:
|
|
561
566
|
addr = SpOffset(len(value), stack_offset)
|
|
@@ -564,7 +569,7 @@ class ReachingDefinitionsState:
|
|
|
564
569
|
if heap_offset is not None:
|
|
565
570
|
addr = HeapAddress(heap_offset)
|
|
566
571
|
elif value.op == "BVV":
|
|
567
|
-
addr = value.args[0]
|
|
572
|
+
addr = cast(int, value.args[0])
|
|
568
573
|
else:
|
|
569
574
|
# cannot resolve
|
|
570
575
|
return None
|
|
@@ -574,9 +579,9 @@ class ReachingDefinitionsState:
|
|
|
574
579
|
@overload
|
|
575
580
|
def deref(
|
|
576
581
|
self,
|
|
577
|
-
pointer: int | claripy.ast.
|
|
582
|
+
pointer: int | claripy.ast.BV | HeapAddress | SpOffset,
|
|
578
583
|
size: int | DerefSize,
|
|
579
|
-
endness:
|
|
584
|
+
endness: archinfo.Endness = ...,
|
|
580
585
|
) -> MemoryLocation | None: ...
|
|
581
586
|
|
|
582
587
|
@overload
|
|
@@ -584,23 +589,23 @@ class ReachingDefinitionsState:
|
|
|
584
589
|
self,
|
|
585
590
|
pointer: MultiValues | A | Definition | Iterable[A] | Iterable[Definition[A]],
|
|
586
591
|
size: int | DerefSize,
|
|
587
|
-
endness:
|
|
592
|
+
endness: archinfo.Endness = ...,
|
|
588
593
|
) -> set[MemoryLocation]: ...
|
|
589
594
|
|
|
590
595
|
def deref(
|
|
591
596
|
self,
|
|
592
597
|
pointer: (
|
|
593
|
-
MultiValues
|
|
594
|
-
|
|
|
595
|
-
| Definition
|
|
596
|
-
| Iterable[
|
|
597
|
-
| Iterable[Definition[
|
|
598
|
+
MultiValues[claripy.ast.BV]
|
|
599
|
+
| Atom
|
|
600
|
+
| Definition[Atom]
|
|
601
|
+
| Iterable[Atom]
|
|
602
|
+
| Iterable[Definition[Atom]]
|
|
598
603
|
| int
|
|
599
604
|
| claripy.ast.BV
|
|
600
605
|
| HeapAddress
|
|
601
606
|
| SpOffset
|
|
602
607
|
),
|
|
603
608
|
size: int | DerefSize,
|
|
604
|
-
endness:
|
|
609
|
+
endness: archinfo.Endness = archinfo.Endness.BE,
|
|
605
610
|
):
|
|
606
611
|
return self.live_definitions.deref(pointer, size, endness)
|
angr/analyses/s_propagator.py
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
|
+
from collections.abc import Mapping
|
|
4
5
|
from collections import defaultdict
|
|
5
6
|
|
|
6
7
|
from ailment.block import Block
|
|
7
|
-
from ailment.expression import
|
|
8
|
+
from ailment.expression import (
|
|
9
|
+
Const,
|
|
10
|
+
VirtualVariable,
|
|
11
|
+
VirtualVariableCategory,
|
|
12
|
+
StackBaseOffset,
|
|
13
|
+
Load,
|
|
14
|
+
Convert,
|
|
15
|
+
Expression,
|
|
16
|
+
)
|
|
8
17
|
from ailment.statement import Assignment, Store, Return, Jump
|
|
9
18
|
|
|
10
19
|
from angr.knowledge_plugins.functions import Function
|
|
@@ -31,7 +40,7 @@ class SPropagatorModel:
|
|
|
31
40
|
"""
|
|
32
41
|
|
|
33
42
|
def __init__(self):
|
|
34
|
-
self.replacements = {}
|
|
43
|
+
self.replacements: Mapping[CodeLocation, Mapping[Expression, Expression]] = {}
|
|
35
44
|
|
|
36
45
|
|
|
37
46
|
class SPropagatorAnalysis(Analysis):
|
|
@@ -41,7 +50,7 @@ class SPropagatorAnalysis(Analysis):
|
|
|
41
50
|
|
|
42
51
|
def __init__( # pylint: disable=too-many-positional-arguments
|
|
43
52
|
self,
|
|
44
|
-
subject,
|
|
53
|
+
subject: Block | Function,
|
|
45
54
|
func_graph=None,
|
|
46
55
|
only_consts: bool = True,
|
|
47
56
|
immediate_stmt_removal: bool = False,
|
|
@@ -86,10 +95,13 @@ class SPropagatorAnalysis(Analysis):
|
|
|
86
95
|
return self.model.replacements
|
|
87
96
|
|
|
88
97
|
def _analyze(self):
|
|
98
|
+
blocks: dict[tuple[int, int | None], Block]
|
|
89
99
|
match self.mode:
|
|
90
100
|
case "block":
|
|
101
|
+
assert self.block is not None
|
|
91
102
|
blocks = {(self.block.addr, self.block.idx): self.block}
|
|
92
103
|
case "function":
|
|
104
|
+
assert self.func_graph is not None
|
|
93
105
|
blocks = {(block.addr, block.idx): block for block in self.func_graph}
|
|
94
106
|
case _:
|
|
95
107
|
raise NotImplementedError
|
|
@@ -120,11 +132,14 @@ class SPropagatorAnalysis(Analysis):
|
|
|
120
132
|
|
|
121
133
|
vvarid_to_vvar[vvar.varid] = vvar
|
|
122
134
|
defloc = vvar_deflocs[vvar]
|
|
135
|
+
assert defloc.block_addr is not None
|
|
136
|
+
assert defloc.stmt_idx is not None
|
|
123
137
|
block = blocks[(defloc.block_addr, defloc.block_idx)]
|
|
124
138
|
stmt = block.statements[defloc.stmt_idx]
|
|
125
139
|
r, v = is_const_assignment(stmt)
|
|
126
140
|
if r:
|
|
127
141
|
# replace wherever it's used
|
|
142
|
+
assert v is not None
|
|
128
143
|
const_vvars[vvar.varid] = v
|
|
129
144
|
for vvar_at_use, useloc in vvar_uselocs[vvar.varid]:
|
|
130
145
|
replacements[useloc][vvar_at_use] = v
|
|
@@ -214,16 +229,34 @@ class SPropagatorAnalysis(Analysis):
|
|
|
214
229
|
|
|
215
230
|
if self._sp_tracker is not None and vvar.category == VirtualVariableCategory.REGISTER:
|
|
216
231
|
if vvar.oident == self.project.arch.sp_offset:
|
|
232
|
+
sp_bits = (
|
|
233
|
+
(self.project.arch.registers["sp"][1] * self.project.arch.byte_width)
|
|
234
|
+
if "sp" in self.project.arch.registers
|
|
235
|
+
else None
|
|
236
|
+
)
|
|
217
237
|
for vvar_at_use, useloc in vvar_uselocs[vvar.varid]:
|
|
218
238
|
sb_offset = self._sp_tracker.offset_before(useloc.ins_addr, self.project.arch.sp_offset)
|
|
219
239
|
if sb_offset is not None:
|
|
220
|
-
|
|
240
|
+
v = StackBaseOffset(None, self.project.arch.bits, sb_offset)
|
|
241
|
+
if sp_bits is not None and vvar.bits < sp_bits:
|
|
242
|
+
# truncation needed
|
|
243
|
+
v = Convert(None, sp_bits, vvar.bits, False, v)
|
|
244
|
+
replacements[useloc][vvar_at_use] = v
|
|
221
245
|
continue
|
|
222
246
|
if not self._bp_as_gpr and vvar.oident == self.project.arch.bp_offset:
|
|
247
|
+
bp_bits = (
|
|
248
|
+
(self.project.arch.registers["bp"][1] * self.project.arch.byte_width)
|
|
249
|
+
if "bp" in self.project.arch.registers
|
|
250
|
+
else None
|
|
251
|
+
)
|
|
223
252
|
for vvar_at_use, useloc in vvar_uselocs[vvar.varid]:
|
|
224
253
|
sb_offset = self._sp_tracker.offset_before(useloc.ins_addr, self.project.arch.bp_offset)
|
|
225
254
|
if sb_offset is not None:
|
|
226
|
-
|
|
255
|
+
v = StackBaseOffset(None, self.project.arch.bits, sb_offset)
|
|
256
|
+
if bp_bits is not None and vvar.bits < bp_bits:
|
|
257
|
+
# truncation needed
|
|
258
|
+
v = Convert(None, bp_bits, vvar.bits, False, v)
|
|
259
|
+
replacements[useloc][vvar_at_use] = v
|
|
227
260
|
continue
|
|
228
261
|
|
|
229
262
|
# find all tmp definitions
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from ailment.block import Block
|
|
4
4
|
from ailment.statement import Assignment, Call, Return
|
|
5
|
+
import networkx
|
|
5
6
|
|
|
6
7
|
from angr.knowledge_plugins.functions import Function
|
|
7
8
|
from angr.knowledge_plugins.key_definitions.constants import ObservationPointType
|
|
@@ -22,9 +23,8 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
22
23
|
self,
|
|
23
24
|
subject,
|
|
24
25
|
func_addr: int | None = None,
|
|
25
|
-
func_graph=None,
|
|
26
|
+
func_graph: networkx.DiGraph[Block] | None = None,
|
|
26
27
|
track_tmps: bool = False,
|
|
27
|
-
stack_pointer_tracker=None,
|
|
28
28
|
):
|
|
29
29
|
if isinstance(subject, Block):
|
|
30
30
|
self.block = subject
|
|
@@ -40,7 +40,6 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
40
40
|
self.func_graph = func_graph
|
|
41
41
|
self.func_addr = func_addr if func_addr is not None else self.func.addr if self.func is not None else None
|
|
42
42
|
self._track_tmps = track_tmps
|
|
43
|
-
self._sp_tracker = stack_pointer_tracker # FIXME: Is it still used?
|
|
44
43
|
|
|
45
44
|
self._bp_as_gpr = False
|
|
46
45
|
if self.func is not None:
|
|
@@ -53,8 +52,10 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
53
52
|
def _analyze(self):
|
|
54
53
|
match self.mode:
|
|
55
54
|
case "block":
|
|
55
|
+
assert self.block is not None
|
|
56
56
|
blocks = {(self.block.addr, self.block.idx): self.block}
|
|
57
57
|
case "function":
|
|
58
|
+
assert self.func_graph is not None
|
|
58
59
|
blocks = {(block.addr, block.idx): block for block in self.func_graph}
|
|
59
60
|
case _:
|
|
60
61
|
raise NotImplementedError
|
|
@@ -115,9 +116,10 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
115
116
|
stmt = block.statements[stmt_idx]
|
|
116
117
|
assert isinstance(stmt, (Call, Assignment, Return))
|
|
117
118
|
|
|
118
|
-
call
|
|
119
|
+
call = (
|
|
119
120
|
stmt if isinstance(stmt, Call) else stmt.src if isinstance(stmt, Assignment) else stmt.ret_exprs[0]
|
|
120
121
|
)
|
|
122
|
+
assert isinstance(call, Call)
|
|
121
123
|
if call.prototype is None:
|
|
122
124
|
# without knowing the prototype, we must conservatively add uses to all registers that are
|
|
123
125
|
# potentially used here
|
|
@@ -126,7 +128,9 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
126
128
|
else:
|
|
127
129
|
# just use all registers in the default calling convention because we don't know anything about
|
|
128
130
|
# the calling convention yet
|
|
129
|
-
|
|
131
|
+
cc_cls = default_cc(self.project.arch.name)
|
|
132
|
+
assert cc_cls is not None
|
|
133
|
+
cc = cc_cls(self.project.arch)
|
|
130
134
|
|
|
131
135
|
codeloc = CodeLocation(block_addr, stmt_idx, block_idx=block_idx, ins_addr=stmt.ins_addr)
|
|
132
136
|
arg_locs = cc.ARG_REGS
|
|
@@ -127,8 +127,8 @@ class SketchNode(SketchNodeBase):
|
|
|
127
127
|
|
|
128
128
|
def __init__(self, typevar: TypeVariable | DerivedTypeVariable):
|
|
129
129
|
self.typevar: TypeVariable | DerivedTypeVariable = typevar
|
|
130
|
-
self.upper_bound = TopType()
|
|
131
|
-
self.lower_bound = BottomType()
|
|
130
|
+
self.upper_bound: TypeConstant = TopType()
|
|
131
|
+
self.lower_bound: TypeConstant = BottomType()
|
|
132
132
|
|
|
133
133
|
def __repr__(self):
|
|
134
134
|
return f"{self.lower_bound} <: {self.typevar} <: {self.upper_bound}"
|
|
@@ -190,7 +190,11 @@ class Sketch:
|
|
|
190
190
|
for _, dst, data in self.graph.out_edges(node, data=True):
|
|
191
191
|
if "label" in data and data["label"] == label:
|
|
192
192
|
succs.append(dst)
|
|
193
|
-
|
|
193
|
+
if len(succs) > 1:
|
|
194
|
+
_l.warning(
|
|
195
|
+
"Multiple successors found for node %s with label %s. Picking the first one.", node, label
|
|
196
|
+
)
|
|
197
|
+
succs = succs[:1]
|
|
194
198
|
if not succs:
|
|
195
199
|
return None
|
|
196
200
|
node = succs[0]
|
|
@@ -198,7 +202,7 @@ class Sketch:
|
|
|
198
202
|
node = self.lookup(node.target)
|
|
199
203
|
return node
|
|
200
204
|
|
|
201
|
-
def add_edge(self, src: SketchNodeBase, dst: SketchNodeBase, label):
|
|
205
|
+
def add_edge(self, src: SketchNodeBase, dst: SketchNodeBase, label) -> None:
|
|
202
206
|
self.graph.add_edge(src, dst, label=label)
|
|
203
207
|
|
|
204
208
|
def add_constraint(self, constraint: TypeConstraint) -> None:
|
|
@@ -210,13 +214,15 @@ class Sketch:
|
|
|
210
214
|
if SimpleSolver._typevar_inside_set(subtype, PRIMITIVE_TYPES) and not SimpleSolver._typevar_inside_set(
|
|
211
215
|
supertype, PRIMITIVE_TYPES
|
|
212
216
|
):
|
|
213
|
-
super_node
|
|
217
|
+
super_node = self.lookup(supertype)
|
|
218
|
+
assert super_node is None or isinstance(super_node, SketchNode)
|
|
214
219
|
if super_node is not None:
|
|
215
220
|
super_node.lower_bound = self.solver.join(super_node.lower_bound, subtype)
|
|
216
221
|
elif SimpleSolver._typevar_inside_set(supertype, PRIMITIVE_TYPES) and not SimpleSolver._typevar_inside_set(
|
|
217
222
|
subtype, PRIMITIVE_TYPES
|
|
218
223
|
):
|
|
219
|
-
sub_node
|
|
224
|
+
sub_node = self.lookup(subtype)
|
|
225
|
+
assert sub_node is None or isinstance(sub_node, SketchNode)
|
|
220
226
|
# assert sub_node is not None
|
|
221
227
|
if sub_node is not None:
|
|
222
228
|
sub_node.upper_bound = self.solver.meet(sub_node.upper_bound, supertype)
|
|
@@ -1166,7 +1172,10 @@ class SimpleSolver:
|
|
|
1166
1172
|
for labels, succ in path_and_successors:
|
|
1167
1173
|
last_label = labels[-1] if labels else None
|
|
1168
1174
|
if isinstance(last_label, HasField):
|
|
1169
|
-
|
|
1175
|
+
# TODO: Really determine the maximum possible size of the field when MAX_POINTSTO_BITS is in use
|
|
1176
|
+
candidate_bases[last_label.offset].add(
|
|
1177
|
+
1 if last_label.bits == MAX_POINTSTO_BITS else (last_label.bits // 8)
|
|
1178
|
+
)
|
|
1170
1179
|
|
|
1171
1180
|
node_to_base = {}
|
|
1172
1181
|
|
|
@@ -151,6 +151,9 @@ class TypeTranslator:
|
|
|
151
151
|
def _translate_Int256(self, tc): # pylint:disable=unused-argument
|
|
152
152
|
return sim_type.SimTypeInt256(signed=False).with_arch(self.arch)
|
|
153
153
|
|
|
154
|
+
def _translate_Int512(self, tc): # pylint:disable=unused-argument
|
|
155
|
+
return sim_type.SimTypeInt512(signed=False).with_arch(self.arch)
|
|
156
|
+
|
|
154
157
|
def _translate_TypeVariableReference(self, tc):
|
|
155
158
|
if tc.typevar in self.translated:
|
|
156
159
|
return self.translated[tc.typevar]
|
|
@@ -190,6 +193,9 @@ class TypeTranslator:
|
|
|
190
193
|
def _translate_SimTypeInt256(self, st: sim_type.SimTypeChar) -> typeconsts.Int256:
|
|
191
194
|
return typeconsts.Int256()
|
|
192
195
|
|
|
196
|
+
def _translate_SimTypeInt512(self, st: sim_type.SimTypeChar) -> typeconsts.Int512:
|
|
197
|
+
return typeconsts.Int512()
|
|
198
|
+
|
|
193
199
|
def _translate_SimTypeInt(self, st: sim_type.SimTypeInt) -> typeconsts.Int32:
|
|
194
200
|
return typeconsts.Int32()
|
|
195
201
|
|
|
@@ -235,6 +241,7 @@ TypeConstHandlers = {
|
|
|
235
241
|
typeconsts.Int64: TypeTranslator._translate_Int64,
|
|
236
242
|
typeconsts.Int128: TypeTranslator._translate_Int128,
|
|
237
243
|
typeconsts.Int256: TypeTranslator._translate_Int256,
|
|
244
|
+
typeconsts.Int512: TypeTranslator._translate_Int512,
|
|
238
245
|
typeconsts.TypeVariableReference: TypeTranslator._translate_TypeVariableReference,
|
|
239
246
|
}
|
|
240
247
|
|
|
@@ -247,6 +254,7 @@ SimTypeHandlers = {
|
|
|
247
254
|
sim_type.SimTypeChar: TypeTranslator._translate_SimTypeChar,
|
|
248
255
|
sim_type.SimTypeInt128: TypeTranslator._translate_SimTypeInt128,
|
|
249
256
|
sim_type.SimTypeInt256: TypeTranslator._translate_SimTypeInt256,
|
|
257
|
+
sim_type.SimTypeInt512: TypeTranslator._translate_SimTypeInt512,
|
|
250
258
|
sim_type.SimStruct: TypeTranslator._translate_SimStruct,
|
|
251
259
|
sim_type.SimTypeArray: TypeTranslator._translate_SimTypeArray,
|
|
252
260
|
}
|
|
@@ -107,6 +107,13 @@ class Int256(Int):
|
|
|
107
107
|
return "int256"
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
class Int512(Int):
|
|
111
|
+
SIZE = 32
|
|
112
|
+
|
|
113
|
+
def __repr__(self, memo=None):
|
|
114
|
+
return "int512"
|
|
115
|
+
|
|
116
|
+
|
|
110
117
|
class FloatBase(TypeConstant):
|
|
111
118
|
def __repr__(self, memo=None):
|
|
112
119
|
return "floatbase"
|
|
@@ -281,7 +288,7 @@ class TypeVariableReference(TypeConstant):
|
|
|
281
288
|
#
|
|
282
289
|
|
|
283
290
|
|
|
284
|
-
def int_type(bits: int) -> Int
|
|
291
|
+
def int_type(bits: int) -> Int:
|
|
285
292
|
mapping = {
|
|
286
293
|
1: Int1,
|
|
287
294
|
8: Int8,
|
|
@@ -290,10 +297,11 @@ def int_type(bits: int) -> Int | None:
|
|
|
290
297
|
64: Int64,
|
|
291
298
|
128: Int128,
|
|
292
299
|
256: Int256,
|
|
300
|
+
512: Int512,
|
|
293
301
|
}
|
|
294
302
|
if bits in mapping:
|
|
295
303
|
return mapping[bits]()
|
|
296
|
-
|
|
304
|
+
raise TypeError(f"Not a known size of int: {bits}")
|
|
297
305
|
|
|
298
306
|
|
|
299
307
|
def float_type(bits: int) -> FloatBase | None:
|
|
@@ -103,8 +103,11 @@ class Typehoon(Analysis):
|
|
|
103
103
|
print(f"### {sum(map(len, self._constraints.values()))} constraints")
|
|
104
104
|
for func_var in self._constraints:
|
|
105
105
|
print(f"{func_var}:")
|
|
106
|
+
lst = []
|
|
106
107
|
for constraint in self._constraints[func_var]:
|
|
107
|
-
|
|
108
|
+
lst.append(" " + constraint.pp_str(typevar_to_var))
|
|
109
|
+
lst = sorted(lst)
|
|
110
|
+
print("\n".join(lst))
|
|
108
111
|
print("### end of constraints ###")
|
|
109
112
|
|
|
110
113
|
def pp_solution(self) -> None:
|
|
@@ -316,12 +316,12 @@ class TypeVariable:
|
|
|
316
316
|
class DerivedTypeVariable(TypeVariable):
|
|
317
317
|
__slots__ = ("type_var", "labels")
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
labels: tuple[BaseLabel, ...]
|
|
320
320
|
|
|
321
321
|
def __init__(
|
|
322
322
|
self,
|
|
323
|
-
type_var:
|
|
324
|
-
label,
|
|
323
|
+
type_var: TypeType,
|
|
324
|
+
label: BaseLabel | None,
|
|
325
325
|
labels: Iterable[BaseLabel] | None = None,
|
|
326
326
|
idx=None,
|
|
327
327
|
):
|
|
@@ -339,8 +339,10 @@ class DerivedTypeVariable(TypeVariable):
|
|
|
339
339
|
|
|
340
340
|
if label is not None:
|
|
341
341
|
self.labels = (*existing_labels, label)
|
|
342
|
+
elif labels is not None:
|
|
343
|
+
self.labels = existing_labels + tuple(labels)
|
|
342
344
|
else:
|
|
343
|
-
self.labels
|
|
345
|
+
self.labels = existing_labels
|
|
344
346
|
|
|
345
347
|
if not self.labels:
|
|
346
348
|
raise ValueError("A DerivedTypeVariable must have at least one label")
|
|
@@ -350,10 +352,10 @@ class DerivedTypeVariable(TypeVariable):
|
|
|
350
352
|
def one_label(self) -> BaseLabel | None:
|
|
351
353
|
return self.labels[0] if len(self.labels) == 1 else None
|
|
352
354
|
|
|
353
|
-
def path(self) -> tuple[BaseLabel]:
|
|
355
|
+
def path(self) -> tuple[BaseLabel, ...]:
|
|
354
356
|
return self.labels
|
|
355
357
|
|
|
356
|
-
def longest_prefix(self) ->
|
|
358
|
+
def longest_prefix(self) -> TypeType | None:
|
|
357
359
|
if not self.labels:
|
|
358
360
|
return None
|
|
359
361
|
if len(self.labels) == 1:
|
|
@@ -418,7 +420,7 @@ class TypeVariables:
|
|
|
418
420
|
# )
|
|
419
421
|
return "{TypeVars: %d items}" % len(self._typevars)
|
|
420
422
|
|
|
421
|
-
def add_type_variable(self, var: SimVariable, codeloc, typevar:
|
|
423
|
+
def add_type_variable(self, var: SimVariable, codeloc, typevar: TypeType): # pylint:disable=unused-argument
|
|
422
424
|
if var not in self._typevars:
|
|
423
425
|
self._typevars[var] = set()
|
|
424
426
|
elif typevar in self._typevars[var]:
|