angr 9.2.134__py3-none-manylinux2014_aarch64.whl → 9.2.136__py3-none-manylinux2014_aarch64.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 +5 -8
- angr/analyses/analysis.py +4 -0
- angr/analyses/backward_slice.py +1 -2
- angr/analyses/binary_optimizer.py +3 -4
- angr/analyses/bindiff.py +4 -6
- angr/analyses/boyscout.py +1 -3
- angr/analyses/callee_cleanup_finder.py +4 -4
- angr/analyses/calling_convention/__init__.py +6 -0
- angr/analyses/{calling_convention.py → calling_convention/calling_convention.py} +32 -64
- angr/analyses/calling_convention/fact_collector.py +502 -0
- angr/analyses/calling_convention/utils.py +57 -0
- angr/analyses/cdg.py +1 -2
- angr/analyses/cfg/cfb.py +1 -3
- angr/analyses/cfg/cfg.py +2 -2
- angr/analyses/cfg/cfg_base.py +37 -35
- angr/analyses/cfg/cfg_emulated.py +1 -1
- angr/analyses/cfg/cfg_fast.py +62 -15
- angr/analyses/cfg/cfg_fast_soot.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +50 -14
- angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
- angr/analyses/complete_calling_conventions.py +32 -3
- angr/analyses/congruency_check.py +2 -3
- angr/analyses/data_dep/data_dependency_analysis.py +2 -2
- angr/analyses/ddg.py +1 -4
- angr/analyses/decompiler/ail_simplifier.py +3 -4
- angr/analyses/decompiler/clinic.py +42 -7
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +0 -6
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -7
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +0 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +0 -6
- angr/analyses/decompiler/structuring/phoenix.py +1 -1
- angr/analyses/disassembly.py +5 -5
- angr/analyses/fcp/__init__.py +4 -0
- angr/analyses/fcp/fcp.py +429 -0
- angr/analyses/identifier/identify.py +1 -3
- angr/analyses/loopfinder.py +4 -3
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/propagator/engine_base.py +4 -3
- angr/analyses/propagator/propagator.py +14 -53
- angr/analyses/reassembler.py +1 -2
- angr/analyses/s_propagator.py +1 -3
- angr/analyses/soot_class_hierarchy.py +1 -2
- angr/analyses/stack_pointer_tracker.py +18 -2
- angr/analyses/static_hooker.py +1 -2
- angr/analyses/typehoon/simple_solver.py +2 -2
- angr/analyses/variable_recovery/engine_vex.py +5 -0
- angr/analyses/variable_recovery/variable_recovery_fast.py +1 -2
- angr/analyses/veritesting.py +4 -7
- angr/analyses/vfg.py +1 -1
- angr/analyses/vsa_ddg.py +1 -2
- angr/block.py +3 -2
- angr/callable.py +1 -3
- angr/calling_conventions.py +15 -7
- angr/codenode.py +5 -1
- angr/concretization_strategies/__init__.py +1 -83
- angr/concretization_strategies/any.py +2 -1
- angr/concretization_strategies/any_named.py +1 -1
- angr/concretization_strategies/base.py +81 -0
- angr/concretization_strategies/controlled_data.py +2 -1
- angr/concretization_strategies/eval.py +2 -1
- angr/concretization_strategies/logging.py +3 -1
- angr/concretization_strategies/max.py +2 -1
- angr/concretization_strategies/nonzero.py +2 -1
- angr/concretization_strategies/nonzero_range.py +2 -1
- angr/concretization_strategies/norepeats.py +2 -1
- angr/concretization_strategies/norepeats_range.py +2 -1
- angr/concretization_strategies/range.py +2 -1
- angr/concretization_strategies/signed_add.py +2 -1
- angr/concretization_strategies/single.py +2 -1
- angr/concretization_strategies/solutions.py +2 -1
- angr/concretization_strategies/unlimited_range.py +2 -1
- angr/engines/__init__.py +8 -5
- angr/engines/engine.py +3 -5
- angr/engines/failure.py +4 -5
- angr/engines/procedure.py +5 -7
- angr/engines/soot/expressions/__init__.py +22 -23
- angr/engines/soot/expressions/base.py +4 -4
- angr/engines/soot/expressions/invoke.py +1 -2
- angr/engines/soot/statements/__init__.py +9 -10
- angr/engines/soot/values/__init__.py +9 -10
- angr/engines/soot/values/arrayref.py +3 -3
- angr/engines/soot/values/instancefieldref.py +3 -2
- angr/engines/successors.py +7 -6
- angr/engines/syscall.py +4 -6
- angr/engines/unicorn.py +3 -2
- angr/engines/vex/claripy/ccall.py +8 -10
- angr/engines/vex/claripy/datalayer.py +4 -5
- angr/exploration_techniques/__init__.py +0 -2
- angr/exploration_techniques/spiller.py +1 -3
- angr/exploration_techniques/stochastic.py +2 -3
- angr/factory.py +3 -9
- angr/knowledge_plugins/cfg/cfg_model.py +20 -17
- angr/knowledge_plugins/functions/function.py +74 -77
- angr/knowledge_plugins/functions/function_manager.py +14 -7
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +16 -16
- angr/knowledge_plugins/propagations/propagation_model.py +4 -5
- angr/knowledge_plugins/propagations/states.py +0 -511
- angr/procedures/libc/memcpy.py +4 -4
- angr/procedures/procedure_dict.py +3 -2
- angr/protos/__init__.py +2 -5
- angr/protos/cfg_pb2.py +21 -18
- angr/protos/function_pb2.py +17 -14
- angr/protos/primitives_pb2.py +44 -39
- angr/protos/variables_pb2.py +36 -31
- angr/protos/xrefs_pb2.py +15 -12
- angr/sim_procedure.py +15 -16
- angr/sim_variable.py +13 -1
- angr/simos/__init__.py +2 -0
- angr/simos/javavm.py +4 -6
- angr/simos/xbox.py +32 -0
- angr/state_plugins/__init__.py +0 -2
- angr/state_plugins/callstack.py +4 -4
- angr/state_plugins/cgc.py +3 -2
- angr/state_plugins/gdb.py +6 -5
- angr/state_plugins/globals.py +1 -2
- angr/state_plugins/heap/heap_brk.py +1 -2
- angr/state_plugins/history.py +10 -12
- angr/state_plugins/inspect.py +3 -5
- angr/state_plugins/libc.py +2 -2
- angr/state_plugins/log.py +8 -10
- angr/state_plugins/loop_data.py +1 -2
- angr/state_plugins/posix.py +7 -7
- angr/state_plugins/preconstrainer.py +2 -3
- angr/state_plugins/scratch.py +5 -8
- angr/state_plugins/sim_action.py +3 -3
- angr/state_plugins/solver.py +8 -3
- angr/state_plugins/symbolizer.py +5 -4
- angr/state_plugins/uc_manager.py +3 -3
- angr/state_plugins/unicorn_engine.py +5 -1
- angr/state_plugins/view.py +3 -5
- angr/storage/file.py +3 -5
- angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
- angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
- angr/storage/memory_mixins/clouseau_mixin.py +1 -3
- angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
- angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
- angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
- angr/utils/bits.py +13 -0
- angr/utils/enums_conv.py +28 -12
- angr/utils/segment_list.py +25 -22
- angr/utils/timing.py +18 -1
- angr/vaults.py +5 -6
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/METADATA +6 -6
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/RECORD +168 -164
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/WHEEL +1 -1
- angr/analyses/propagator/outdated_definition_walker.py +0 -159
- angr/analyses/propagator/tmpvar_finder.py +0 -18
- angr/engines/concrete.py +0 -180
- angr/exploration_techniques/symbion.py +0 -80
- angr/state_plugins/concrete.py +0 -295
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/LICENSE +0 -0
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/entry_points.txt +0 -0
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,7 @@ class PropagatorLoadCallback:
|
|
|
10
10
|
def __init__(self, project):
|
|
11
11
|
self.project = project
|
|
12
12
|
|
|
13
|
-
def propagator_load_callback(self, addr, size) -> bool: # pylint:disable=unused-argument
|
|
13
|
+
def propagator_load_callback(self, addr: claripy.ast.BV | int, size: int) -> bool: # pylint:disable=unused-argument
|
|
14
14
|
# only allow loading if the address falls into a read-only region
|
|
15
15
|
if isinstance(addr, claripy.ast.BV) and addr.op == "BVV":
|
|
16
16
|
addr_v = addr.args[0]
|
|
@@ -19,9 +19,28 @@ class PropagatorLoadCallback:
|
|
|
19
19
|
else:
|
|
20
20
|
return False
|
|
21
21
|
section = self.project.loader.find_section_containing(addr_v)
|
|
22
|
+
segment = None
|
|
22
23
|
if section is not None:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
if section.is_readable and not section.is_writable:
|
|
25
|
+
# read-only section
|
|
26
|
+
return True
|
|
27
|
+
else:
|
|
28
|
+
segment = self.project.loader.find_segment_containing(addr_v)
|
|
29
|
+
if segment is not None and segment.is_readable and not segment.is_writable:
|
|
30
|
+
# read-only segment
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
if (size == self.project.arch.bytes and (section is not None and section.is_readable)) or (
|
|
34
|
+
segment is not None and segment.is_readable
|
|
35
|
+
):
|
|
36
|
+
# memory is mapped and readable. does it contain a valid address?
|
|
37
|
+
try:
|
|
38
|
+
target_addr = self.project.loader.memory.unpack_word(
|
|
39
|
+
addr_v, size=size, endness=self.project.arch.memory_endness
|
|
40
|
+
)
|
|
41
|
+
if target_addr >= 0x1000 and self.project.loader.find_object_containing(target_addr) is not None:
|
|
42
|
+
return True
|
|
43
|
+
except KeyError:
|
|
44
|
+
return False
|
|
45
|
+
|
|
27
46
|
return False
|
|
@@ -3,7 +3,6 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
from capstone.x86_const import X86_OP_MEM
|
|
5
5
|
|
|
6
|
-
from angr.simos import SimWindows
|
|
7
6
|
from .resolver import IndirectJumpResolver
|
|
8
7
|
|
|
9
8
|
l = logging.getLogger(name=__name__)
|
|
@@ -11,16 +10,14 @@ l = logging.getLogger(name=__name__)
|
|
|
11
10
|
|
|
12
11
|
class X86PeIatResolver(IndirectJumpResolver):
|
|
13
12
|
"""
|
|
14
|
-
A timeless indirect jump resolver for IAT in x86 PEs.
|
|
13
|
+
A timeless indirect jump resolver for IAT in x86 PEs and xbes.
|
|
15
14
|
"""
|
|
16
15
|
|
|
17
16
|
def __init__(self, project):
|
|
18
17
|
super().__init__(project, timeless=True)
|
|
19
18
|
|
|
20
19
|
def filter(self, cfg, addr, func_addr, block, jumpkind):
|
|
21
|
-
if not
|
|
22
|
-
return False
|
|
23
|
-
if jumpkind != "Ijk_Call":
|
|
20
|
+
if jumpkind not in {"Ijk_Call", "Ijk_Boring"}: # both call and jmp
|
|
24
21
|
return False
|
|
25
22
|
|
|
26
23
|
insns = self.project.factory.block(addr).capstone.insns
|
|
@@ -7,6 +7,7 @@ import threading
|
|
|
7
7
|
import time
|
|
8
8
|
import logging
|
|
9
9
|
from collections import defaultdict
|
|
10
|
+
from enum import Enum
|
|
10
11
|
|
|
11
12
|
import networkx
|
|
12
13
|
|
|
@@ -16,7 +17,7 @@ from angr.utils.graph import GraphUtils
|
|
|
16
17
|
from angr.simos import SimWindows
|
|
17
18
|
from angr.utils.mp import mp_context, Initializer
|
|
18
19
|
from angr.knowledge_plugins.cfg import CFGModel
|
|
19
|
-
from . import Analysis, register_analysis, VariableRecoveryFast, CallingConventionAnalysis
|
|
20
|
+
from . import Analysis, register_analysis, VariableRecoveryFast, CallingConventionAnalysis, FactCollector
|
|
20
21
|
|
|
21
22
|
if TYPE_CHECKING:
|
|
22
23
|
from angr.calling_conventions import SimCC
|
|
@@ -30,6 +31,18 @@ _l = logging.getLogger(name=__name__)
|
|
|
30
31
|
_mp_context = mp_context()
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
class CallingConventionAnalysisMode(Enum):
|
|
35
|
+
"""
|
|
36
|
+
The mode of calling convention analysis.
|
|
37
|
+
|
|
38
|
+
FAST: Using FactCollector to collect facts, then use facts for calling convention analysis.
|
|
39
|
+
VARIABLES: Using variables in VariableManager for calling convention analysis.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
FAST = "fast"
|
|
43
|
+
VARIABLES = "variables"
|
|
44
|
+
|
|
45
|
+
|
|
33
46
|
class CompleteCallingConventionsAnalysis(Analysis):
|
|
34
47
|
"""
|
|
35
48
|
Implements full-binary calling convention analysis. During the initial analysis of a binary, you may set
|
|
@@ -39,6 +52,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
39
52
|
|
|
40
53
|
def __init__(
|
|
41
54
|
self,
|
|
55
|
+
mode: CallingConventionAnalysisMode = CallingConventionAnalysisMode.FAST,
|
|
42
56
|
recover_variables=False,
|
|
43
57
|
low_priority=False,
|
|
44
58
|
force=False,
|
|
@@ -71,6 +85,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
71
85
|
:param workers: Number of multiprocessing workers.
|
|
72
86
|
"""
|
|
73
87
|
|
|
88
|
+
self.mode = mode
|
|
74
89
|
self._recover_variables = recover_variables
|
|
75
90
|
self._low_priority = low_priority
|
|
76
91
|
self._force = force
|
|
@@ -88,6 +103,10 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
88
103
|
self._func_graphs = func_graphs if func_graphs else {}
|
|
89
104
|
self.prototype_libnames: set[str] = set()
|
|
90
105
|
|
|
106
|
+
# sanity check
|
|
107
|
+
if self.mode not in {CallingConventionAnalysisMode.FAST, CallingConventionAnalysisMode.VARIABLES}:
|
|
108
|
+
raise ValueError(f"Invalid calling convention analysis mode {self.mode}.")
|
|
109
|
+
|
|
91
110
|
self._func_addrs = [] # a list that holds addresses of all functions to be analyzed
|
|
92
111
|
self._results = []
|
|
93
112
|
if workers > 0:
|
|
@@ -322,7 +341,11 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
322
341
|
self.kb.variables.get_function_manager(func_addr),
|
|
323
342
|
)
|
|
324
343
|
|
|
325
|
-
if
|
|
344
|
+
if (
|
|
345
|
+
self.mode == CallingConventionAnalysisMode.VARIABLES
|
|
346
|
+
and self._recover_variables
|
|
347
|
+
and self.function_needs_variable_recovery(func)
|
|
348
|
+
):
|
|
326
349
|
# special case: we don't have a PCode-engine variable recovery analysis for PCode architectures!
|
|
327
350
|
if ":" in self.project.arch.name and self._func_graphs and func.addr in self._func_graphs:
|
|
328
351
|
# this is a pcode architecture
|
|
@@ -341,9 +364,15 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
341
364
|
)
|
|
342
365
|
return None, None, None, None
|
|
343
366
|
|
|
367
|
+
kwargs = {}
|
|
368
|
+
if self.mode == CallingConventionAnalysisMode.FAST:
|
|
369
|
+
facts = self.project.analyses[FactCollector].prep(kb=self.kb)(func)
|
|
370
|
+
kwargs["input_args"] = facts.input_args
|
|
371
|
+
kwargs["retval_size"] = facts.retval_size
|
|
372
|
+
|
|
344
373
|
# determine the calling convention of each function
|
|
345
374
|
cc_analysis = self.project.analyses[CallingConventionAnalysis].prep(kb=self.kb)(
|
|
346
|
-
func, cfg=self._cfg, analyze_callsites=self._analyze_callsites
|
|
375
|
+
func, cfg=self._cfg, analyze_callsites=self._analyze_callsites, **kwargs
|
|
347
376
|
)
|
|
348
377
|
|
|
349
378
|
if cc_analysis.cc is not None:
|
|
@@ -3,6 +3,8 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
import claripy
|
|
5
5
|
|
|
6
|
+
from angr.errors import AngrIncongruencyError
|
|
7
|
+
from angr.analyses import AnalysesHub
|
|
6
8
|
from . import Analysis
|
|
7
9
|
|
|
8
10
|
l = logging.getLogger(name=__name__)
|
|
@@ -372,7 +374,4 @@ class CongruencyCheck(Analysis):
|
|
|
372
374
|
return True
|
|
373
375
|
|
|
374
376
|
|
|
375
|
-
from angr.errors import AngrIncongruencyError
|
|
376
|
-
from angr.analyses import AnalysesHub
|
|
377
|
-
|
|
378
377
|
AnalysesHub.register_default("CongruencyCheck", CongruencyCheck)
|
|
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
|
|
|
9
9
|
from networkx import DiGraph
|
|
10
10
|
|
|
11
11
|
import claripy
|
|
12
|
-
from claripy.ast
|
|
12
|
+
from claripy.ast import BV
|
|
13
13
|
from .dep_nodes import DepNodeTypes, ConstantDepNode, MemDepNode, VarDepNode, RegDepNode, TmpDepNode
|
|
14
14
|
from .sim_act_location import SimActLocation, DEFAULT_LOCATION, ParsedInstruction
|
|
15
15
|
from angr.analyses import Analysis
|
|
@@ -173,7 +173,7 @@ class DataDependencyGraphAnalysis(Analysis):
|
|
|
173
173
|
self,
|
|
174
174
|
type_: int,
|
|
175
175
|
sim_act: SimActionData,
|
|
176
|
-
val: tuple[BV, int],
|
|
176
|
+
val: tuple[claripy.ast.BV, int],
|
|
177
177
|
*constructor_params,
|
|
178
178
|
) -> BaseDepNode:
|
|
179
179
|
"""
|
angr/analyses/ddg.py
CHANGED
|
@@ -6,8 +6,7 @@ import claripy
|
|
|
6
6
|
import networkx
|
|
7
7
|
import pyvex
|
|
8
8
|
|
|
9
|
-
from . import Analysis
|
|
10
|
-
|
|
9
|
+
from angr.analyses import Analysis, AnalysesHub
|
|
11
10
|
from angr.code_location import CodeLocation
|
|
12
11
|
from angr.errors import SimSolverModeError, SimUnsatError, AngrDDGError
|
|
13
12
|
from angr.sim_variable import (
|
|
@@ -1668,6 +1667,4 @@ class DDG(Analysis):
|
|
|
1668
1667
|
return sources
|
|
1669
1668
|
|
|
1670
1669
|
|
|
1671
|
-
from angr.analyses import AnalysesHub
|
|
1672
|
-
|
|
1673
1670
|
AnalysesHub.register_default("DDG", DDG)
|
|
@@ -216,7 +216,7 @@ class AILSimplifier(Analysis):
|
|
|
216
216
|
self._reaching_definitions = rd
|
|
217
217
|
return rd
|
|
218
218
|
|
|
219
|
-
def _compute_propagation(self
|
|
219
|
+
def _compute_propagation(self) -> SPropagatorAnalysis:
|
|
220
220
|
# Propagate expressions or return the existing result
|
|
221
221
|
if self._propagator is not None:
|
|
222
222
|
return self._propagator
|
|
@@ -225,7 +225,6 @@ class AILSimplifier(Analysis):
|
|
|
225
225
|
func_graph=self.func_graph,
|
|
226
226
|
# gp=self._gp,
|
|
227
227
|
only_consts=self._only_consts,
|
|
228
|
-
immediate_stmt_removal=immediate_stmt_removal,
|
|
229
228
|
)
|
|
230
229
|
self._propagator = prop
|
|
231
230
|
return prop
|
|
@@ -354,7 +353,7 @@ class AILSimplifier(Analysis):
|
|
|
354
353
|
):
|
|
355
354
|
repeat = False
|
|
356
355
|
narrowable_phivarids = set()
|
|
357
|
-
for def_vvarid
|
|
356
|
+
for def_vvarid in narrowing_candidates:
|
|
358
357
|
if def_vvarid in blacklist_varids:
|
|
359
358
|
continue
|
|
360
359
|
if def_vvarid in rd.phi_vvar_ids:
|
|
@@ -591,7 +590,7 @@ class AILSimplifier(Analysis):
|
|
|
591
590
|
"""
|
|
592
591
|
|
|
593
592
|
# propagator
|
|
594
|
-
propagator = self._compute_propagation(
|
|
593
|
+
propagator = self._compute_propagation()
|
|
595
594
|
replacements = propagator.replacements
|
|
596
595
|
|
|
597
596
|
# take replacements and rebuild the corresponding blocks
|
|
@@ -527,6 +527,9 @@ class Clinic(Analysis):
|
|
|
527
527
|
# TODO: Totally remove this dict
|
|
528
528
|
self._blocks_by_addr_and_size = None
|
|
529
529
|
|
|
530
|
+
# Rust-specific; only call this on Rust binaries when we can identify language and compiler
|
|
531
|
+
ail_graph = self._rewrite_rust_probestack_call(ail_graph)
|
|
532
|
+
|
|
530
533
|
# Make call-sites
|
|
531
534
|
self._update_progress(50.0, text="Making callsites")
|
|
532
535
|
_, stackarg_offsets, removed_vvar_ids = self._make_callsites(ail_graph, stack_pointer_tracker=spt)
|
|
@@ -1010,13 +1013,15 @@ class Clinic(Analysis):
|
|
|
1010
1013
|
if node is None:
|
|
1011
1014
|
continue
|
|
1012
1015
|
successors = self._cfg.get_successors(node, excluding_fakeret=True, jumpkind="Ijk_Call")
|
|
1013
|
-
if len(successors) == 1
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1016
|
+
if len(successors) == 1:
|
|
1017
|
+
succ_addr = successors[0].addr
|
|
1018
|
+
if not self.project.is_hooked(succ_addr) or not isinstance(
|
|
1019
|
+
self.project.hooked_by(successors[0].addr), UnresolvableCallTarget
|
|
1020
|
+
):
|
|
1021
|
+
# found a single successor - replace the last statement
|
|
1022
|
+
new_last_stmt = last_stmt.copy()
|
|
1023
|
+
new_last_stmt.target = ailment.Expr.Const(None, None, successors[0].addr, last_stmt.target.bits)
|
|
1024
|
+
block.statements[-1] = new_last_stmt
|
|
1020
1025
|
|
|
1021
1026
|
elif isinstance(last_stmt, ailment.Stmt.Jump) and not isinstance(last_stmt.target, ailment.Expr.Const):
|
|
1022
1027
|
# indirect jump
|
|
@@ -2732,6 +2737,36 @@ class Clinic(Analysis):
|
|
|
2732
2737
|
|
|
2733
2738
|
return extra_regs
|
|
2734
2739
|
|
|
2740
|
+
def _rewrite_rust_probestack_call(self, ail_graph):
|
|
2741
|
+
for node in ail_graph:
|
|
2742
|
+
if not node.statements or ail_graph.out_degree[node] != 1:
|
|
2743
|
+
continue
|
|
2744
|
+
last_stmt = node.statements[-1]
|
|
2745
|
+
if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
|
|
2746
|
+
func = (
|
|
2747
|
+
self.project.kb.functions.get_by_addr(last_stmt.target.value)
|
|
2748
|
+
if self.project.kb.functions.contains_addr(last_stmt.target.value)
|
|
2749
|
+
else None
|
|
2750
|
+
)
|
|
2751
|
+
if func is not None and func.info.get("is_rust_probestack", False) is True:
|
|
2752
|
+
# get rid of this call
|
|
2753
|
+
node.statements = node.statements[:-1]
|
|
2754
|
+
if self.project.arch.call_pushes_ret and node.statements:
|
|
2755
|
+
last_stmt = node.statements[-1]
|
|
2756
|
+
succ = next(iter(ail_graph.successors(node)))
|
|
2757
|
+
if (
|
|
2758
|
+
isinstance(last_stmt, ailment.Stmt.Store)
|
|
2759
|
+
and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
|
|
2760
|
+
and isinstance(last_stmt.addr.offset, int)
|
|
2761
|
+
and last_stmt.addr.offset < 0
|
|
2762
|
+
and isinstance(last_stmt.data, ailment.Expr.Const)
|
|
2763
|
+
and last_stmt.data.value == succ.addr
|
|
2764
|
+
):
|
|
2765
|
+
# remove the statement that pushes the return address
|
|
2766
|
+
node.statements = node.statements[:-1]
|
|
2767
|
+
break
|
|
2768
|
+
return ail_graph
|
|
2769
|
+
|
|
2735
2770
|
def _rewrite_alloca(self, ail_graph):
|
|
2736
2771
|
# pylint:disable=too-many-boolean-expressions
|
|
2737
2772
|
alloca_node = None
|
|
@@ -304,7 +304,7 @@ class AILMergeGraph:
|
|
|
304
304
|
end_pair_map = {}
|
|
305
305
|
end_pairs = set()
|
|
306
306
|
merge_to_end_pair = {}
|
|
307
|
-
for
|
|
307
|
+
for sblocks in self.merge_blocks_to_originals.values():
|
|
308
308
|
for sblock in sblocks:
|
|
309
309
|
if isinstance(sblock, AILBlockSplit) and sblock.original in self.merge_blocks_to_originals:
|
|
310
310
|
deletable_blocks.add(sblock.original)
|
|
@@ -429,7 +429,7 @@ class AILMergeGraph:
|
|
|
429
429
|
self.original_split_blocks[updated] = self.original_split_blocks[k]
|
|
430
430
|
del self.original_split_blocks[k]
|
|
431
431
|
|
|
432
|
-
for
|
|
432
|
+
for v in self.original_split_blocks.values():
|
|
433
433
|
for sblock in v:
|
|
434
434
|
for attr in ["up_split", "match_split", "down_split"]:
|
|
435
435
|
if getattr(sblock, attr) == original:
|
|
@@ -167,7 +167,7 @@ class DuplicationReverter(StructuringOptimizationPass):
|
|
|
167
167
|
|
|
168
168
|
def _reinsert_merged_candidate(self, ail_merge_graph: AILMergeGraph, candidate: tuple[Block, Block]) -> bool:
|
|
169
169
|
og_succs, og_preds = {}, {}
|
|
170
|
-
for
|
|
170
|
+
for original_blocks in ail_merge_graph.original_blocks.values():
|
|
171
171
|
# collect all the old edges
|
|
172
172
|
for og_block in original_blocks:
|
|
173
173
|
og_succs[og_block] = list(self.write_graph.successors(og_block))
|
|
@@ -364,7 +364,7 @@ class DuplicationReverter(StructuringOptimizationPass):
|
|
|
364
364
|
new_nodes[node] = new_node
|
|
365
365
|
|
|
366
366
|
# fixup every single jump target (before adding them to the graph)
|
|
367
|
-
for src, dst
|
|
367
|
+
for src, dst in graph.edges():
|
|
368
368
|
new_src = new_nodes[src]
|
|
369
369
|
new_dst = new_nodes[dst]
|
|
370
370
|
if new_dst is not dst:
|
|
@@ -263,7 +263,7 @@ class ITERegionConverter(OptimizationPass):
|
|
|
263
263
|
|
|
264
264
|
# is this the statement that we are looking for?
|
|
265
265
|
found_true_src_vvar, found_false_src_vvar = False, False
|
|
266
|
-
for
|
|
266
|
+
for _src, vvar in stmt.src.src_and_vvars:
|
|
267
267
|
if vvar is not None:
|
|
268
268
|
if vvar.varid == true_stmt_dst.varid:
|
|
269
269
|
found_true_src_vvar = True
|
|
@@ -557,7 +557,7 @@ class LoweredSwitchSimplifier(StructuringOptimizationPass):
|
|
|
557
557
|
varhash_to_caselists[v].append((cases, extra_cmp_nodes))
|
|
558
558
|
|
|
559
559
|
for v, caselists in list(varhash_to_caselists.items()):
|
|
560
|
-
for idx, (cases,
|
|
560
|
+
for idx, (cases, _redundant_nodes) in list(enumerate(caselists)):
|
|
561
561
|
# filter: each case value should only appear once
|
|
562
562
|
if len({case.value for case in cases}) != len(cases):
|
|
563
563
|
caselists[idx] = None
|
|
@@ -13,12 +13,6 @@ from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
|
13
13
|
_l = logging.getLogger(name=__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def s2u(s, bits):
|
|
17
|
-
if s > 0:
|
|
18
|
-
return s
|
|
19
|
-
return (1 << bits) + s
|
|
20
|
-
|
|
21
|
-
|
|
22
16
|
class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
23
17
|
"""
|
|
24
18
|
Optimizes away register spilling effects, including callee-saved registers.
|
|
@@ -5,18 +5,13 @@ import logging
|
|
|
5
5
|
|
|
6
6
|
import ailment
|
|
7
7
|
|
|
8
|
+
from angr.utils.bits import s2u
|
|
8
9
|
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
_l = logging.getLogger(name=__name__)
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
def s2u(s, bits):
|
|
15
|
-
if s > 0:
|
|
16
|
-
return s
|
|
17
|
-
return (1 << bits) + s
|
|
18
|
-
|
|
19
|
-
|
|
20
15
|
class StackCanarySimplifier(OptimizationPass):
|
|
21
16
|
"""
|
|
22
17
|
Removes stack canary checks from decompilation results.
|
|
@@ -149,7 +144,7 @@ class StackCanarySimplifier(OptimizationPass):
|
|
|
149
144
|
nodes_to_process.append((pred, canary_check_stmt_idx, stack_chk_fail_caller, ret_node))
|
|
150
145
|
|
|
151
146
|
# Awesome. Now patch this function.
|
|
152
|
-
for pred,
|
|
147
|
+
for pred, _canary_check_stmt_idx, stack_chk_fail_caller, ret_node in nodes_to_process:
|
|
153
148
|
# Patch the pred so that it jumps to the one that is not stack_chk_fail_caller
|
|
154
149
|
pred_copy = pred.copy()
|
|
155
150
|
pred_copy.statements[-1] = ailment.Stmt.Jump(
|
|
@@ -17,12 +17,6 @@ from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
|
17
17
|
_l = logging.getLogger(name=__name__)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def s2u(s, bits):
|
|
21
|
-
if s > 0:
|
|
22
|
-
return s
|
|
23
|
-
return (1 << bits) + s
|
|
24
|
-
|
|
25
|
-
|
|
26
20
|
class SwitchDefaultCaseDuplicator(OptimizationPass):
|
|
27
21
|
"""
|
|
28
22
|
For each switch-case construct (identified by jump tables), duplicate the default-case node when we detect
|
|
@@ -13,12 +13,6 @@ from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
|
13
13
|
_l = logging.getLogger(name=__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def s2u(s, bits):
|
|
17
|
-
if s > 0:
|
|
18
|
-
return s
|
|
19
|
-
return (1 << bits) + s
|
|
20
|
-
|
|
21
|
-
|
|
22
16
|
class WinStackCanarySimplifier(OptimizationPass):
|
|
23
17
|
"""
|
|
24
18
|
Removes stack canary checks from decompilation results for Windows PE files.
|
|
@@ -1536,7 +1536,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1536
1536
|
full_graph.remove_edge(head, out_dst)
|
|
1537
1537
|
|
|
1538
1538
|
# fix full_graph if needed: remove successors that are no longer needed
|
|
1539
|
-
for
|
|
1539
|
+
for _out_src, out_dst in out_edges[1:]:
|
|
1540
1540
|
if out_dst in full_graph and out_dst not in graph and full_graph.in_degree[out_dst] == 0:
|
|
1541
1541
|
full_graph.remove_node(out_dst)
|
|
1542
1542
|
if out_dst in self._region.successors:
|
angr/analyses/disassembly.py
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
2
4
|
import logging
|
|
3
5
|
from collections import defaultdict
|
|
4
|
-
from typing import Union, Any
|
|
5
6
|
from collections.abc import Sequence
|
|
7
|
+
from typing import Union, Any
|
|
6
8
|
|
|
7
9
|
import pyvex
|
|
8
10
|
import archinfo
|
|
9
|
-
from angr.knowledge_plugins import Function
|
|
10
11
|
|
|
11
12
|
from . import Analysis
|
|
12
13
|
|
|
14
|
+
from angr.analyses import AnalysesHub
|
|
13
15
|
from angr.errors import AngrTypeError
|
|
16
|
+
from angr.knowledge_plugins import Function
|
|
14
17
|
from angr.utils.library import get_cpp_function_name
|
|
15
18
|
from angr.utils.formatting import ansi_color_enabled, ansi_color, add_edge_to_buffer
|
|
16
19
|
from angr.block import DisassemblerInsn, CapstoneInsn, SootBlockNode
|
|
17
20
|
from angr.codenode import BlockNode
|
|
18
21
|
from .disassembly_utils import decode_instruction
|
|
19
|
-
import contextlib
|
|
20
22
|
|
|
21
23
|
try:
|
|
22
24
|
from angr.engines import pcode
|
|
@@ -1295,6 +1297,4 @@ class Disassembly(Analysis):
|
|
|
1295
1297
|
return "\n".join(buf)
|
|
1296
1298
|
|
|
1297
1299
|
|
|
1298
|
-
from angr.analyses import AnalysesHub
|
|
1299
|
-
|
|
1300
1300
|
AnalysesHub.register_default("Disassembly", Disassembly)
|