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