angr 9.2.135__py3-none-manylinux2014_aarch64.whl → 9.2.137__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 (198) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +3 -7
  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/calling_convention.py +6 -4
  10. angr/analyses/calling_convention/fact_collector.py +10 -3
  11. angr/analyses/cdg.py +1 -2
  12. angr/analyses/cfg/cfb.py +1 -3
  13. angr/analyses/cfg/cfg.py +2 -2
  14. angr/analyses/cfg/cfg_base.py +40 -68
  15. angr/analyses/cfg/cfg_emulated.py +1 -104
  16. angr/analyses/cfg/cfg_fast.py +90 -27
  17. angr/analyses/cfg/cfg_fast_soot.py +1 -1
  18. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
  19. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
  20. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
  21. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +65 -14
  22. angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
  23. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
  24. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
  25. angr/analyses/class_identifier.py +1 -2
  26. angr/analyses/complete_calling_conventions.py +3 -0
  27. angr/analyses/congruency_check.py +2 -3
  28. angr/analyses/data_dep/data_dependency_analysis.py +2 -2
  29. angr/analyses/ddg.py +1 -4
  30. angr/analyses/decompiler/ail_simplifier.py +15 -5
  31. angr/analyses/decompiler/block_simplifier.py +2 -2
  32. angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
  33. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  34. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
  35. angr/analyses/decompiler/clinic.py +119 -72
  36. angr/analyses/decompiler/condition_processor.py +2 -0
  37. angr/analyses/decompiler/decompiler.py +1 -0
  38. angr/analyses/decompiler/dephication/dephication_base.py +2 -0
  39. angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
  40. angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
  41. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  42. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
  43. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
  44. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  45. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
  46. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
  47. angr/analyses/decompiler/sequence_walker.py +6 -2
  48. angr/analyses/decompiler/ssailification/rewriting.py +11 -1
  49. angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
  50. angr/analyses/decompiler/ssailification/ssailification.py +13 -3
  51. angr/analyses/decompiler/ssailification/traversal.py +28 -2
  52. angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
  53. angr/analyses/decompiler/structured_codegen/c.py +44 -21
  54. angr/analyses/decompiler/structuring/phoenix.py +118 -15
  55. angr/analyses/decompiler/utils.py +113 -8
  56. angr/analyses/disassembly.py +5 -5
  57. angr/analyses/fcp/__init__.py +4 -0
  58. angr/analyses/fcp/fcp.py +429 -0
  59. angr/analyses/identifier/identify.py +1 -3
  60. angr/analyses/loopfinder.py +4 -3
  61. angr/analyses/patchfinder.py +1 -1
  62. angr/analyses/propagator/engine_base.py +4 -3
  63. angr/analyses/propagator/propagator.py +14 -53
  64. angr/analyses/reaching_definitions/function_handler.py +1 -1
  65. angr/analyses/reassembler.py +1 -2
  66. angr/analyses/s_liveness.py +5 -1
  67. angr/analyses/s_propagator.py +26 -7
  68. angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
  69. angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
  70. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
  71. angr/analyses/soot_class_hierarchy.py +1 -2
  72. angr/analyses/stack_pointer_tracker.py +29 -3
  73. angr/analyses/static_hooker.py +1 -2
  74. angr/analyses/typehoon/simple_solver.py +2 -2
  75. angr/analyses/variable_recovery/engine_ail.py +19 -7
  76. angr/analyses/variable_recovery/engine_base.py +16 -14
  77. angr/analyses/variable_recovery/engine_vex.py +2 -2
  78. angr/analyses/variable_recovery/variable_recovery_fast.py +23 -3
  79. angr/analyses/veritesting.py +4 -7
  80. angr/analyses/vfg.py +1 -1
  81. angr/analyses/vsa_ddg.py +1 -2
  82. angr/block.py +62 -22
  83. angr/callable.py +1 -3
  84. angr/calling_conventions.py +3 -3
  85. angr/codenode.py +5 -1
  86. angr/concretization_strategies/__init__.py +1 -83
  87. angr/concretization_strategies/any.py +2 -1
  88. angr/concretization_strategies/any_named.py +1 -1
  89. angr/concretization_strategies/base.py +81 -0
  90. angr/concretization_strategies/controlled_data.py +2 -1
  91. angr/concretization_strategies/eval.py +2 -1
  92. angr/concretization_strategies/logging.py +3 -1
  93. angr/concretization_strategies/max.py +2 -1
  94. angr/concretization_strategies/nonzero.py +2 -1
  95. angr/concretization_strategies/nonzero_range.py +2 -1
  96. angr/concretization_strategies/norepeats.py +2 -1
  97. angr/concretization_strategies/norepeats_range.py +2 -1
  98. angr/concretization_strategies/range.py +2 -1
  99. angr/concretization_strategies/signed_add.py +2 -1
  100. angr/concretization_strategies/single.py +2 -1
  101. angr/concretization_strategies/solutions.py +2 -1
  102. angr/concretization_strategies/unlimited_range.py +2 -1
  103. angr/engines/__init__.py +8 -5
  104. angr/engines/engine.py +3 -5
  105. angr/engines/failure.py +4 -5
  106. angr/engines/pcode/emulate.py +1 -1
  107. angr/engines/pcode/lifter.py +31 -18
  108. angr/engines/procedure.py +5 -7
  109. angr/engines/soot/expressions/__init__.py +20 -23
  110. angr/engines/soot/expressions/base.py +4 -4
  111. angr/engines/soot/expressions/invoke.py +1 -2
  112. angr/engines/soot/statements/__init__.py +10 -12
  113. angr/engines/soot/values/__init__.py +10 -12
  114. angr/engines/soot/values/arrayref.py +3 -3
  115. angr/engines/soot/values/instancefieldref.py +3 -2
  116. angr/engines/successors.py +18 -12
  117. angr/engines/syscall.py +4 -6
  118. angr/engines/unicorn.py +3 -2
  119. angr/engines/vex/claripy/ccall.py +8 -10
  120. angr/engines/vex/claripy/datalayer.py +4 -5
  121. angr/engines/vex/lifter.py +9 -6
  122. angr/exploration_techniques/__init__.py +0 -2
  123. angr/exploration_techniques/spiller.py +1 -3
  124. angr/exploration_techniques/stochastic.py +2 -3
  125. angr/factory.py +3 -9
  126. angr/flirt/build_sig.py +8 -15
  127. angr/knowledge_plugins/cfg/cfg_model.py +20 -17
  128. angr/knowledge_plugins/functions/function.py +70 -79
  129. angr/knowledge_plugins/functions/function_manager.py +8 -7
  130. angr/knowledge_plugins/functions/function_parser.py +1 -1
  131. angr/knowledge_plugins/functions/soot_function.py +21 -24
  132. angr/knowledge_plugins/propagations/propagation_model.py +4 -5
  133. angr/knowledge_plugins/propagations/states.py +0 -511
  134. angr/knowledge_plugins/variables/variable_manager.py +16 -10
  135. angr/procedures/libc/memcpy.py +4 -4
  136. angr/procedures/procedure_dict.py +3 -2
  137. angr/protos/__init__.py +2 -5
  138. angr/protos/cfg_pb2.py +21 -18
  139. angr/protos/function_pb2.py +17 -14
  140. angr/protos/primitives_pb2.py +44 -39
  141. angr/protos/variables_pb2.py +36 -31
  142. angr/protos/xrefs_pb2.py +15 -12
  143. angr/sim_procedure.py +15 -16
  144. angr/sim_variable.py +13 -1
  145. angr/simos/__init__.py +2 -0
  146. angr/simos/javavm.py +4 -6
  147. angr/simos/xbox.py +32 -0
  148. angr/state_plugins/__init__.py +0 -2
  149. angr/state_plugins/callstack.py +4 -4
  150. angr/state_plugins/cgc.py +3 -2
  151. angr/state_plugins/gdb.py +6 -5
  152. angr/state_plugins/globals.py +1 -2
  153. angr/state_plugins/heap/heap_brk.py +1 -2
  154. angr/state_plugins/history.py +10 -12
  155. angr/state_plugins/inspect.py +3 -5
  156. angr/state_plugins/libc.py +2 -2
  157. angr/state_plugins/log.py +8 -10
  158. angr/state_plugins/loop_data.py +1 -2
  159. angr/state_plugins/posix.py +7 -7
  160. angr/state_plugins/preconstrainer.py +2 -3
  161. angr/state_plugins/scratch.py +5 -8
  162. angr/state_plugins/sim_action.py +3 -3
  163. angr/state_plugins/solver.py +8 -3
  164. angr/state_plugins/symbolizer.py +5 -4
  165. angr/state_plugins/uc_manager.py +3 -3
  166. angr/state_plugins/unicorn_engine.py +5 -1
  167. angr/state_plugins/view.py +3 -5
  168. angr/storage/file.py +3 -5
  169. angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
  170. angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
  171. angr/storage/memory_mixins/clouseau_mixin.py +1 -3
  172. angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
  173. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
  174. angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
  175. angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
  176. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  177. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  178. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  179. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
  180. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
  181. angr/storage/memory_mixins/smart_find_mixin.py +1 -1
  182. angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
  183. angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
  184. angr/utils/enums_conv.py +28 -12
  185. angr/utils/segment_list.py +25 -22
  186. angr/utils/timing.py +18 -1
  187. angr/vaults.py +5 -6
  188. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
  189. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/RECORD +193 -191
  190. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
  191. angr/analyses/propagator/outdated_definition_walker.py +0 -159
  192. angr/analyses/propagator/tmpvar_finder.py +0 -18
  193. angr/engines/concrete.py +0 -180
  194. angr/exploration_techniques/symbion.py +0 -80
  195. angr/state_plugins/concrete.py +0 -295
  196. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
  197. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
  198. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
@@ -30,8 +30,7 @@ class ClassIdentifier(Analysis):
30
30
  continue
31
31
  col_ind = func.demangled_name.rfind("::")
32
32
  class_name = func.demangled_name[:col_ind]
33
- if class_name.startswith("non-virtual thunk for "):
34
- class_name = class_name[len("non-virtual thunk for ") :]
33
+ class_name = class_name.removeprefix("non-virtual thunk for ")
35
34
  if col_ind != -1:
36
35
  if class_name not in self.classes:
37
36
  ctor = False
@@ -208,6 +208,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
208
208
  self._update_progress(percentage, text=f"{idx + 1}/{total_funcs} - {func.demangled_name}")
209
209
  if self._low_priority:
210
210
  self._release_gil(idx + 1, 10, 0.000001)
211
+ self._finish_progress()
211
212
 
212
213
  else:
213
214
  self._remaining_funcs.value = len(self._func_addrs)
@@ -298,6 +299,8 @@ class CompleteCallingConventionsAnalysis(Analysis):
298
299
  for proc in procs:
299
300
  proc.join()
300
301
 
302
+ self._finish_progress()
303
+
301
304
  def _worker_routine(self, worker_id: int, initializer: Initializer):
302
305
  initializer.initialize()
303
306
  idx = 0
@@ -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)
@@ -207,25 +207,28 @@ class AILSimplifier(Analysis):
207
207
  # Computing reaching definitions or return the cached one
208
208
  if self._reaching_definitions is not None:
209
209
  return self._reaching_definitions
210
+ func_args = {vvar for vvar, _ in self._arg_vvars.values()} if self._arg_vvars else set()
210
211
  rd = self.project.analyses.SReachingDefinitions(
211
212
  subject=self.func,
212
213
  func_graph=self.func_graph,
214
+ func_args=func_args,
213
215
  # use_callee_saved_regs_at_return=self._use_callee_saved_regs_at_return,
214
216
  # track_tmps=True,
215
217
  ).model
216
218
  self._reaching_definitions = rd
217
219
  return rd
218
220
 
219
- def _compute_propagation(self, immediate_stmt_removal: bool = False) -> SPropagatorAnalysis:
221
+ def _compute_propagation(self) -> SPropagatorAnalysis:
220
222
  # Propagate expressions or return the existing result
221
223
  if self._propagator is not None:
222
224
  return self._propagator
223
- prop = self.project.analyses[SPropagatorAnalysis].prep()(
225
+ func_args = {vvar for vvar, _ in self._arg_vvars.values()} if self._arg_vvars else set()
226
+ prop = self.project.analyses[SPropagatorAnalysis].prep(fail_fast=self._fail_fast)(
224
227
  subject=self.func,
225
228
  func_graph=self.func_graph,
229
+ func_args=func_args,
226
230
  # gp=self._gp,
227
231
  only_consts=self._only_consts,
228
- immediate_stmt_removal=immediate_stmt_removal,
229
232
  )
230
233
  self._propagator = prop
231
234
  return prop
@@ -354,7 +357,7 @@ class AILSimplifier(Analysis):
354
357
  ):
355
358
  repeat = False
356
359
  narrowable_phivarids = set()
357
- for def_vvarid, (_, narrow_info) in narrowing_candidates.items():
360
+ for def_vvarid in narrowing_candidates:
358
361
  if def_vvarid in blacklist_varids:
359
362
  continue
360
363
  if def_vvarid in rd.phi_vvar_ids:
@@ -591,7 +594,7 @@ class AILSimplifier(Analysis):
591
594
  """
592
595
 
593
596
  # propagator
594
- propagator = self._compute_propagation(immediate_stmt_removal=True)
597
+ propagator = self._compute_propagation()
595
598
  replacements = propagator.replacements
596
599
 
597
600
  # take replacements and rebuild the corresponding blocks
@@ -899,6 +902,13 @@ class AILSimplifier(Analysis):
899
902
 
900
903
  to_replace_def = the_def
901
904
 
905
+ # check: the definition of expression being replaced should not be a phi variable
906
+ if (
907
+ isinstance(to_replace_def.atom, atoms.VirtualVariable)
908
+ and to_replace_def.atom.varid in rd.phi_vvar_ids
909
+ ):
910
+ continue
911
+
902
912
  # find all uses of this definition
903
913
  # we make a copy of the set since we may touch the set (uses) when replacing expressions
904
914
  all_uses: set[tuple[CodeLocation, Any]] = set(rd.get_vvar_uses_with_expr(to_replace_def.atom))
@@ -141,7 +141,7 @@ class BlockSimplifier(Analysis):
141
141
 
142
142
  def _compute_propagation(self, block) -> SPropagatorAnalysis:
143
143
  if self._propagator is None:
144
- self._propagator = self.project.analyses[SPropagatorAnalysis].prep()(
144
+ self._propagator = self.project.analyses[SPropagatorAnalysis].prep(fail_fast=self._fail_fast)(
145
145
  subject=block,
146
146
  func_addr=self.func_addr,
147
147
  stack_pointer_tracker=self._stack_pointer_tracker,
@@ -152,7 +152,7 @@ class BlockSimplifier(Analysis):
152
152
  if self._reaching_definitions is None:
153
153
  self._reaching_definitions = (
154
154
  self.project.analyses[SReachingDefinitionsAnalysis]
155
- .prep()(
155
+ .prep(fail_fast=self._fail_fast)(
156
156
  subject=block,
157
157
  track_tmps=True,
158
158
  func_addr=self.func_addr,
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
  from .amd64_ccalls import AMD64CCallRewriter
3
+ from .x86_ccalls import X86CCallRewriter
3
4
 
4
5
 
5
6
  CCALL_REWRITERS = {
7
+ "X86": X86CCallRewriter,
6
8
  "AMD64": AMD64CCallRewriter,
7
9
  }
@@ -14,7 +14,7 @@ AMD64_CondBitOffsets = data["AMD64"]["CondBitOffsets"]
14
14
 
15
15
  class AMD64CCallRewriter(CCallRewriterBase):
16
16
  """
17
- Implements ccall rewriter for AMD64.
17
+ Implements VEX ccall rewriter for AMD64.
18
18
  """
19
19
 
20
20
  __slots__ = ()
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ from ailment import Expr
4
+
5
+ from angr.engines.vex.claripy.ccall import data
6
+ from .rewriter_base import CCallRewriterBase
7
+
8
+
9
+ X86_CondTypes = data["X86"]["CondTypes"]
10
+ X86_OpTypes = data["X86"]["OpTypes"]
11
+ X86_CondBitMasks = data["X86"]["CondBitMasks"]
12
+ X86_CondBitOffsets = data["X86"]["CondBitOffsets"]
13
+
14
+
15
+ class X86CCallRewriter(CCallRewriterBase):
16
+ """
17
+ Implements VEX ccall rewriter for X86.
18
+ """
19
+
20
+ __slots__ = ()
21
+
22
+ def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Expr.Expression | None:
23
+ if ccall.callee == "x86g_calculate_condition":
24
+ cond = ccall.operands[0]
25
+ op = ccall.operands[1]
26
+ dep_1 = ccall.operands[2]
27
+ dep_2 = ccall.operands[3]
28
+ if isinstance(cond, Expr.Const) and isinstance(op, Expr.Const):
29
+ cond_v = cond.value
30
+ op_v = op.value
31
+ if cond_v == X86_CondTypes["CondLE"]: # noqa: SIM102
32
+ if op_v in {
33
+ X86_OpTypes["G_CC_OP_SUBB"],
34
+ X86_OpTypes["G_CC_OP_SUBW"],
35
+ X86_OpTypes["G_CC_OP_SUBL"],
36
+ }:
37
+ # dep_1 <=s dep_2
38
+ dep_1 = self._fix_size(
39
+ dep_1,
40
+ op_v,
41
+ X86_OpTypes["G_CC_OP_SUBB"],
42
+ X86_OpTypes["G_CC_OP_SUBW"],
43
+ ccall.tags,
44
+ )
45
+ dep_2 = self._fix_size(
46
+ dep_2,
47
+ op_v,
48
+ X86_OpTypes["G_CC_OP_SUBB"],
49
+ X86_OpTypes["G_CC_OP_SUBW"],
50
+ ccall.tags,
51
+ )
52
+
53
+ r = Expr.BinaryOp(ccall.idx, "CmpLE", (dep_1, dep_2), True, **ccall.tags)
54
+ return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
55
+ return None
56
+
57
+ @staticmethod
58
+ def _fix_size(expr, op_v: int, type_8bit, type_16bit, tags):
59
+ if op_v == type_8bit:
60
+ bits = 8
61
+ elif op_v == type_16bit:
62
+ bits = 16
63
+ else:
64
+ bits = 32
65
+ if bits < 32:
66
+ if isinstance(expr, Expr.Const):
67
+ return Expr.Const(expr.idx, None, expr.value & ((1 << bits) - 1), bits, **tags)
68
+ return Expr.Convert(None, 32, bits, False, expr, **tags)
69
+ return expr
@@ -49,7 +49,6 @@ from .optimization_passes import (
49
49
  DUPLICATING_OPTS,
50
50
  CONDENSING_OPTS,
51
51
  )
52
- from .utils import first_nonlabel_statement_id
53
52
 
54
53
  if TYPE_CHECKING:
55
54
  from angr.knowledge_plugins.cfg import CFGModel
@@ -461,12 +460,12 @@ class Clinic(Analysis):
461
460
  # Make function arguments
462
461
  self._update_progress(33.0, text="Making argument list")
463
462
  arg_list = self._make_argument_list()
464
- arg_vvars = {}
465
- ail_graph = self._create_argument_accessing_statements(arg_list, ail_graph, arg_vvars)
463
+ arg_vvars = self._create_function_argument_vvars(arg_list)
464
+ func_args = {arg_vvar for arg_vvar, _ in arg_vvars.values()}
466
465
 
467
466
  # Transform the graph into partial SSA form
468
467
  self._update_progress(35.0, text="Transforming to partial-SSA form")
469
- ail_graph = self._transform_to_ssa_level0(ail_graph)
468
+ ail_graph = self._transform_to_ssa_level0(ail_graph, func_args)
470
469
 
471
470
  # full-function constant-only propagation
472
471
  self._update_progress(36.0, text="Constant propagation")
@@ -521,15 +520,20 @@ class Clinic(Analysis):
521
520
  )
522
521
 
523
522
  # rewrite (qualified) stack variables into SSA form
524
- ail_graph = self._transform_to_ssa_level1(ail_graph)
523
+ ail_graph = self._transform_to_ssa_level1(ail_graph, func_args)
525
524
 
526
525
  # clear _blocks_by_addr_and_size so no one can use it again
527
526
  # TODO: Totally remove this dict
528
527
  self._blocks_by_addr_and_size = None
529
528
 
529
+ # Rust-specific; only call this on Rust binaries when we can identify language and compiler
530
+ ail_graph = self._rewrite_rust_probestack_call(ail_graph)
531
+ # Windows-specific
532
+ ail_graph = self._rewrite_windows_stkchk_call(ail_graph)
533
+
530
534
  # Make call-sites
531
535
  self._update_progress(50.0, text="Making callsites")
532
- _, stackarg_offsets, removed_vvar_ids = self._make_callsites(ail_graph, stack_pointer_tracker=spt)
536
+ _, stackarg_offsets, removed_vvar_ids = self._make_callsites(ail_graph, func_args, stack_pointer_tracker=spt)
533
537
 
534
538
  # Run simplification passes
535
539
  self._update_progress(53.0, text="Running simplifications 2")
@@ -1010,13 +1014,15 @@ class Clinic(Analysis):
1010
1014
  if node is None:
1011
1015
  continue
1012
1016
  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
1017
+ if len(successors) == 1:
1018
+ succ_addr = successors[0].addr
1019
+ if not self.project.is_hooked(succ_addr) or not isinstance(
1020
+ self.project.hooked_by(successors[0].addr), UnresolvableCallTarget
1021
+ ):
1022
+ # found a single successor - replace the last statement
1023
+ new_last_stmt = last_stmt.copy()
1024
+ new_last_stmt.target = ailment.Expr.Const(None, None, successors[0].addr, last_stmt.target.bits)
1025
+ block.statements[-1] = new_last_stmt
1020
1026
 
1021
1027
  elif isinstance(last_stmt, ailment.Stmt.Jump) and not isinstance(last_stmt.target, ailment.Expr.Const):
1022
1028
  # indirect jump
@@ -1301,84 +1307,57 @@ class Clinic(Analysis):
1301
1307
  return ail_graph
1302
1308
 
1303
1309
  @timethis
1304
- def _create_argument_accessing_statements(
1305
- self,
1306
- arg_list: list[SimVariable],
1307
- ail_graph: networkx.DiGraph,
1308
- arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]],
1309
- ) -> networkx.DiGraph:
1310
- entrypoint = next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr))
1311
- new_stmts = []
1310
+ def _create_function_argument_vvars(self, arg_list) -> dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]]:
1311
+ arg_vvars = {}
1312
1312
  for arg in arg_list:
1313
- if not isinstance(arg, SimRegisterVariable):
1314
- continue
1315
-
1316
- # get the full register if needed
1317
- basereg_offset, basereg_size = self.project.arch.get_base_register(arg.reg, size=arg.size)
1318
-
1319
- arg_vvar = ailment.Expr.VirtualVariable(
1320
- self._ail_manager.next_atom(),
1321
- self.vvar_id_start,
1322
- arg.bits,
1323
- ailment.Expr.VirtualVariableCategory.PARAMETER,
1324
- oident=arg.reg,
1325
- ins_addr=self.function.addr,
1326
- vex_block_addr=self.function.addr,
1327
- )
1328
- self.vvar_id_start += 1
1329
- arg_vvars[arg_vvar.varid] = arg_vvar, arg
1330
-
1331
- if basereg_size != arg.size:
1332
- # extend the value to the full register
1333
- arg_vvar = ailment.Expr.Convert(
1313
+ if isinstance(arg, SimRegisterVariable):
1314
+ # get the full register if needed
1315
+ arg_vvar = ailment.Expr.VirtualVariable(
1334
1316
  self._ail_manager.next_atom(),
1335
- arg.size * self.project.arch.byte_width,
1336
- basereg_size * self.project.arch.byte_width,
1337
- False,
1338
- arg_vvar,
1317
+ self.vvar_id_start,
1318
+ arg.bits,
1319
+ ailment.Expr.VirtualVariableCategory.PARAMETER,
1320
+ oident=(ailment.Expr.VirtualVariableCategory.REGISTER, arg.reg),
1339
1321
  ins_addr=self.function.addr,
1340
1322
  vex_block_addr=self.function.addr,
1341
1323
  )
1324
+ self.vvar_id_start += 1
1325
+ arg_vvars[arg_vvar.varid] = arg_vvar, arg
1326
+ elif isinstance(arg, SimStackVariable):
1327
+ arg_vvar = ailment.Expr.VirtualVariable(
1328
+ self._ail_manager.next_atom(),
1329
+ self.vvar_id_start,
1330
+ arg.bits,
1331
+ ailment.Expr.VirtualVariableCategory.PARAMETER,
1332
+ oident=(ailment.Expr.VirtualVariableCategory.STACK, arg.offset),
1333
+ ins_addr=self.function.addr,
1334
+ vex_block_addr=self.function.addr,
1335
+ )
1336
+ self.vvar_id_start += 1
1337
+ arg_vvars[arg_vvar.varid] = arg_vvar, arg
1342
1338
 
1343
- fullreg_dst = ailment.Expr.Register(
1344
- self._ail_manager.next_atom(),
1345
- None,
1346
- basereg_offset,
1347
- basereg_size * self.project.arch.byte_width,
1348
- ins_addr=self.function.addr,
1349
- vex_block_addr=self.function.addr,
1350
- )
1351
- stmt = ailment.Stmt.Assignment(
1352
- self._ail_manager.next_atom(),
1353
- fullreg_dst,
1354
- arg_vvar,
1355
- ins_addr=self.function.addr,
1356
- vex_block_addr=self.function.addr,
1357
- )
1358
- new_stmts.append(stmt)
1359
-
1360
- non_label_stmt_idx = first_nonlabel_statement_id(entrypoint)
1361
- # update the ail block in-place
1362
- entrypoint.statements = (
1363
- entrypoint.statements[:non_label_stmt_idx] + new_stmts + entrypoint.statements[non_label_stmt_idx:]
1364
- )
1365
- return ail_graph
1339
+ return arg_vvars
1366
1340
 
1367
1341
  @timethis
1368
- def _transform_to_ssa_level0(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1342
+ def _transform_to_ssa_level0(
1343
+ self, ail_graph: networkx.DiGraph, func_args: set[ailment.Expr.VirtualVariable]
1344
+ ) -> networkx.DiGraph:
1369
1345
  ssailification = self.project.analyses[Ssailification].prep(fail_fast=self._fail_fast)(
1370
1346
  self.function,
1371
1347
  ail_graph,
1372
1348
  entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
1373
1349
  ail_manager=self._ail_manager,
1374
1350
  ssa_stackvars=False,
1351
+ func_args=func_args,
1375
1352
  vvar_id_start=self.vvar_id_start,
1376
1353
  )
1377
1354
  self.vvar_id_start = ssailification.max_vvar_id + 1
1378
1355
  return ssailification.out_graph
1379
1356
 
1380
1357
  @timethis
1381
- def _transform_to_ssa_level1(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1358
+ def _transform_to_ssa_level1(
1359
+ self, ail_graph: networkx.DiGraph, func_args: set[ailment.Expr.VirtualVariable]
1360
+ ) -> networkx.DiGraph:
1382
1361
  ssailification = self.project.analyses.Ssailification(
1383
1362
  self.function,
1384
1363
  ail_graph,
@@ -1387,6 +1366,7 @@ class Clinic(Analysis):
1387
1366
  ail_manager=self._ail_manager,
1388
1367
  ssa_tmps=True,
1389
1368
  ssa_stackvars=True,
1369
+ func_args=func_args,
1390
1370
  vvar_id_start=self.vvar_id_start,
1391
1371
  )
1392
1372
  self.vvar_id_start = ssailification.max_vvar_id + 1
@@ -1444,7 +1424,7 @@ class Clinic(Analysis):
1444
1424
  return []
1445
1425
 
1446
1426
  @timethis
1447
- def _make_callsites(self, ail_graph, stack_pointer_tracker=None):
1427
+ def _make_callsites(self, ail_graph, func_args: set[ailment.Expr.VirtualVariable], stack_pointer_tracker=None):
1448
1428
  """
1449
1429
  Simplify all function call statements.
1450
1430
  """
@@ -1453,6 +1433,7 @@ class Clinic(Analysis):
1453
1433
  rd = self.project.analyses.SReachingDefinitions(
1454
1434
  subject=self.function,
1455
1435
  func_graph=ail_graph,
1436
+ func_args=func_args,
1456
1437
  fail_fast=self._fail_fast,
1457
1438
  # use_callee_saved_regs_at_return=not self._register_save_areas_removed, FIXME
1458
1439
  )
@@ -1709,6 +1690,9 @@ class Clinic(Analysis):
1709
1690
  elif stmt_type is ailment.Stmt.ConditionalJump:
1710
1691
  self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.condition)
1711
1692
 
1693
+ elif stmt_type is ailment.Stmt.Jump and not isinstance(stmt.target, ailment.Expr.Const):
1694
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.target)
1695
+
1712
1696
  elif stmt_type is ailment.Stmt.Call:
1713
1697
  self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, stmt, is_expr=False)
1714
1698
 
@@ -2732,6 +2716,69 @@ class Clinic(Analysis):
2732
2716
 
2733
2717
  return extra_regs
2734
2718
 
2719
+ def _rewrite_rust_probestack_call(self, ail_graph):
2720
+ for node in ail_graph:
2721
+ if not node.statements or ail_graph.out_degree[node] != 1:
2722
+ continue
2723
+ last_stmt = node.statements[-1]
2724
+ if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
2725
+ func = (
2726
+ self.project.kb.functions.get_by_addr(last_stmt.target.value)
2727
+ if self.project.kb.functions.contains_addr(last_stmt.target.value)
2728
+ else None
2729
+ )
2730
+ if func is not None and func.info.get("is_rust_probestack", False) is True:
2731
+ # get rid of this call
2732
+ node.statements = node.statements[:-1]
2733
+ if self.project.arch.call_pushes_ret and node.statements:
2734
+ last_stmt = node.statements[-1]
2735
+ succ = next(iter(ail_graph.successors(node)))
2736
+ if (
2737
+ isinstance(last_stmt, ailment.Stmt.Store)
2738
+ and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
2739
+ and isinstance(last_stmt.addr.offset, int)
2740
+ and last_stmt.addr.offset < 0
2741
+ and isinstance(last_stmt.data, ailment.Expr.Const)
2742
+ and last_stmt.data.value == succ.addr
2743
+ ):
2744
+ # remove the statement that pushes the return address
2745
+ node.statements = node.statements[:-1]
2746
+ break
2747
+ return ail_graph
2748
+
2749
+ def _rewrite_windows_stkchk_call(self, ail_graph) -> networkx.DiGraph:
2750
+ if not (self.project.simos is not None and self.project.simos.name == "Win32"):
2751
+ return ail_graph
2752
+
2753
+ for node in ail_graph:
2754
+ if not node.statements or ail_graph.out_degree[node] != 1:
2755
+ continue
2756
+ last_stmt = node.statements[-1]
2757
+ if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
2758
+ func = (
2759
+ self.project.kb.functions.get_by_addr(last_stmt.target.value)
2760
+ if self.project.kb.functions.contains_addr(last_stmt.target.value)
2761
+ else None
2762
+ )
2763
+ if func is not None and func.name == "__chkstk":
2764
+ # get rid of this call
2765
+ node.statements = node.statements[:-1]
2766
+ if self.project.arch.call_pushes_ret and node.statements:
2767
+ last_stmt = node.statements[-1]
2768
+ succ = next(iter(ail_graph.successors(node)))
2769
+ if (
2770
+ isinstance(last_stmt, ailment.Stmt.Store)
2771
+ and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
2772
+ and isinstance(last_stmt.addr.offset, int)
2773
+ and last_stmt.addr.offset < 0
2774
+ and isinstance(last_stmt.data, ailment.Expr.Const)
2775
+ and last_stmt.data.value == succ.addr
2776
+ ):
2777
+ # remove the statement that pushes the return address
2778
+ node.statements = node.statements[:-1]
2779
+ break
2780
+ return ail_graph
2781
+
2735
2782
  def _rewrite_alloca(self, ail_graph):
2736
2783
  # pylint:disable=too-many-boolean-expressions
2737
2784
  alloca_node = None
@@ -721,6 +721,8 @@ class ConditionProcessor:
721
721
  :return: None
722
722
  """
723
723
 
724
+ if not isinstance(cond, claripy.ast.Base):
725
+ return cond
724
726
  if memo is None:
725
727
  memo = {}
726
728
  if cond._hash in memo:
@@ -368,6 +368,7 @@ class Decompiler(Analysis):
368
368
  self.cache.clinic = self.clinic
369
369
 
370
370
  self.kb.decompilations[(self.func.addr, self._flavor)] = self.cache
371
+ self._finish_progress()
371
372
 
372
373
  def _recover_regions(self, graph: networkx.DiGraph, condition_processor, update_graph: bool = True):
373
374
  return self.project.analyses[RegionIdentifier].prep(kb=self.kb, fail_fast=self._fail_fast)(
@@ -77,6 +77,8 @@ class DephicationBase(Analysis):
77
77
  mapped_phivarid = phivarid_to_phivarid.get(phi_varid, phi_varid)
78
78
  for varid in varids:
79
79
  vvar_to_vvar[varid] = mapped_phivarid
80
+ if phi_varid != mapped_phivarid:
81
+ vvar_to_vvar[phi_varid] = mapped_phivarid
80
82
 
81
83
  return vvar_to_vvar
82
84
 
@@ -88,12 +88,14 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
88
88
  )
89
89
 
90
90
  if new_dst is not None or new_src is not None:
91
- return Assignment(
92
- stmt.idx,
93
- stmt.dst if new_dst is None else new_dst,
94
- stmt.src if new_src is None else new_src,
95
- **stmt.tags,
96
- )
91
+ # ensure we do not generate vvar_A = vvar_A
92
+ dst = stmt.dst if new_dst is None else new_dst
93
+ src = stmt.src if new_src is None else new_src
94
+ if isinstance(dst, VirtualVariable) and isinstance(src, VirtualVariable) and dst.varid == src.varid:
95
+ # skip it
96
+ return ()
97
+
98
+ return Assignment(stmt.idx, dst, src, **stmt.tags)
97
99
  return None
98
100
 
99
101
  def _handle_stmt_Store(self, stmt):
@@ -5,7 +5,7 @@ from typing import Any
5
5
 
6
6
  from ailment.block import Block
7
7
  from ailment.statement import Assignment
8
- from ailment.expression import VirtualVariable, Phi
8
+ from ailment.expression import VirtualVariable, Phi, BinaryOp, UnaryOp
9
9
 
10
10
  import angr
11
11
  from angr.utils.ail import is_phi_assignment
@@ -60,6 +60,9 @@ class SeqNodeRewriter(SequenceWalker):
60
60
  Block: self._handle_Block,
61
61
  # statement handlers
62
62
  Assignment: self._handle_Assignment,
63
+ # expression handlers
64
+ BinaryOp: self._handle_BinaryOp,
65
+ UnaryOp: self._handle_UnaryOp,
63
66
  }
64
67
  )
65
68
 
@@ -74,6 +77,12 @@ class SeqNodeRewriter(SequenceWalker):
74
77
  def _handle_Assignment(self, stmt: Assignment, **kwargs) -> Assignment: # pylint:disable=unused-argument
75
78
  return self.engine._handle_stmt_Assignment(stmt)
76
79
 
80
+ def _handle_BinaryOp(self, expr, **kwargs): # pylint:disable=unused-argument
81
+ return self.engine._handle_expr_BinaryOp(expr)
82
+
83
+ def _handle_UnaryOp(self, expr, **kwargs): # pylint:disable=unused-argument
84
+ return self.engine._handle_expr_UnaryOp(expr)
85
+
77
86
  def _handle_Block(self, block: Block, **kwargs) -> Block | None: # pylint:disable=unused-argument
78
87
  self.engine.out_block = None
79
88
  self.engine.process(None, block=block)
@@ -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: