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.

Files changed (173) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +5 -8
  3. angr/analyses/analysis.py +4 -0
  4. angr/analyses/backward_slice.py +1 -2
  5. angr/analyses/binary_optimizer.py +3 -4
  6. angr/analyses/bindiff.py +4 -6
  7. angr/analyses/boyscout.py +1 -3
  8. angr/analyses/callee_cleanup_finder.py +4 -4
  9. angr/analyses/calling_convention/__init__.py +6 -0
  10. angr/analyses/{calling_convention.py → calling_convention/calling_convention.py} +32 -64
  11. angr/analyses/calling_convention/fact_collector.py +502 -0
  12. angr/analyses/calling_convention/utils.py +57 -0
  13. angr/analyses/cdg.py +1 -2
  14. angr/analyses/cfg/cfb.py +1 -3
  15. angr/analyses/cfg/cfg.py +2 -2
  16. angr/analyses/cfg/cfg_base.py +37 -35
  17. angr/analyses/cfg/cfg_emulated.py +1 -1
  18. angr/analyses/cfg/cfg_fast.py +62 -15
  19. angr/analyses/cfg/cfg_fast_soot.py +1 -1
  20. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
  21. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
  22. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
  23. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +50 -14
  24. angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
  25. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
  26. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
  27. angr/analyses/complete_calling_conventions.py +32 -3
  28. angr/analyses/congruency_check.py +2 -3
  29. angr/analyses/data_dep/data_dependency_analysis.py +2 -2
  30. angr/analyses/ddg.py +1 -4
  31. angr/analyses/decompiler/ail_simplifier.py +3 -4
  32. angr/analyses/decompiler/clinic.py +42 -7
  33. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  34. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
  35. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
  36. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  37. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +0 -6
  38. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -7
  39. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +0 -6
  40. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +0 -6
  41. angr/analyses/decompiler/structuring/phoenix.py +1 -1
  42. angr/analyses/disassembly.py +5 -5
  43. angr/analyses/fcp/__init__.py +4 -0
  44. angr/analyses/fcp/fcp.py +429 -0
  45. angr/analyses/identifier/identify.py +1 -3
  46. angr/analyses/loopfinder.py +4 -3
  47. angr/analyses/patchfinder.py +1 -1
  48. angr/analyses/propagator/engine_base.py +4 -3
  49. angr/analyses/propagator/propagator.py +14 -53
  50. angr/analyses/reassembler.py +1 -2
  51. angr/analyses/s_propagator.py +1 -3
  52. angr/analyses/soot_class_hierarchy.py +1 -2
  53. angr/analyses/stack_pointer_tracker.py +18 -2
  54. angr/analyses/static_hooker.py +1 -2
  55. angr/analyses/typehoon/simple_solver.py +2 -2
  56. angr/analyses/variable_recovery/engine_vex.py +5 -0
  57. angr/analyses/variable_recovery/variable_recovery_fast.py +1 -2
  58. angr/analyses/veritesting.py +4 -7
  59. angr/analyses/vfg.py +1 -1
  60. angr/analyses/vsa_ddg.py +1 -2
  61. angr/block.py +3 -2
  62. angr/callable.py +1 -3
  63. angr/calling_conventions.py +15 -7
  64. angr/codenode.py +5 -1
  65. angr/concretization_strategies/__init__.py +1 -83
  66. angr/concretization_strategies/any.py +2 -1
  67. angr/concretization_strategies/any_named.py +1 -1
  68. angr/concretization_strategies/base.py +81 -0
  69. angr/concretization_strategies/controlled_data.py +2 -1
  70. angr/concretization_strategies/eval.py +2 -1
  71. angr/concretization_strategies/logging.py +3 -1
  72. angr/concretization_strategies/max.py +2 -1
  73. angr/concretization_strategies/nonzero.py +2 -1
  74. angr/concretization_strategies/nonzero_range.py +2 -1
  75. angr/concretization_strategies/norepeats.py +2 -1
  76. angr/concretization_strategies/norepeats_range.py +2 -1
  77. angr/concretization_strategies/range.py +2 -1
  78. angr/concretization_strategies/signed_add.py +2 -1
  79. angr/concretization_strategies/single.py +2 -1
  80. angr/concretization_strategies/solutions.py +2 -1
  81. angr/concretization_strategies/unlimited_range.py +2 -1
  82. angr/engines/__init__.py +8 -5
  83. angr/engines/engine.py +3 -5
  84. angr/engines/failure.py +4 -5
  85. angr/engines/procedure.py +5 -7
  86. angr/engines/soot/expressions/__init__.py +22 -23
  87. angr/engines/soot/expressions/base.py +4 -4
  88. angr/engines/soot/expressions/invoke.py +1 -2
  89. angr/engines/soot/statements/__init__.py +9 -10
  90. angr/engines/soot/values/__init__.py +9 -10
  91. angr/engines/soot/values/arrayref.py +3 -3
  92. angr/engines/soot/values/instancefieldref.py +3 -2
  93. angr/engines/successors.py +7 -6
  94. angr/engines/syscall.py +4 -6
  95. angr/engines/unicorn.py +3 -2
  96. angr/engines/vex/claripy/ccall.py +8 -10
  97. angr/engines/vex/claripy/datalayer.py +4 -5
  98. angr/exploration_techniques/__init__.py +0 -2
  99. angr/exploration_techniques/spiller.py +1 -3
  100. angr/exploration_techniques/stochastic.py +2 -3
  101. angr/factory.py +3 -9
  102. angr/knowledge_plugins/cfg/cfg_model.py +20 -17
  103. angr/knowledge_plugins/functions/function.py +74 -77
  104. angr/knowledge_plugins/functions/function_manager.py +14 -7
  105. angr/knowledge_plugins/functions/function_parser.py +1 -1
  106. angr/knowledge_plugins/functions/soot_function.py +16 -16
  107. angr/knowledge_plugins/propagations/propagation_model.py +4 -5
  108. angr/knowledge_plugins/propagations/states.py +0 -511
  109. angr/procedures/libc/memcpy.py +4 -4
  110. angr/procedures/procedure_dict.py +3 -2
  111. angr/protos/__init__.py +2 -5
  112. angr/protos/cfg_pb2.py +21 -18
  113. angr/protos/function_pb2.py +17 -14
  114. angr/protos/primitives_pb2.py +44 -39
  115. angr/protos/variables_pb2.py +36 -31
  116. angr/protos/xrefs_pb2.py +15 -12
  117. angr/sim_procedure.py +15 -16
  118. angr/sim_variable.py +13 -1
  119. angr/simos/__init__.py +2 -0
  120. angr/simos/javavm.py +4 -6
  121. angr/simos/xbox.py +32 -0
  122. angr/state_plugins/__init__.py +0 -2
  123. angr/state_plugins/callstack.py +4 -4
  124. angr/state_plugins/cgc.py +3 -2
  125. angr/state_plugins/gdb.py +6 -5
  126. angr/state_plugins/globals.py +1 -2
  127. angr/state_plugins/heap/heap_brk.py +1 -2
  128. angr/state_plugins/history.py +10 -12
  129. angr/state_plugins/inspect.py +3 -5
  130. angr/state_plugins/libc.py +2 -2
  131. angr/state_plugins/log.py +8 -10
  132. angr/state_plugins/loop_data.py +1 -2
  133. angr/state_plugins/posix.py +7 -7
  134. angr/state_plugins/preconstrainer.py +2 -3
  135. angr/state_plugins/scratch.py +5 -8
  136. angr/state_plugins/sim_action.py +3 -3
  137. angr/state_plugins/solver.py +8 -3
  138. angr/state_plugins/symbolizer.py +5 -4
  139. angr/state_plugins/uc_manager.py +3 -3
  140. angr/state_plugins/unicorn_engine.py +5 -1
  141. angr/state_plugins/view.py +3 -5
  142. angr/storage/file.py +3 -5
  143. angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
  144. angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
  145. angr/storage/memory_mixins/clouseau_mixin.py +1 -3
  146. angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
  147. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
  148. angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
  149. angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
  150. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  151. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  152. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  153. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
  154. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
  155. angr/storage/memory_mixins/smart_find_mixin.py +1 -1
  156. angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
  157. angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
  158. angr/utils/bits.py +13 -0
  159. angr/utils/enums_conv.py +28 -12
  160. angr/utils/segment_list.py +25 -22
  161. angr/utils/timing.py +18 -1
  162. angr/vaults.py +5 -6
  163. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/METADATA +6 -6
  164. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/RECORD +168 -164
  165. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/WHEEL +1 -1
  166. angr/analyses/propagator/outdated_definition_walker.py +0 -159
  167. angr/analyses/propagator/tmpvar_finder.py +0 -18
  168. angr/engines/concrete.py +0 -180
  169. angr/exploration_techniques/symbion.py +0 -80
  170. angr/state_plugins/concrete.py +0 -295
  171. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/LICENSE +0 -0
  172. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/entry_points.txt +0 -0
  173. {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
- return section.is_readable and not section.is_writable
24
- segment = self.project.loader.find_segment_containing(addr_v)
25
- if segment is not None:
26
- return segment.is_readable and not segment.is_writable
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 isinstance(self.project.simos, SimWindows):
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 self._recover_variables and self.function_needs_variable_recovery(func):
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.bv import BV
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, immediate_stmt_removal: bool = False) -> SPropagatorAnalysis:
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, (_, narrow_info) in narrowing_candidates.items():
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(immediate_stmt_removal=True)
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 and not isinstance(
1014
- self.project.hooked_by(successors[0].addr), UnresolvableCallTarget
1015
- ):
1016
- # found a single successor - replace the last statement
1017
- new_last_stmt = last_stmt.copy()
1018
- new_last_stmt.target = ailment.Expr.Const(None, None, successors[0].addr, last_stmt.target.bits)
1019
- block.statements[-1] = new_last_stmt
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 split, sblocks in self.merge_blocks_to_originals.items():
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 k, v in self.original_split_blocks.items():
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 block, original_blocks in ail_merge_graph.original_blocks.items():
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, data in graph.edges(data=True):
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 src, vvar in stmt.src.src_and_vvars:
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, redundant_nodes) in list(enumerate(caselists)):
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, canary_check_stmt_idx, stack_chk_fail_caller, ret_node in nodes_to_process:
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 out_src, out_dst in out_edges[1:]:
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:
@@ -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)
@@ -0,0 +1,4 @@
1
+ from __future__ import annotations
2
+ from .fcp import FastConstantPropagation
3
+
4
+ __all__ = ["FastConstantPropagation"]