angr 9.2.139__py3-none-manylinux2014_aarch64.whl → 9.2.141__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 (87) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/calling_convention.py +136 -53
  3. angr/analyses/calling_convention/fact_collector.py +44 -18
  4. angr/analyses/calling_convention/utils.py +3 -1
  5. angr/analyses/cfg/cfg_base.py +13 -0
  6. angr/analyses/cfg/cfg_fast.py +11 -0
  7. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +9 -8
  8. angr/analyses/decompiler/ail_simplifier.py +115 -72
  9. angr/analyses/decompiler/callsite_maker.py +24 -11
  10. angr/analyses/decompiler/clinic.py +78 -43
  11. angr/analyses/decompiler/decompiler.py +18 -7
  12. angr/analyses/decompiler/expression_narrower.py +1 -1
  13. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
  14. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +3 -1
  15. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +21 -2
  16. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
  17. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +84 -15
  18. angr/analyses/decompiler/optimization_passes/optimization_pass.py +92 -11
  19. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +53 -9
  20. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +44 -7
  21. angr/analyses/decompiler/region_identifier.py +6 -4
  22. angr/analyses/decompiler/region_simplifiers/expr_folding.py +287 -122
  23. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +31 -13
  24. angr/analyses/decompiler/ssailification/rewriting.py +23 -15
  25. angr/analyses/decompiler/ssailification/rewriting_engine.py +105 -24
  26. angr/analyses/decompiler/ssailification/ssailification.py +22 -14
  27. angr/analyses/decompiler/structured_codegen/c.py +73 -137
  28. angr/analyses/decompiler/structuring/dream.py +22 -18
  29. angr/analyses/decompiler/structuring/phoenix.py +158 -41
  30. angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
  31. angr/analyses/decompiler/structuring/structurer_base.py +37 -10
  32. angr/analyses/decompiler/structuring/structurer_nodes.py +4 -1
  33. angr/analyses/decompiler/utils.py +106 -21
  34. angr/analyses/deobfuscator/api_obf_finder.py +8 -5
  35. angr/analyses/deobfuscator/api_obf_type2_finder.py +18 -10
  36. angr/analyses/deobfuscator/string_obf_finder.py +105 -18
  37. angr/analyses/forward_analysis/forward_analysis.py +1 -1
  38. angr/analyses/propagator/top_checker_mixin.py +6 -6
  39. angr/analyses/reaching_definitions/__init__.py +2 -1
  40. angr/analyses/reaching_definitions/dep_graph.py +1 -12
  41. angr/analyses/reaching_definitions/engine_vex.py +36 -31
  42. angr/analyses/reaching_definitions/function_handler.py +15 -2
  43. angr/analyses/reaching_definitions/rd_state.py +1 -37
  44. angr/analyses/reaching_definitions/reaching_definitions.py +13 -24
  45. angr/analyses/s_propagator.py +6 -41
  46. angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
  47. angr/analyses/s_reaching_definitions/s_rda_view.py +43 -25
  48. angr/analyses/stack_pointer_tracker.py +36 -22
  49. angr/analyses/typehoon/simple_solver.py +45 -7
  50. angr/analyses/typehoon/typeconsts.py +18 -5
  51. angr/analyses/variable_recovery/engine_ail.py +1 -1
  52. angr/analyses/variable_recovery/engine_base.py +7 -5
  53. angr/analyses/variable_recovery/engine_vex.py +20 -4
  54. angr/block.py +69 -107
  55. angr/callable.py +14 -7
  56. angr/calling_conventions.py +30 -11
  57. angr/distributed/__init__.py +1 -1
  58. angr/engines/__init__.py +7 -8
  59. angr/engines/engine.py +1 -120
  60. angr/engines/failure.py +2 -2
  61. angr/engines/hook.py +2 -2
  62. angr/engines/light/engine.py +2 -2
  63. angr/engines/pcode/engine.py +2 -14
  64. angr/engines/procedure.py +2 -2
  65. angr/engines/soot/engine.py +2 -2
  66. angr/engines/soot/statements/switch.py +1 -1
  67. angr/engines/successors.py +124 -11
  68. angr/engines/syscall.py +2 -2
  69. angr/engines/unicorn.py +3 -3
  70. angr/engines/vex/heavy/heavy.py +3 -15
  71. angr/factory.py +12 -22
  72. angr/knowledge_plugins/key_definitions/atoms.py +8 -4
  73. angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
  74. angr/knowledge_plugins/variables/variable_manager.py +7 -5
  75. angr/sim_type.py +19 -17
  76. angr/simos/simos.py +3 -1
  77. angr/state_plugins/plugin.py +19 -4
  78. angr/storage/memory_mixins/memory_mixin.py +1 -1
  79. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +10 -5
  80. angr/utils/ssa/__init__.py +119 -4
  81. angr/utils/types.py +48 -0
  82. {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/METADATA +6 -6
  83. {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/RECORD +87 -86
  84. {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/LICENSE +0 -0
  85. {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/WHEEL +0 -0
  86. {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/entry_points.txt +0 -0
  87. {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import cast
3
+ from typing import Any, Generic, cast, TypeVar, Protocol
4
+ from collections.abc import Callable
4
5
 
5
6
  import logging
6
7
 
@@ -9,6 +10,18 @@ from angr.misc.ux import once
9
10
 
10
11
  l = logging.getLogger(name=__name__)
11
12
 
13
+ T = TypeVar("T")
14
+ S_co = TypeVar("S_co", covariant=True)
15
+
16
+
17
+ class _CopyFunc(Protocol, Generic[S_co]):
18
+ """
19
+ Function wrapping copy method for memo tracking.
20
+ """
21
+
22
+ @staticmethod
23
+ def __call__(memo: dict[int, Any] | None = None) -> S_co: ...
24
+
12
25
 
13
26
  class SimStatePlugin:
14
27
  """
@@ -55,12 +68,12 @@ class SimStatePlugin:
55
68
  return o
56
69
 
57
70
  @staticmethod
58
- def memo(f):
71
+ def memo(f: Callable[[T, dict[int, Any]], S_co]) -> _CopyFunc[S_co]:
59
72
  """
60
73
  A decorator function you should apply to ``copy``
61
74
  """
62
75
 
63
- def inner(self, memo=None, **kwargs):
76
+ def inner(self, memo: dict[int, Any] | None = None, **kwargs: Any) -> S_co:
64
77
  if memo is None:
65
78
  memo = {}
66
79
  if id(self) in memo:
@@ -69,7 +82,9 @@ class SimStatePlugin:
69
82
  memo[id(self)] = c
70
83
  return c
71
84
 
72
- return inner
85
+ # Type-checking fails here because we can't express the `self` partial-application with a Protocol
86
+ # and we can't express the optional `memo` parameter without a Protocol
87
+ return inner # type: ignore
73
88
 
74
89
  def merge(self, others, merge_conditions, common_ancestor=None): # pylint:disable=unused-argument
75
90
  """
@@ -80,7 +80,7 @@ class MemoryMixin(Generic[InData, OutData, Addr], SimStatePlugin):
80
80
  def store(self, addr: Addr, data: InData, size: InData | None = None, **kwargs) -> None: ...
81
81
 
82
82
  def merge(
83
- self, others: list[Self], merge_conditions: list[claripy.ast.Bool], common_ancestor: Self | None = None
83
+ self, others: list[Self], merge_conditions: list[claripy.ast.Bool] | None, common_ancestor: Self | None = None
84
84
  ) -> bool: ...
85
85
 
86
86
  def compare(self, other: Self) -> bool: ...
@@ -5,7 +5,6 @@ import archinfo
5
5
 
6
6
  import claripy
7
7
 
8
- from angr.errors import AngrTypeError
9
8
  from angr.storage.memory_object import bv_slice
10
9
 
11
10
  MVType = TypeVar("MVType", bound=claripy.ast.BV | claripy.ast.FP)
@@ -91,8 +90,10 @@ class MultiValues(Generic[MVType]):
91
90
  value_end = offset + value.size() // 8
92
91
  if value_end > succ_offset:
93
92
  if isinstance(value, claripy.ast.FP):
94
- raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
93
+ # no precise floating point support; it directly goes to TOP
94
+ value = cast(MVType, claripy.BVS("top", value.size()))
95
95
  # value is too long. we need to break value into two
96
+ assert isinstance(value, claripy.ast.BV)
96
97
  mid_value_size = succ_offset - offset
97
98
  remaining_value = cast(MVType, value[value.size() - mid_value_size * 8 - 1 : 0])
98
99
  # update value
@@ -107,7 +108,8 @@ class MultiValues(Generic[MVType]):
107
108
  remaining_values = set()
108
109
  for v in self._values[offset]:
109
110
  if isinstance(v, claripy.ast.FP):
110
- raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
111
+ # no precise floating point support; it directly goes to TOP
112
+ v = claripy.BVS("top", v.size())
111
113
 
112
114
  new_curr_values.add(v[v.size() - 1 : v.size() - value.size()])
113
115
  remaining_values.add(v[v.size() - value.size() - 1 : 0])
@@ -116,9 +118,11 @@ class MultiValues(Generic[MVType]):
116
118
  self.add_value(offset + value.size() // 8, v)
117
119
  elif curr_value_size < value.size() // 8:
118
120
  if isinstance(value, claripy.ast.FP):
119
- raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
121
+ # no precise floating point support; it directly goes to TOP
122
+ value = cast(MVType, claripy.BVS("top", value.size()))
120
123
 
121
124
  # value is too long. we need to break value into two
125
+ assert isinstance(value, claripy.ast.BV)
122
126
  remaining_value = cast(MVType, value[value.size() - curr_value_size * 8 - 1 : 0])
123
127
  # update value
124
128
  value = cast(MVType, value[value.size() - 1 : value.size() - curr_value_size * 8])
@@ -137,7 +141,8 @@ class MultiValues(Generic[MVType]):
137
141
  remaining_values = set()
138
142
  for v in pre_values:
139
143
  if isinstance(v, claripy.ast.FP):
140
- raise AngrTypeError("Unsupported case. How do we handle floating point values overlapping?")
144
+ # no precise floating point support; it directly goes to TOP
145
+ v = claripy.BVS("top", v.size())
141
146
  new_pre_values.add(v[v.size() - 1 : v.size() - new_pre_value_size * 8])
142
147
  remaining_values.add(v[v.size() - new_pre_value_size * 8 - 1 : 0])
143
148
  self._values[pre_offset] = new_pre_values
@@ -1,11 +1,14 @@
1
1
  from __future__ import annotations
2
2
  from collections import defaultdict
3
+ from collections.abc import Callable
3
4
  from typing import Any, Literal, overload
4
5
 
6
+ import networkx
7
+
5
8
  import archinfo
6
9
  from ailment import Expression, Block
7
10
  from ailment.expression import VirtualVariable, Const, Phi, Tmp, Load, Register, StackBaseOffset, DirtyExpression, ITE
8
- from ailment.statement import Statement, Assignment, Call
11
+ from ailment.statement import Statement, Assignment, Call, Store
9
12
  from ailment.block_walker import AILBlockWalkerBase
10
13
 
11
14
  from angr.knowledge_plugins.key_definitions import atoms
@@ -153,19 +156,41 @@ class AILBlacklistExprTypeWalker(AILBlockWalkerBase):
153
156
  Walks an AIL expression or statement and determines if it does not contain certain types of expressions.
154
157
  """
155
158
 
156
- def __init__(self, blacklist_expr_types: tuple[type, ...]):
159
+ def __init__(self, blacklist_expr_types: tuple[type, ...], skip_if_contains_vvar: int | None = None):
157
160
  super().__init__()
158
161
  self.blacklist_expr_types = blacklist_expr_types
159
162
  self.has_blacklisted_exprs = False
163
+ self.skip_if_contains_vvar = skip_if_contains_vvar
164
+
165
+ self._has_specified_vvar = False
160
166
 
161
167
  def _handle_expr(
162
168
  self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
163
169
  ) -> Any:
164
170
  if isinstance(expr, self.blacklist_expr_types):
165
- self.has_blacklisted_exprs = True
166
- return None
171
+ if self.skip_if_contains_vvar is None:
172
+ self.has_blacklisted_exprs = True
173
+ return None
174
+ # otherwise we do a more complicated check
175
+ self._has_specified_vvar = False # we do not support nested blacklisted expr types
176
+ has_blacklisted_exprs = True
177
+ r = super()._handle_expr(expr_idx, expr, stmt_idx, stmt, block)
178
+ if self._has_specified_vvar is False:
179
+ # we have seen the vvar that we are looking for! ignore this match
180
+ self.has_blacklisted_exprs = has_blacklisted_exprs
181
+ return None
182
+ self._has_specified_vvar = False
183
+ return r
184
+
167
185
  return super()._handle_expr(expr_idx, expr, stmt_idx, stmt, block)
168
186
 
187
+ def _handle_VirtualVariable(
188
+ self, expr_idx: int, expr: VirtualVariable, stmt_idx: int, stmt: Statement, block: Block | None
189
+ ):
190
+ if self.skip_if_contains_vvar is not None and expr.varid == self.skip_if_contains_vvar:
191
+ self._has_specified_vvar = True
192
+ return super()._handle_VirtualVariable(expr_idx, expr, stmt_idx, stmt, block)
193
+
169
194
 
170
195
  def is_const_and_vvar_assignment(stmt: Statement) -> bool:
171
196
  if isinstance(stmt, Assignment):
@@ -203,6 +228,12 @@ def is_phi_assignment(stmt: Statement) -> bool:
203
228
  return isinstance(stmt, Assignment) and isinstance(stmt.src, Phi)
204
229
 
205
230
 
231
+ def has_load_expr(stmt: Statement, skip_if_contains_vvar: int | None = None) -> bool:
232
+ walker = AILBlacklistExprTypeWalker((Load,), skip_if_contains_vvar=skip_if_contains_vvar)
233
+ walker.walk_statement(stmt)
234
+ return walker.has_blacklisted_exprs
235
+
236
+
206
237
  def phi_assignment_get_src(stmt: Statement) -> Phi | None:
207
238
  if isinstance(stmt, Assignment) and isinstance(stmt.src, Phi):
208
239
  return stmt.src
@@ -225,13 +256,97 @@ def has_ite_stmt(stmt: Statement) -> bool:
225
256
  return walker.has_blacklisted_exprs
226
257
 
227
258
 
259
+ def check_in_between_stmts(
260
+ graph: networkx.DiGraph,
261
+ blocks: dict[tuple[int, int | None], Block],
262
+ defloc: CodeLocation,
263
+ useloc: CodeLocation,
264
+ predicate: Callable,
265
+ ):
266
+ assert defloc.block_addr is not None
267
+ assert defloc.stmt_idx is not None
268
+ assert useloc.block_addr is not None
269
+ assert useloc.stmt_idx is not None
270
+ assert graph is not None
271
+
272
+ use_block = blocks[(useloc.block_addr, useloc.block_idx)]
273
+ def_block = blocks[(defloc.block_addr, defloc.block_idx)]
274
+
275
+ # traverse the graph, go from use_block until we reach def_block, and look for Store statements
276
+ seen = {use_block}
277
+ queue = [use_block]
278
+ while queue:
279
+ block = queue.pop(0)
280
+
281
+ starting_stmt_idx, ending_stmt_idx = 0, len(block.statements)
282
+ if block is def_block:
283
+ starting_stmt_idx = defloc.stmt_idx + 1
284
+ if block is use_block:
285
+ ending_stmt_idx = useloc.stmt_idx
286
+
287
+ for i in range(starting_stmt_idx, ending_stmt_idx):
288
+ if predicate(block.statements[i]):
289
+ return True
290
+
291
+ if block is def_block:
292
+ continue
293
+
294
+ for pred in graph.predecessors(block):
295
+ if pred not in seen:
296
+ seen.add(pred)
297
+ queue.append(pred)
298
+
299
+ return False
300
+
301
+
302
+ def has_store_stmt_in_between_stmts(
303
+ graph: networkx.DiGraph, blocks: dict[tuple[int, int | None], Block], defloc: CodeLocation, useloc: CodeLocation
304
+ ) -> bool:
305
+ return check_in_between_stmts(graph, blocks, defloc, useloc, lambda stmt: isinstance(stmt, Store))
306
+
307
+
308
+ def has_call_in_between_stmts(
309
+ graph: networkx.DiGraph,
310
+ blocks: dict[tuple[int, int | None], Block],
311
+ defloc: CodeLocation,
312
+ useloc: CodeLocation,
313
+ skip_if_contains_vvar: int | None = None,
314
+ ) -> bool:
315
+
316
+ def _contains_call(stmt: Statement) -> bool:
317
+ if isinstance(stmt, Call):
318
+ return True
319
+ # walk the statement and check if there is a call expression
320
+ walker = AILBlacklistExprTypeWalker((Call,), skip_if_contains_vvar=skip_if_contains_vvar)
321
+ walker.walk_statement(stmt)
322
+ return walker.has_blacklisted_exprs
323
+
324
+ return check_in_between_stmts(graph, blocks, defloc, useloc, _contains_call)
325
+
326
+
327
+ def has_load_expr_in_between_stmts(
328
+ graph: networkx.DiGraph,
329
+ blocks: dict[tuple[int, int | None], Block],
330
+ defloc: CodeLocation,
331
+ useloc: CodeLocation,
332
+ skip_if_contains_vvar: int | None = None,
333
+ ) -> bool:
334
+ return check_in_between_stmts(
335
+ graph, blocks, defloc, useloc, lambda stmt: has_load_expr(stmt, skip_if_contains_vvar=skip_if_contains_vvar)
336
+ )
337
+
338
+
228
339
  __all__ = (
229
340
  "VVarUsesCollector",
341
+ "check_in_between_stmts",
230
342
  "get_tmp_deflocs",
231
343
  "get_tmp_uselocs",
232
344
  "get_vvar_deflocs",
233
345
  "get_vvar_uselocs",
346
+ "has_call_in_between_stmts",
234
347
  "has_ite_expr",
348
+ "has_load_expr_in_between_stmts",
349
+ "has_store_stmt_in_between_stmts",
235
350
  "is_const_and_vvar_assignment",
236
351
  "is_const_assignment",
237
352
  "is_const_vvar_load_assignment",
angr/utils/types.py ADDED
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ from angr.sim_type import TypeRef, SimType, SimTypePointer, SimTypeArray, SimTypeFixedSizeArray
4
+
5
+
6
+ def unpack_typeref(ty):
7
+ if isinstance(ty, TypeRef):
8
+ return ty.type
9
+ return ty
10
+
11
+
12
+ def unpack_pointer(ty, iterative: bool = False) -> SimType | None:
13
+ if isinstance(ty, SimTypePointer):
14
+ if iterative:
15
+ inner = unpack_pointer(ty.pts_to, iterative=True)
16
+ return inner if inner is not None else ty.pts_to
17
+ return ty.pts_to
18
+ return None
19
+
20
+
21
+ def replace_pointer_pts_to(ty: SimType, old_pts_to: SimType, new_pts_to: SimType) -> SimTypePointer | None:
22
+ if isinstance(ty, SimTypePointer):
23
+ if ty.pts_to is old_pts_to:
24
+ inner = new_pts_to
25
+ elif isinstance(ty.pts_to, SimTypePointer):
26
+ # recursively replace pts_to inside
27
+ inner = replace_pointer_pts_to(ty.pts_to, old_pts_to, new_pts_to)
28
+ else:
29
+ return None
30
+ return SimTypePointer(inner, label=ty.label, offset=ty.offset)
31
+ return None
32
+
33
+
34
+ def unpack_array(ty) -> SimType | None:
35
+ if isinstance(ty, SimTypeArray):
36
+ return ty.elem_type
37
+ if isinstance(ty, SimTypeFixedSizeArray):
38
+ return ty.elem_type
39
+ return None
40
+
41
+
42
+ def squash_array_reference(ty):
43
+ pointed_to = unpack_pointer(ty)
44
+ if pointed_to:
45
+ array_of = unpack_array(pointed_to)
46
+ if array_of:
47
+ return SimTypePointer(array_of)
48
+ return ty
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: angr
3
- Version: 9.2.139
3
+ Version: 9.2.141
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  Home-page: https://github.com/angr/angr
6
6
  License: BSD-2-Clause
@@ -16,13 +16,13 @@ Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: CppHeaderParser
18
18
  Requires-Dist: GitPython
19
- Requires-Dist: ailment==9.2.139
20
- Requires-Dist: archinfo==9.2.139
19
+ Requires-Dist: ailment==9.2.141
20
+ Requires-Dist: archinfo==9.2.141
21
21
  Requires-Dist: cachetools
22
22
  Requires-Dist: capstone==5.0.3
23
23
  Requires-Dist: cffi>=1.14.0
24
- Requires-Dist: claripy==9.2.139
25
- Requires-Dist: cle==9.2.139
24
+ Requires-Dist: claripy==9.2.141
25
+ Requires-Dist: cle==9.2.141
26
26
  Requires-Dist: itanium-demangler
27
27
  Requires-Dist: mulpyplexer
28
28
  Requires-Dist: nampa
@@ -31,7 +31,7 @@ Requires-Dist: protobuf>=5.28.2
31
31
  Requires-Dist: psutil
32
32
  Requires-Dist: pycparser>=2.18
33
33
  Requires-Dist: pyformlang
34
- Requires-Dist: pyvex==9.2.139
34
+ Requires-Dist: pyvex==9.2.141
35
35
  Requires-Dist: rich>=13.1.0
36
36
  Requires-Dist: sortedcontainers
37
37
  Requires-Dist: sympy