angr 9.2.130__py3-none-win_amd64.whl → 9.2.132__py3-none-win_amd64.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 (128) 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/lib/angr_native.dll +0 -0
  112. angr/sim_manager.py +1 -3
  113. angr/sim_state.py +39 -41
  114. angr/sim_type.py +5 -0
  115. angr/sim_variable.py +29 -28
  116. angr/utils/bits.py +17 -0
  117. angr/utils/formatting.py +4 -1
  118. angr/utils/orderedset.py +4 -1
  119. angr/utils/ssa/__init__.py +21 -3
  120. {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/METADATA +6 -6
  121. {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/RECORD +125 -124
  122. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +0 -223
  123. angr/analyses/propagator/engine_ail.py +0 -1562
  124. angr/storage/memory_mixins/__init__.pyi +0 -48
  125. {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/LICENSE +0 -0
  126. {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/WHEEL +0 -0
  127. {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/entry_points.txt +0 -0
  128. {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/top_level.txt +0 -0
@@ -3,10 +3,10 @@ from __future__ import annotations
3
3
 
4
4
  import pyvex
5
5
 
6
- from angr.engines.light import SimEngineLightVEXMixin
6
+ from angr.engines.light import SimEngineLightVEX
7
7
 
8
8
 
9
- class VEXIRSBScanner(SimEngineLightVEXMixin):
9
+ class VEXIRSBScanner(SimEngineLightVEX[None, None, None, None]):
10
10
  """
11
11
  Scan the VEX IRSB to determine if any argument-passing registers should be narrowed by detecting cases of loading
12
12
  the whole register and immediately narrowing the register before writing to the tmp.
@@ -33,22 +33,22 @@ class VEXIRSBScanner(SimEngineLightVEXMixin):
33
33
  self.reg_read_stmt_id: dict[int, int] = {}
34
34
  self.reg_read_stmts_to_ignore: set[int] = set()
35
35
 
36
- def _top(self, size: int):
36
+ def _top(self, bits: int):
37
37
  return None
38
38
 
39
39
  def _is_top(self, expr) -> bool:
40
40
  return True
41
41
 
42
- def _process_Stmt(self, whitelist=None):
42
+ def _process(self, state, *, block=None, whitelist=None, **kwargs):
43
43
  self.tmps_with_64bit_regs = set()
44
44
  self.tmps_assignment_stmtidx = {}
45
45
  self.tmps_converted_to_32bit = set()
46
46
 
47
- super()._process_Stmt(whitelist=whitelist)
47
+ super()._process(state, block=block, whitelist=whitelist, **kwargs)
48
48
 
49
49
  self.stmts_to_lower = {self.tmps_assignment_stmtidx[i] for i in self.tmps_converted_to_32bit}
50
50
 
51
- def _handle_Put(self, stmt):
51
+ def _handle_stmt_Put(self, stmt):
52
52
  if isinstance(stmt.data, pyvex.IRExpr.RdTmp) and stmt.data.tmp in self.tmp_with_reg_as_value:
53
53
  if (
54
54
  stmt.offset in self.reg_with_reg_as_value
@@ -61,25 +61,46 @@ class VEXIRSBScanner(SimEngineLightVEXMixin):
61
61
  self.reg_read_stmts_to_ignore.add(self.reg_read_stmt_id[old_reg_offset])
62
62
  self.reg_with_reg_as_value[stmt.offset] = self.tmp_with_reg_as_value[stmt.data.tmp]
63
63
 
64
- def _handle_PutI(self, stmt):
64
+ def _handle_stmt_PutI(self, stmt):
65
65
  pass
66
66
 
67
- def _handle_Load(self, expr):
67
+ def _handle_expr_Load(self, expr):
68
68
  pass
69
69
 
70
- def _handle_Store(self, stmt):
70
+ def _handle_stmt_Store(self, stmt):
71
71
  pass
72
72
 
73
- def _handle_LoadG(self, stmt):
73
+ def _handle_stmt_LoadG(self, stmt):
74
74
  pass
75
75
 
76
- def _handle_LLSC(self, stmt: pyvex.IRStmt.LLSC):
76
+ def _handle_stmt_LLSC(self, stmt):
77
77
  pass
78
78
 
79
- def _handle_StoreG(self, stmt):
79
+ def _handle_stmt_CAS(self, stmt):
80
80
  pass
81
81
 
82
- def _handle_WrTmp(self, stmt):
82
+ def _handle_stmt_StoreG(self, stmt):
83
+ pass
84
+
85
+ def _handle_stmt_MBE(self, stmt):
86
+ pass
87
+
88
+ def _handle_stmt_Exit(self, stmt):
89
+ pass
90
+
91
+ def _handle_stmt_NoOp(self, stmt):
92
+ pass
93
+
94
+ def _handle_stmt_IMark(self, stmt):
95
+ pass
96
+
97
+ def _handle_stmt_AbiHint(self, stmt):
98
+ pass
99
+
100
+ def _process_block_end(self, stmt_result, whitelist):
101
+ pass
102
+
103
+ def _handle_stmt_WrTmp(self, stmt):
83
104
  if isinstance(stmt.data, pyvex.IRExpr.Get) and stmt.data.result_size(self.tyenv) == 64:
84
105
  self.tmps_with_64bit_regs.add(stmt.tmp)
85
106
  self.tmps_assignment_stmtidx[stmt.tmp] = self.stmt_idx
@@ -87,46 +108,36 @@ class VEXIRSBScanner(SimEngineLightVEXMixin):
87
108
  if isinstance(stmt.data, pyvex.IRExpr.Get) and stmt.data.result_size(self.tyenv) == 64:
88
109
  self.tmp_with_reg_as_value[stmt.tmp] = stmt.data.offset
89
110
 
90
- super()._handle_WrTmp(stmt)
111
+ self.tmps[stmt.tmp] = self._expr(stmt.data)
91
112
 
92
- def _handle_Get(self, expr):
113
+ def _handle_expr_Get(self, expr):
93
114
  self.reg_read_stmt_id[expr.offset] = self.stmt_idx
94
115
  if expr.offset in self.reg_with_reg_as_value:
95
116
  del self.reg_with_reg_as_value[expr.offset]
96
117
 
97
- def _handle_GetI(self, expr):
118
+ def _handle_expr_GetI(self, expr):
98
119
  pass
99
120
 
100
- def _handle_RdTmp(self, expr):
121
+ def _handle_expr_RdTmp(self, expr):
101
122
  if expr.tmp in self.tmps_converted_to_32bit:
102
123
  self.tmps_converted_to_32bit.remove(expr.tmp)
103
124
 
104
- def _handle_Conversion(self, expr: pyvex.IRExpr.Unop):
105
- if expr.op == "Iop_64to32" and isinstance(expr.args[0], pyvex.IRExpr.RdTmp):
106
- # special handling for t11 = GET:I64(rdi); t4 = 64to32(t11) style of code in x86-64 (and other 64-bit
107
- # architectures as well)
108
- tmp_src = expr.args[0].tmp
109
- if tmp_src in self.tmps_with_64bit_regs:
110
- self.tmps_converted_to_32bit.add(tmp_src)
111
-
112
- def _handle_16HLto32(self, expr):
125
+ def _handle_expr_Const(self, expr):
113
126
  pass
114
127
 
115
- def _handle_Cmp_v(self, expr, _vector_size, _vector_count):
128
+ def _handle_expr_ITE(self, expr):
116
129
  pass
117
130
 
118
- _handle_CmpEQ_v = _handle_Cmp_v
119
- _handle_CmpNE_v = _handle_Cmp_v
120
- _handle_CmpLE_v = _handle_Cmp_v
121
- _handle_CmpLT_v = _handle_Cmp_v
122
- _handle_CmpGE_v = _handle_Cmp_v
123
- _handle_CmpGT_v = _handle_Cmp_v
124
-
125
- def _handle_ExpCmpNE64(self, expr):
131
+ def _handle_expr_VECRET(self, expr):
126
132
  pass
127
133
 
128
- def _handle_CCall(self, expr):
134
+ def _handle_expr_GSPTR(self, expr):
129
135
  pass
130
136
 
131
- def _handle_function(self, func_addr):
132
- pass
137
+ def _handle_conversion(self, from_size, to_size, signed, operand):
138
+ if from_size == 64 and to_size == 32 and isinstance(operand, pyvex.IRExpr.RdTmp):
139
+ # special handling for t11 = GET:I64(rdi); t4 = 64to32(t11) style of code in x86-64 (and other 64-bit
140
+ # architectures as well)
141
+ tmp_src = operand.tmp
142
+ if tmp_src in self.tmps_with_64bit_regs:
143
+ self.tmps_converted_to_32bit.add(tmp_src)
@@ -2,11 +2,14 @@ from __future__ import annotations
2
2
  import logging
3
3
  from collections import defaultdict
4
4
 
5
+ import archinfo
5
6
  import claripy
6
7
 
8
+ import angr
7
9
  from angr.analyses import ForwardAnalysis, visitors
8
10
  from angr.analyses import AnalysesHub
9
11
  from angr.errors import SimMemoryMissingError
12
+ from angr.knowledge_plugins.functions.function import Function
10
13
  from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
11
14
  from angr import BP, BP_AFTER
12
15
  from angr.sim_variable import SimRegisterVariable, SimStackVariable
@@ -24,8 +27,26 @@ class VariableRecoveryState(VariableRecoveryStateBase):
24
27
  :ivar angr.knowledge.variable_manager.VariableManager variable_manager: The variable manager.
25
28
  """
26
29
 
27
- def __init__(self, block_addr, analysis, arch, func, concrete_states, stack_region=None, register_region=None):
28
- super().__init__(block_addr, analysis, arch, func, stack_region=stack_region, register_region=register_region)
30
+ def __init__(
31
+ self,
32
+ project: angr.Project,
33
+ block_addr: int,
34
+ analysis,
35
+ arch: archinfo.Arch,
36
+ func: Function,
37
+ concrete_states,
38
+ stack_region=None,
39
+ register_region=None,
40
+ ):
41
+ super().__init__(
42
+ project=project,
43
+ block_addr=block_addr,
44
+ analysis=analysis,
45
+ arch=arch,
46
+ func=func,
47
+ stack_region=stack_region,
48
+ register_region=register_region,
49
+ )
29
50
 
30
51
  self._concrete_states = concrete_states
31
52
  # register callbacks
@@ -50,13 +71,14 @@ class VariableRecoveryState(VariableRecoveryStateBase):
50
71
  """
51
72
 
52
73
  for s in self.concrete_states:
53
- if s.ip.concrete_value == addr:
74
+ if s.addr == addr:
54
75
  return s
55
76
 
56
77
  return None
57
78
 
58
79
  def copy(self):
59
80
  return VariableRecoveryState(
81
+ self.project,
60
82
  self.block_addr,
61
83
  self._analysis,
62
84
  self.arch,
@@ -88,7 +110,7 @@ class VariableRecoveryState(VariableRecoveryStateBase):
88
110
  )
89
111
  concrete_state.inspect.add_breakpoint("mem_write", BP(enabled=True, action=self._hook_memory_write))
90
112
 
91
- def merge(self, others: tuple[VariableRecoveryState], successor=None) -> tuple[VariableRecoveryState, bool]:
113
+ def merge(self, others: tuple[VariableRecoveryState, ...], successor=None) -> tuple[VariableRecoveryState, bool]:
92
114
  """
93
115
  Merge two abstract states.
94
116
 
@@ -115,6 +137,7 @@ class VariableRecoveryState(VariableRecoveryStateBase):
115
137
 
116
138
  return (
117
139
  VariableRecoveryState(
140
+ self.project,
118
141
  successor,
119
142
  self._analysis,
120
143
  self.arch,
@@ -477,7 +500,7 @@ class VariableRecovery(ForwardAnalysis, VariableRecoveryBase): # pylint:disable
477
500
  # give it enough stack space
478
501
  concrete_state.regs.bp = concrete_state.regs.sp + 0x100000
479
502
 
480
- return VariableRecoveryState(node.addr, self, self.project.arch, self.function, [concrete_state])
503
+ return VariableRecoveryState(self.project, node.addr, self, self.project.arch, self.function, [concrete_state])
481
504
 
482
505
  def _merge_states(self, node, *states: VariableRecoveryState):
483
506
  if len(states) == 1:
@@ -1,17 +1,19 @@
1
1
  from __future__ import annotations
2
2
  import weakref
3
- from typing import Any, TYPE_CHECKING
3
+ from typing import Any, TYPE_CHECKING, cast, TypeVar
4
4
  from collections.abc import Generator, Iterable
5
5
  import logging
6
6
  from collections import defaultdict
7
7
 
8
+ import archinfo
8
9
  import claripy
9
10
  from claripy.annotation import Annotation
10
11
  from archinfo import Arch
11
12
  from ailment.expression import BinaryOp, StackBaseOffset
12
13
 
14
+ from angr.knowledge_plugins.functions.function import Function
15
+ from angr.project import Project
13
16
  from angr.utils.cowdict import DefaultChainMapCOW
14
- from angr.engines.light import SpOffset
15
17
  from angr.sim_variable import SimVariable
16
18
  from angr.errors import AngrRuntimeError
17
19
  from angr.storage.memory_mixins import MultiValuedMemory
@@ -24,6 +26,8 @@ if TYPE_CHECKING:
24
26
 
25
27
  l = logging.getLogger(name=__name__)
26
28
 
29
+ AnyClaripy = TypeVar("AnyClaripy", bound=claripy.ast.Base)
30
+
27
31
 
28
32
  def parse_stack_pointer(sp):
29
33
  """
@@ -152,10 +156,11 @@ class VariableRecoveryStateBase:
152
156
 
153
157
  def __init__(
154
158
  self,
155
- block_addr,
156
- analysis,
157
- arch,
158
- func,
159
+ block_addr: int,
160
+ analysis: VariableRecoveryBase,
161
+ arch: archinfo.Arch,
162
+ func: Function,
163
+ project: Project,
159
164
  stack_region=None,
160
165
  register_region=None,
161
166
  global_region=None,
@@ -164,7 +169,6 @@ class VariableRecoveryStateBase:
164
169
  func_typevar=None,
165
170
  delayed_type_constraints=None,
166
171
  stack_offset_typevars=None,
167
- project=None,
168
172
  ):
169
173
  self.block_addr = block_addr
170
174
  self._analysis = analysis
@@ -246,18 +250,16 @@ class VariableRecoveryStateBase:
246
250
  return bool(isinstance(thing, claripy.ast.BV) and thing.op == "BVS" and thing.args[0] == "top")
247
251
 
248
252
  @staticmethod
249
- def extract_variables(expr: claripy.ast.Base) -> Generator[tuple[int, SimVariable | SpOffset]]:
253
+ def extract_variables(expr: claripy.ast.Base) -> Generator[tuple[int, SimVariable]]:
250
254
  for anno in expr.annotations:
251
255
  if isinstance(anno, VariableAnnotation):
252
256
  yield from anno.addr_and_variables
253
257
 
254
258
  @staticmethod
255
- def annotate_with_variables(
256
- expr: claripy.ast.Base, addr_and_variables: Iterable[tuple[int, SimVariable | SpOffset]]
257
- ) -> claripy.ast.Base:
259
+ def annotate_with_variables(expr: AnyClaripy, addr_and_variables: Iterable[tuple[int, SimVariable]]) -> AnyClaripy:
258
260
  return expr.replace_annotations((VariableAnnotation(list(addr_and_variables)),))
259
261
 
260
- def stack_address(self, offset: int) -> claripy.ast.Base:
262
+ def stack_address(self, offset: int) -> claripy.ast.BV:
261
263
  base = claripy.BVS("stack_base", self.arch.bits, explicit_name=True)
262
264
  if offset:
263
265
  return base + offset
@@ -267,9 +269,9 @@ class VariableRecoveryStateBase:
267
269
  def is_stack_address(addr: claripy.ast.Base) -> bool:
268
270
  return "stack_base" in addr.variables
269
271
 
270
- def is_global_variable_address(self, addr: claripy.ast.Base) -> bool:
272
+ def is_global_variable_address(self, addr: claripy.ast.Bits) -> bool:
271
273
  if addr.op == "BVV":
272
- addr_v = addr.concrete_value
274
+ addr_v = cast(claripy.ast.BV, addr).concrete_value
273
275
  # make sure it is within a mapped region
274
276
  obj = self.project.loader.find_object_containing(addr_v)
275
277
  if obj is not None:
@@ -277,45 +279,42 @@ class VariableRecoveryStateBase:
277
279
  return False
278
280
 
279
281
  @staticmethod
280
- def extract_stack_offset_from_addr(addr: claripy.ast.Base) -> claripy.ast.Base | None:
282
+ def _get_stack_offset(addr: claripy.ast.Bits) -> int | None:
283
+ # recursive function that returns a python int without really trying to handle bitvector arithmetic wrapping
281
284
  r = None
282
285
  if addr.op == "BVS":
283
286
  if addr.args[0] == "stack_base":
284
- return claripy.BVV(0, addr.size())
287
+ return 0
285
288
  return None
286
289
  if addr.op == "BVV":
287
- r = addr
290
+ r = cast(int, addr.concrete_value)
288
291
  elif addr.op == "__add__":
289
292
  arg_offsets = []
290
- for arg in addr.args:
291
- arg_offset = VariableRecoveryStateBase.extract_stack_offset_from_addr(arg)
293
+ for arg in cast(list[claripy.ast.BV], addr.args):
294
+ arg_offset = VariableRecoveryStateBase._get_stack_offset(arg)
292
295
  if arg_offset is None:
293
296
  return None
294
297
  arg_offsets.append(arg_offset)
295
298
  r = sum(arg_offsets)
296
299
  elif addr.op == "__sub__":
297
- r1 = VariableRecoveryStateBase.extract_stack_offset_from_addr(addr.args[0])
298
- r2 = VariableRecoveryStateBase.extract_stack_offset_from_addr(addr.args[1])
300
+ r1 = VariableRecoveryStateBase._get_stack_offset(cast(claripy.ast.BV, addr.args[0]))
301
+ r2 = VariableRecoveryStateBase._get_stack_offset(cast(claripy.ast.BV, addr.args[1]))
299
302
  if r1 is None or r2 is None:
300
303
  return None
301
304
  r = r1 - r2
302
305
  return r
303
306
 
304
- def get_stack_offset(self, addr: claripy.ast.Base) -> int | None:
307
+ def get_stack_offset(self, addr: claripy.ast.Bits) -> int | None:
305
308
  if "stack_base" in addr.variables:
306
- r = VariableRecoveryStateBase.extract_stack_offset_from_addr(addr)
307
- if r is None:
309
+ val = VariableRecoveryStateBase._get_stack_offset(addr)
310
+ if val is None:
308
311
  return None
309
312
 
310
- # extract_stack_offset_from_addr should ensure that r is a BVV
311
- assert r.concrete
312
-
313
- val = r.concrete_value
314
313
  # convert it to a signed integer
315
- if val >= 2 ** (self.arch.bits - 1):
316
- return val - 2**self.arch.bits
317
- if val < -(2 ** (self.arch.bits - 1)):
318
- return 2**self.arch.bits + val
314
+ while val >= 2 ** (self.arch.bits - 1):
315
+ val -= 2**self.arch.bits
316
+ while val < -(2 ** (self.arch.bits - 1)):
317
+ val += 2**self.arch.bits
319
318
  return val
320
319
 
321
320
  return None
@@ -414,7 +413,7 @@ class VariableRecoveryStateBase:
414
413
 
415
414
  return mos_self == mos_other
416
415
 
417
- def _make_phi_variable(self, values: set[claripy.ast.Base]) -> claripy.ast.Base | None:
416
+ def _make_phi_variable(self, values: set[claripy.ast.BV | claripy.ast.FP]) -> claripy.ast.Base | None:
418
417
  # we only create a new phi variable if the there is at least one variable involved
419
418
  variables = set()
420
419
  bits: int | None = None
@@ -288,8 +288,8 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
288
288
 
289
289
  # cleanup (for cpython pickle)
290
290
  self.downsize()
291
- self._ail_engine = None
292
- self._vex_engine = None
291
+ del self._ail_engine
292
+ del self._vex_engine
293
293
 
294
294
  #
295
295
  # Main analysis routines
angr/analyses/xrefs.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
  from collections import defaultdict
3
+ from typing import cast
3
4
 
4
5
  import claripy
5
6
  import pyvex
@@ -7,27 +8,29 @@ import pyvex
7
8
  from angr.analyses import visitors, ForwardAnalysis
8
9
  from angr.knowledge_plugins.xrefs import XRef, XRefType
9
10
  from angr.knowledge_plugins.functions.function import Function
10
- from angr.engines.light import SimEngineLight, SimEngineLightVEXMixin
11
+ from angr.engines.light import SimEngineNostmtVEX
11
12
  from .propagator.vex_vars import VEXTmp
12
13
  from .propagator.values import Top
13
14
  from . import register_analysis, PropagatorAnalysis
14
15
  from .analysis import Analysis
15
16
 
16
17
 
17
- class SimEngineXRefsVEX(
18
- SimEngineLightVEXMixin,
19
- SimEngineLight,
20
- ):
18
+ class SimEngineXRefsVEX(SimEngineNostmtVEX[None, None, None]): # go girl give us nothing!!
21
19
  """
22
20
  The VEX engine class for XRefs analysis.
23
21
  """
24
22
 
25
- def __init__(self, xref_manager, project=None, replacements=None):
26
- super().__init__()
27
- self.project = project
23
+ def __init__(self, xref_manager, project, replacements=None):
24
+ super().__init__(project)
28
25
  self.xref_manager = xref_manager
29
26
  self.replacements = replacements if replacements is not None else {}
30
27
 
28
+ def _top(self, bits):
29
+ return None
30
+
31
+ def _is_top(self, expr):
32
+ return True
33
+
31
34
  def add_xref(self, xref_type, from_loc, to_loc):
32
35
  self.xref_manager.add_xref(
33
36
  XRef(
@@ -49,24 +52,27 @@ class SimEngineXRefsVEX(
49
52
  """
50
53
 
51
54
  if isinstance(expr, claripy.ast.Base) and expr.op == "BVV":
52
- return expr.args[0]
55
+ return cast(int, expr.args[0])
56
+ return None
57
+
58
+ def _process_block_end(self, stmt_result, whitelist):
53
59
  return None
54
60
 
55
61
  #
56
62
  # Statement handlers
57
63
  #
58
64
 
59
- def _handle_WrTmp(self, stmt):
65
+ def _handle_stmt_WrTmp(self, stmt):
60
66
  # Don't execute the tmp write since it has been done during constant propagation
61
67
  self._expr(stmt.data)
62
68
  if type(stmt.data) is pyvex.IRExpr.Load:
63
69
  self._handle_data_offset_refs(stmt.tmp)
64
70
 
65
- def _handle_Put(self, stmt):
71
+ def _handle_stmt_Put(self, stmt):
66
72
  # if there is a Load, get it executed
67
73
  self._expr(stmt.data)
68
74
 
69
- def _handle_Store(self, stmt):
75
+ def _handle_stmt_Store(self, stmt):
70
76
  if isinstance(stmt.addr, pyvex.IRExpr.RdTmp):
71
77
  addr_tmp = VEXTmp(stmt.addr.tmp)
72
78
  blockloc = self._codeloc(block_only=True)
@@ -79,7 +85,7 @@ class SimEngineXRefsVEX(
79
85
  addr = stmt.addr.con.value
80
86
  self.add_xref(XRefType.Write, self._codeloc(), addr)
81
87
 
82
- def _handle_StoreG(self, stmt):
88
+ def _handle_stmt_StoreG(self, stmt):
83
89
  blockloc = self._codeloc(block_only=True)
84
90
  if type(stmt.addr) is pyvex.IRExpr.RdTmp:
85
91
  addr_tmp = VEXTmp(stmt.addr.tmp)
@@ -89,7 +95,7 @@ class SimEngineXRefsVEX(
89
95
  if addr_v is not None:
90
96
  self.add_xref(XRefType.Write, self._codeloc(), addr_v)
91
97
 
92
- def _handle_LoadG(self, stmt):
98
+ def _handle_stmt_LoadG(self, stmt):
93
99
  # What are we reading?
94
100
  blockloc = self._codeloc(block_only=True)
95
101
  if type(stmt.addr) is pyvex.IRExpr.RdTmp:
@@ -101,7 +107,7 @@ class SimEngineXRefsVEX(
101
107
  self.add_xref(XRefType.Read, self._codeloc(), addr_v)
102
108
  self._handle_data_offset_refs(stmt.dst)
103
109
 
104
- def _handle_LLSC(self, stmt: pyvex.IRStmt.LLSC):
110
+ def _handle_stmt_LLSC(self, stmt: pyvex.IRStmt.LLSC):
105
111
  blockloc = self._codeloc(block_only=True)
106
112
  if isinstance(stmt.addr, pyvex.IRExpr.RdTmp):
107
113
  addr_tmp = VEXTmp(stmt.addr.tmp)
@@ -135,10 +141,16 @@ class SimEngineXRefsVEX(
135
141
  # Expression handlers
136
142
  #
137
143
 
138
- def _handle_Get(self, expr):
144
+ def _handle_conversion(self, from_size, to_size, signed, operand):
139
145
  return None
140
146
 
141
- def _handle_Load(self, expr):
147
+ def _handle_expr_Const(self, expr):
148
+ return None
149
+
150
+ def _handle_expr_Get(self, expr):
151
+ return None
152
+
153
+ def _handle_expr_Load(self, expr):
142
154
  blockloc = self._codeloc(block_only=True)
143
155
  if type(expr.addr) is pyvex.IRExpr.RdTmp:
144
156
  addr_tmp = VEXTmp(expr.addr.tmp)
@@ -151,7 +163,22 @@ class SimEngineXRefsVEX(
151
163
  addr = expr.addr.con.value
152
164
  self.add_xref(XRefType.Read, self._codeloc(), addr)
153
165
 
154
- def _handle_CCall(self, expr):
166
+ def _handle_expr_CCall(self, expr):
167
+ return None
168
+
169
+ def _handle_expr_VECRET(self, expr):
170
+ return None
171
+
172
+ def _handle_expr_GSPTR(self, expr):
173
+ return None
174
+
175
+ def _handle_expr_ITE(self, expr):
176
+ return None
177
+
178
+ def _handle_expr_RdTmp(self, expr):
179
+ return None
180
+
181
+ def _handle_expr_GetI(self, expr):
155
182
  return None
156
183
 
157
184
  def _handle_function(self, func):
@@ -231,7 +258,7 @@ class XRefsAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-metho
231
258
  return None
232
259
 
233
260
  def _merge_states(self, node, *states):
234
- return None
261
+ return None, False
235
262
 
236
263
  def _run_on_node(self, node, state):
237
264
  block = self.project.factory.block(node.addr, node.size, opt_level=1, cross_insn_opt=False)
angr/annocfg.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from collections import defaultdict
3
3
  import logging
4
+ from typing import Literal
4
5
 
5
6
  import networkx
6
7
 
@@ -30,7 +31,7 @@ class AnnotatedCFG:
30
31
  self._cfg = None
31
32
  self._target = None
32
33
 
33
- self._run_statement_whitelist: dict[int, list[int] | bool] = defaultdict(list)
34
+ self._run_statement_whitelist: dict[int, list[int] | Literal[True]] = defaultdict(list)
34
35
  self._exit_taken = defaultdict(list)
35
36
  self._addr_to_run = {}
36
37
  self._addr_to_last_stmt_id = {}
@@ -76,6 +77,7 @@ class AnnotatedCFG:
76
77
 
77
78
  def get_addr(self, run):
78
79
  if isinstance(run, CFGNode):
80
+ assert isinstance(run.addr, int)
79
81
  return run.addr
80
82
  if type(run) is int:
81
83
  return run
@@ -87,17 +89,18 @@ class AnnotatedCFG:
87
89
 
88
90
  def add_statements_to_whitelist(self, block, stmt_ids):
89
91
  addr = self.get_addr(block)
90
- if type(stmt_ids) is bool:
92
+ if stmt_ids is True:
91
93
  if type(self._run_statement_whitelist[addr]) is list and self._run_statement_whitelist[addr]:
92
94
  raise Exception("WTF")
93
95
  self._run_statement_whitelist[addr] = stmt_ids
94
96
  elif -1 in stmt_ids:
95
97
  self._run_statement_whitelist[addr] = True
96
98
  else:
97
- self._run_statement_whitelist[addr].extend(stmt_ids)
98
- self._run_statement_whitelist[addr] = sorted(
99
- set(self._run_statement_whitelist[addr]), key=lambda v: v if type(v) is int else float("inf")
100
- )
99
+ whitelist_lst = self._run_statement_whitelist[addr]
100
+ assert whitelist_lst is not True
101
+ whitelist = set(whitelist_lst)
102
+ whitelist.update(stmt_ids)
103
+ self._run_statement_whitelist[addr] = sorted(whitelist)
101
104
 
102
105
  def add_exit_to_whitelist(self, run_from, run_to):
103
106
  addr_from = self.get_addr(run_from)
@@ -135,17 +138,18 @@ class AnnotatedCFG:
135
138
  return self._addr_to_run[addr]
136
139
  return None
137
140
 
138
- def get_whitelisted_statements(self, addr):
141
+ def get_whitelisted_statements(self, addr) -> list[int] | None:
139
142
  """
140
143
  :returns: True if all statements are whitelisted
141
144
  """
142
145
  if addr in self._run_statement_whitelist:
143
- if self._run_statement_whitelist[addr] is True:
146
+ whitelist = self._run_statement_whitelist[addr]
147
+ if whitelist is True:
144
148
  return None # This is the default value used to say
145
149
  # we execute all statements in this basic block. A
146
150
  # little weird...
147
151
 
148
- return self._run_statement_whitelist[addr]
152
+ return whitelist
149
153
 
150
154
  return []
151
155
 
@@ -166,12 +170,12 @@ class AnnotatedCFG:
166
170
  return self._addr_to_last_stmt_id[addr]
167
171
  if addr in self._run_statement_whitelist:
168
172
  # is the default exit there? it equals to a negative number (-2 by default) so `max()` won't work.
169
- if self._run_statement_whitelist[addr] is True or (
170
- isinstance(self._run_statement_whitelist[addr], list)
171
- and DEFAULT_STATEMENT in self._run_statement_whitelist[addr]
173
+ whitelist = self._run_statement_whitelist[addr]
174
+ if whitelist is True or (
175
+ isinstance(self._run_statement_whitelist[addr], list) and DEFAULT_STATEMENT in whitelist
172
176
  ):
173
177
  return DEFAULT_STATEMENT
174
- return max(self._run_statement_whitelist[addr], key=lambda v: v if type(v) is int else float("inf"))
178
+ return max(whitelist, key=lambda v: v if type(v) is int else float("inf"))
175
179
  return None
176
180
 
177
181
  def get_loops(self):
@@ -224,7 +228,7 @@ class AnnotatedCFG:
224
228
  statements = vex_block.statements
225
229
  whitelist = self.get_whitelisted_statements(irsb_addr)
226
230
  for i in range(len(statements)):
227
- line = "+" if whitelist is True or i in whitelist else "-"
231
+ line = "+" if whitelist is None or i in whitelist else "-"
228
232
  line += "[% 3d] " % i
229
233
  # We cannot get data returned by pp(). WTF?
230
234
  print(line, end="")
@@ -301,6 +305,7 @@ class AnnotatedCFG:
301
305
 
302
306
  def _detect_loops(self):
303
307
  temp_graph = networkx.DiGraph()
308
+ assert self._cfg is not None
304
309
  for source, target_list in self._cfg._edge_map.items():
305
310
  for target in target_list:
306
311
  temp_graph.add_edge(source, target)