angr 9.2.136__py3-none-macosx_11_0_arm64.whl → 9.2.137__py3-none-macosx_11_0_arm64.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 (60) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/calling_convention.py +2 -1
  3. angr/analyses/calling_convention/fact_collector.py +10 -2
  4. angr/analyses/cfg/cfg_base.py +3 -33
  5. angr/analyses/cfg/cfg_emulated.py +0 -103
  6. angr/analyses/cfg/cfg_fast.py +28 -12
  7. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +15 -0
  8. angr/analyses/class_identifier.py +1 -2
  9. angr/analyses/complete_calling_conventions.py +3 -0
  10. angr/analyses/decompiler/ail_simplifier.py +12 -1
  11. angr/analyses/decompiler/block_simplifier.py +2 -2
  12. angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
  13. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  14. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
  15. angr/analyses/decompiler/clinic.py +77 -65
  16. angr/analyses/decompiler/condition_processor.py +2 -0
  17. angr/analyses/decompiler/decompiler.py +1 -0
  18. angr/analyses/decompiler/dephication/dephication_base.py +2 -0
  19. angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
  20. angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
  21. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
  22. angr/analyses/decompiler/sequence_walker.py +6 -2
  23. angr/analyses/decompiler/ssailification/rewriting.py +11 -1
  24. angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
  25. angr/analyses/decompiler/ssailification/ssailification.py +13 -3
  26. angr/analyses/decompiler/ssailification/traversal.py +28 -2
  27. angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
  28. angr/analyses/decompiler/structured_codegen/c.py +44 -21
  29. angr/analyses/decompiler/structuring/phoenix.py +117 -14
  30. angr/analyses/decompiler/utils.py +113 -8
  31. angr/analyses/reaching_definitions/function_handler.py +1 -1
  32. angr/analyses/s_liveness.py +5 -1
  33. angr/analyses/s_propagator.py +25 -4
  34. angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
  35. angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
  36. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
  37. angr/analyses/stack_pointer_tracker.py +26 -16
  38. angr/analyses/variable_recovery/engine_ail.py +19 -7
  39. angr/analyses/variable_recovery/engine_base.py +16 -14
  40. angr/analyses/variable_recovery/engine_vex.py +2 -2
  41. angr/analyses/variable_recovery/variable_recovery_fast.py +22 -1
  42. angr/block.py +59 -20
  43. angr/engines/pcode/emulate.py +1 -1
  44. angr/engines/pcode/lifter.py +31 -18
  45. angr/engines/soot/expressions/__init__.py +2 -4
  46. angr/engines/soot/statements/__init__.py +1 -2
  47. angr/engines/soot/values/__init__.py +1 -2
  48. angr/engines/successors.py +11 -6
  49. angr/engines/vex/lifter.py +9 -6
  50. angr/flirt/build_sig.py +8 -15
  51. angr/knowledge_plugins/functions/function.py +0 -6
  52. angr/knowledge_plugins/functions/soot_function.py +5 -8
  53. angr/knowledge_plugins/variables/variable_manager.py +16 -10
  54. angr/lib/angr_native.dylib +0 -0
  55. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
  56. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/RECORD +60 -59
  57. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
  58. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
  59. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
  60. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
@@ -17,7 +17,7 @@ from ailment.expression import (
17
17
  from ailment.statement import Assignment, Store, Return, Jump
18
18
 
19
19
  from angr.knowledge_plugins.functions import Function
20
- from angr.code_location import CodeLocation
20
+ from angr.code_location import CodeLocation, ExternalCodeLocation
21
21
  from angr.analyses import Analysis, register_analysis
22
22
  from angr.utils.ssa import (
23
23
  get_vvar_uselocs,
@@ -54,6 +54,7 @@ class SPropagatorAnalysis(Analysis):
54
54
  func_graph=None,
55
55
  only_consts: bool = True,
56
56
  stack_pointer_tracker=None,
57
+ func_args: set[VirtualVariable] | None = None,
57
58
  func_addr: int | None = None,
58
59
  ):
59
60
  if isinstance(subject, Block):
@@ -69,6 +70,7 @@ class SPropagatorAnalysis(Analysis):
69
70
 
70
71
  self.func_graph = func_graph
71
72
  self.func_addr = func_addr
73
+ self.func_args = func_args
72
74
  self.only_consts = only_consts
73
75
  self._sp_tracker = stack_pointer_tracker
74
76
 
@@ -109,6 +111,11 @@ class SPropagatorAnalysis(Analysis):
109
111
  # find all vvar uses
110
112
  vvar_uselocs = get_vvar_uselocs(blocks.values())
111
113
 
114
+ # update vvar_deflocs using function arguments
115
+ if self.func_args:
116
+ for func_arg in self.func_args:
117
+ vvar_deflocs[func_arg] = ExternalCodeLocation()
118
+
112
119
  # find all ret sites and indirect jump sites
113
120
  retsites: set[tuple[int, int | None, int]] = set()
114
121
  jumpsites: set[tuple[int, int | None, int]] = set()
@@ -130,8 +137,9 @@ class SPropagatorAnalysis(Analysis):
130
137
 
131
138
  vvarid_to_vvar[vvar.varid] = vvar
132
139
  defloc = vvar_deflocs[vvar]
133
- assert defloc.block_addr is not None
134
- assert defloc.stmt_idx is not None
140
+ if isinstance(defloc, ExternalCodeLocation):
141
+ continue
142
+
135
143
  block = blocks[(defloc.block_addr, defloc.block_idx)]
136
144
  stmt = block.statements[defloc.stmt_idx]
137
145
  r, v = is_const_assignment(stmt)
@@ -179,7 +187,20 @@ class SPropagatorAnalysis(Analysis):
179
187
  continue
180
188
 
181
189
  if is_const_and_vvar_assignment(stmt):
182
- replacements[vvar_useloc][vvar_used] = stmt.src
190
+ # if the useloc is a phi assignment statement, ensure that stmt.src is the same as the phi
191
+ # variable
192
+ useloc_stmt = blocks[(vvar_useloc.block_addr, vvar_useloc.block_idx)].statements[
193
+ vvar_useloc.stmt_idx
194
+ ]
195
+ if is_phi_assignment(useloc_stmt):
196
+ if (
197
+ isinstance(stmt.src, VirtualVariable)
198
+ and stmt.src.oident == useloc_stmt.dst.oident
199
+ and stmt.src.category == useloc_stmt.dst.category
200
+ ):
201
+ replacements[vvar_useloc][vvar_used] = stmt.src
202
+ else:
203
+ replacements[vvar_useloc][vvar_used] = stmt.src
183
204
  continue
184
205
 
185
206
  elif (
@@ -15,8 +15,9 @@ class SRDAModel:
15
15
  The model for SRDA.
16
16
  """
17
17
 
18
- def __init__(self, func_graph, arch):
18
+ def __init__(self, func_graph, func_args, arch):
19
19
  self.func_graph = func_graph
20
+ self.func_args = func_args
20
21
  self.arch = arch
21
22
  self.varid_to_vvar: dict[int, VirtualVariable] = {}
22
23
  self.all_vvar_definitions: dict[VirtualVariable, CodeLocation] = {}
@@ -4,7 +4,7 @@ import logging
4
4
  from collections import defaultdict
5
5
 
6
6
  from ailment.statement import Statement, Assignment, Call, Label
7
- from ailment.expression import VirtualVariable, Expression
7
+ from ailment.expression import VirtualVariable, VirtualVariableCategory, Expression
8
8
 
9
9
  from angr.utils.ail import is_phi_assignment
10
10
  from angr.utils.graph import GraphUtils
@@ -133,6 +133,16 @@ class SRDAView:
133
133
  predicater = RegVVarPredicate(reg_offset, vvars, self.model.arch)
134
134
  self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
135
135
 
136
+ if not vvars:
137
+ # not found - check function arguments
138
+ for func_arg in self.model.func_args:
139
+ if isinstance(func_arg, VirtualVariable):
140
+ func_arg_category = func_arg.oident[0]
141
+ if func_arg_category == VirtualVariableCategory.REGISTER:
142
+ func_arg_regoff = func_arg.oident[1]
143
+ if func_arg_regoff == reg_offset:
144
+ vvars.add(func_arg)
145
+
136
146
  assert len(vvars) <= 1
137
147
  return next(iter(vvars), None)
138
148
 
@@ -149,6 +159,15 @@ class SRDAView:
149
159
  predicater = StackVVarPredicate(stack_offset, size, vvars)
150
160
  self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
151
161
 
162
+ if not vvars:
163
+ # not found - check function arguments
164
+ for func_arg in self.model.func_args:
165
+ if isinstance(func_arg, VirtualVariable):
166
+ func_arg_category = func_arg.oident[0]
167
+ if func_arg_category == VirtualVariableCategory.STACK:
168
+ func_arg_stackoff = func_arg.oident[1]
169
+ if func_arg_stackoff == stack_offset and func_arg.size == size:
170
+ vvars.add(func_arg)
152
171
  assert len(vvars) <= 1
153
172
  return next(iter(vvars), None)
154
173
 
@@ -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
+ from ailment.expression import VirtualVariable
5
6
  import networkx
6
7
 
7
8
  from angr.knowledge_plugins.functions import Function
@@ -24,6 +25,7 @@ class SReachingDefinitionsAnalysis(Analysis):
24
25
  subject,
25
26
  func_addr: int | None = None,
26
27
  func_graph: networkx.DiGraph[Block] | None = None,
28
+ func_args: set[VirtualVariable] | None = None,
27
29
  track_tmps: bool = False,
28
30
  ):
29
31
  if isinstance(subject, Block):
@@ -39,13 +41,14 @@ class SReachingDefinitionsAnalysis(Analysis):
39
41
 
40
42
  self.func_graph = func_graph
41
43
  self.func_addr = func_addr if func_addr is not None else self.func.addr if self.func is not None else None
44
+ self.func_args = func_args
42
45
  self._track_tmps = track_tmps
43
46
 
44
47
  self._bp_as_gpr = False
45
48
  if self.func is not None:
46
49
  self._bp_as_gpr = self.func.info.get("bp_as_gpr", False)
47
50
 
48
- self.model = SRDAModel(func_graph, self.project.arch)
51
+ self.model = SRDAModel(func_graph, func_args, self.project.arch)
49
52
 
50
53
  self._analyze()
51
54
 
@@ -66,6 +69,13 @@ class SReachingDefinitionsAnalysis(Analysis):
66
69
  # find all explicit vvar uses
67
70
  vvar_uselocs = get_vvar_uselocs(blocks.values())
68
71
 
72
+ # update vvar definitions using function arguments
73
+ if self.func_args:
74
+ for vvar in self.func_args:
75
+ if vvar not in vvar_deflocs:
76
+ vvar_deflocs[vvar] = ExternalCodeLocation()
77
+ self.model.func_args = self.func_args
78
+
69
79
  # update model
70
80
  for vvar, defloc in vvar_deflocs.items():
71
81
  self.model.varid_to_vvar[vvar.varid] = vvar
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  from typing import Any, TYPE_CHECKING
5
+ import contextlib
5
6
  import re
6
7
  import logging
7
8
  from collections import defaultdict
@@ -15,7 +16,6 @@ from angr.knowledge_plugins import Function
15
16
  from angr.block import BlockNode
16
17
  from angr.errors import SimTranslationError
17
18
  from .analysis import Analysis
18
- import contextlib
19
19
 
20
20
  try:
21
21
  import pypcode
@@ -702,21 +702,31 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
702
702
  # who are we calling?
703
703
  callees = [] if self._func is None else self._find_callees(node)
704
704
  if callees:
705
- if (
706
- len(callees) == 1
707
- and callees[0].info.get("is_rust_probestack", False) is True
708
- and self.project.arch.name == "AMD64"
709
- ):
710
- # special-case for rust_probestack: sp = sp - rax right after returning from the call, so we need
711
- # to keep track of rax
712
- for stmt in reversed(vex_block.statements):
713
- if (
714
- isinstance(stmt, pyvex.IRStmt.Put)
715
- and stmt.offset == self.project.arch.registers["rax"][0]
716
- and isinstance(stmt.data, pyvex.IRExpr.Const)
717
- ):
718
- state.put(stmt.offset, Constant(stmt.data.con.value), force=True)
719
- break
705
+ if len(callees) == 1:
706
+ callee = callees[0]
707
+
708
+ if callee.info.get("is_rust_probestack", False) is True and self.project.arch.name == "AMD64":
709
+ # special-case for rust_probestack: sp = sp - rax right after returning from the call, so we
710
+ # need to keep track of rax
711
+ for stmt in reversed(vex_block.statements):
712
+ if (
713
+ isinstance(stmt, pyvex.IRStmt.Put)
714
+ and stmt.offset == self.project.arch.registers["rax"][0]
715
+ and isinstance(stmt.data, pyvex.IRExpr.Const)
716
+ ):
717
+ state.put(stmt.offset, Constant(stmt.data.con.value), force=True)
718
+ break
719
+ elif callee.name == "__chkstk":
720
+ # special-case for __chkstk: sp = sp - rax right after returning from the call, so we need to
721
+ # keep track of rax
722
+ for stmt in reversed(vex_block.statements):
723
+ if (
724
+ isinstance(stmt, pyvex.IRStmt.Put)
725
+ and stmt.offset == self.project.arch.registers["rax"][0]
726
+ and isinstance(stmt.data, pyvex.IRExpr.Const)
727
+ ):
728
+ state.put(stmt.offset, Constant(stmt.data.con.value), force=True)
729
+ break
720
730
 
721
731
  callee_cleanups = [
722
732
  callee
@@ -74,17 +74,28 @@ class SimEngineVRAIL(
74
74
 
75
75
  elif dst_type is ailment.Expr.VirtualVariable:
76
76
  data = self._expr(stmt.src)
77
- self._assign_to_vvar(
77
+ variable = self._assign_to_vvar(
78
78
  stmt.dst, data, src=stmt.src, dst=stmt.dst, vvar_id=self._mapped_vvarid(stmt.dst.varid)
79
79
  )
80
80
 
81
+ if variable is not None and isinstance(stmt.src, ailment.Expr.Phi):
82
+ # this is a phi node - we update variable manager's phi variable tracking
83
+ for _, vvar in stmt.src.src_and_vvars:
84
+ if vvar is not None:
85
+ r = self._read_from_vvar(vvar, expr=stmt.src, vvar_id=self._mapped_vvarid(vvar.varid))
86
+ if r.variable is not None:
87
+ pv = self.variable_manager[self.func_addr]._phi_variables
88
+ if variable not in pv:
89
+ pv[variable] = set()
90
+ pv[variable].add(r.variable)
91
+
81
92
  if stmt.dst.was_stack and isinstance(stmt.dst.stack_offset, int):
82
93
  # store it to the stack region in case it's directly referenced later
83
94
  self._store(
84
95
  RichR(self.state.stack_address(stmt.dst.stack_offset)),
85
96
  data,
86
97
  stmt.dst.bits // self.arch.byte_width,
87
- stmt=stmt,
98
+ atom=stmt.dst,
88
99
  )
89
100
 
90
101
  else:
@@ -94,10 +105,11 @@ class SimEngineVRAIL(
94
105
  addr_r = self._expr_bv(stmt.addr)
95
106
  data = self._expr(stmt.data)
96
107
  size = stmt.size
97
- self._store(addr_r, data, size, stmt=stmt)
108
+ self._store(addr_r, data, size, atom=stmt)
98
109
 
99
- def _handle_stmt_Jump(self, stmt):
100
- pass
110
+ def _handle_stmt_Jump(self, stmt: ailment.Stmt.Jump):
111
+ if not isinstance(stmt.target, ailment.Expr.Const):
112
+ self._expr(stmt.target)
101
113
 
102
114
  def _handle_stmt_ConditionalJump(self, stmt):
103
115
  self._expr(stmt.condition)
@@ -149,7 +161,7 @@ class SimEngineVRAIL(
149
161
  prototype_libname = func.prototype_libname
150
162
 
151
163
  # dump the type of the return value
152
- ret_ty = typevars.TypeVariable() if prototype is not None else typevars.TypeVariable()
164
+ ret_ty = typevars.TypeVariable()
153
165
  if isinstance(ret_ty, typeconsts.BottomType):
154
166
  ret_ty = typevars.TypeVariable()
155
167
 
@@ -218,7 +230,7 @@ class SimEngineVRAIL(
218
230
  prototype_libname = func.prototype_libname
219
231
 
220
232
  # dump the type of the return value
221
- ret_ty = typevars.TypeVariable() if prototype is not None else typevars.TypeVariable()
233
+ ret_ty = typevars.TypeVariable()
222
234
  if isinstance(ret_ty, typeconsts.BottomType):
223
235
  ret_ty = typevars.TypeVariable()
224
236
 
@@ -387,7 +387,7 @@ class SimEngineVRBase(
387
387
  ) or not create_variable:
388
388
  # only store the value. don't worry about variables.
389
389
  self.vvar_region[vvar_id] = richr.data
390
- return
390
+ return None
391
391
 
392
392
  codeloc: CodeLocation = self._codeloc()
393
393
  data = richr.data
@@ -463,10 +463,14 @@ class SimEngineVRBase(
463
463
  else:
464
464
  typevar = self.state.typevars.get_type_variable(variable, codeloc)
465
465
  self.state.add_type_constraint(typevars.Subtype(richr.typevar, typevar))
466
+ # the constraint below is a default constraint that may conflict with more specific ones with different
467
+ # sizes; we post-process at the very end of VRA to remove conflicting default constraints.
466
468
  self.state.add_type_constraint(typevars.Subtype(typevar, typeconsts.int_type(variable.size * 8)))
467
469
 
470
+ return variable
471
+
468
472
  def _store(
469
- self, richr_addr: RichR[claripy.ast.BV], data: RichR[claripy.ast.BV | claripy.ast.FP], size, stmt=None
473
+ self, richr_addr: RichR[claripy.ast.BV], data: RichR[claripy.ast.BV | claripy.ast.FP], size, atom=None
470
474
  ): # pylint:disable=unused-argument
471
475
  """
472
476
 
@@ -481,19 +485,19 @@ class SimEngineVRBase(
481
485
 
482
486
  if addr.concrete:
483
487
  # fully concrete. this is a global address
484
- self._store_to_global(addr.concrete_value, data, size, stmt=stmt)
488
+ self._store_to_global(addr.concrete_value, data, size, stmt=atom)
485
489
  stored = True
486
490
  elif self._addr_has_concrete_base(addr) and (parsed := self._parse_offsetted_addr(addr)) is not None:
487
491
  # we are storing to a concrete global address with an offset
488
492
  base_addr, offset, elem_size = parsed
489
- self._store_to_global(base_addr.concrete_value, data, size, stmt=stmt, offset=offset, elem_size=elem_size)
493
+ self._store_to_global(base_addr.concrete_value, data, size, stmt=atom, offset=offset, elem_size=elem_size)
490
494
  stored = True
491
495
  else:
492
496
  if self.state.is_stack_address(addr):
493
497
  stack_offset = self.state.get_stack_offset(addr)
494
498
  if stack_offset is not None:
495
499
  # fast path: Storing data to stack
496
- self._store_to_stack(stack_offset, data, size, stmt=stmt)
500
+ self._store_to_stack(stack_offset, data, size, atom=atom)
497
501
  stored = True
498
502
 
499
503
  if not stored:
@@ -504,21 +508,21 @@ class SimEngineVRBase(
504
508
  codeloc = self._codeloc()
505
509
  if existing_vars:
506
510
  for existing_var, _ in list(existing_vars):
507
- self.variable_manager[self.func_addr].remove_variable_by_atom(codeloc, existing_var, stmt)
511
+ self.variable_manager[self.func_addr].remove_variable_by_atom(codeloc, existing_var, atom)
508
512
 
509
513
  # storing to a location specified by a pointer whose value cannot be determined at this point
510
- self._store_to_variable(richr_addr, size, stmt=stmt)
514
+ self._store_to_variable(richr_addr, size)
511
515
 
512
516
  def _store_to_stack(
513
- self, stack_offset, data: RichR[claripy.ast.BV | claripy.ast.FP], size, offset=0, stmt=None, endness=None
517
+ self, stack_offset, data: RichR[claripy.ast.BV | claripy.ast.FP], size, offset=0, atom=None, endness=None
514
518
  ):
515
- if stmt is None:
519
+ if atom is None:
516
520
  existing_vars = self.variable_manager[self.func_addr].find_variables_by_stmt(
517
521
  self.block.addr, self.stmt_idx, "memory"
518
522
  )
519
523
  else:
520
524
  existing_vars = self.variable_manager[self.func_addr].find_variables_by_atom(
521
- self.block.addr, self.stmt_idx, stmt
525
+ self.block.addr, self.stmt_idx, atom
522
526
  )
523
527
  if not existing_vars:
524
528
  variable = SimStackVariable(
@@ -562,7 +566,7 @@ class SimEngineVRBase(
562
566
  var,
563
567
  offset_into_var,
564
568
  codeloc,
565
- atom=stmt,
569
+ atom=atom,
566
570
  )
567
571
 
568
572
  # create type constraints
@@ -673,9 +677,7 @@ class SimEngineVRBase(
673
677
  self.state.add_type_constraint(typevars.Subtype(store_typevar, typeconsts.TopType()))
674
678
  self.state.add_type_constraint(typevars.Subtype(data.typevar, store_typevar))
675
679
 
676
- def _store_to_variable(
677
- self, richr_addr: RichR[claripy.ast.BV], size: int, stmt=None
678
- ): # pylint:disable=unused-argument
680
+ def _store_to_variable(self, richr_addr: RichR[claripy.ast.BV], size: int):
679
681
  addr_variable = richr_addr.variable
680
682
  codeloc = self._codeloc()
681
683
 
@@ -74,7 +74,7 @@ class SimEngineVRVEX(
74
74
  size = stmt.data.result_size(self.tyenv) // 8
75
75
  r = self._expr(stmt.data)
76
76
 
77
- self._store(addr_r, r, size, stmt=stmt)
77
+ self._store(addr_r, r, size, atom=stmt)
78
78
 
79
79
  def _handle_stmt_StoreG(self, stmt):
80
80
  guard = self._expr(stmt.guard)
@@ -82,7 +82,7 @@ class SimEngineVRVEX(
82
82
  addr = self._expr_bv(stmt.addr)
83
83
  size = stmt.data.result_size(self.tyenv) // 8
84
84
  data = self._expr(stmt.data)
85
- self._store(addr, data, size, stmt=stmt)
85
+ self._store(addr, data, size, atom=stmt)
86
86
 
87
87
  def _handle_stmt_LoadG(self, stmt):
88
88
  guard = self._expr(stmt.guard)
@@ -20,7 +20,8 @@ from angr.knowledge_plugins import Function
20
20
  from angr.sim_variable import SimStackVariable, SimRegisterVariable, SimVariable, SimMemoryVariable
21
21
  from angr.engines.vex.claripy.irop import vexop_to_simop
22
22
  from angr.analyses import ForwardAnalysis, visitors
23
- from angr.analyses.typehoon.typevars import Equivalence, TypeVariable, TypeVariables
23
+ from angr.analyses.typehoon.typevars import Equivalence, TypeVariable, TypeVariables, Subtype, DerivedTypeVariable
24
+ from angr.analyses.typehoon.typeconsts import Int
24
25
  from .variable_recovery_base import VariableRecoveryBase, VariableRecoveryStateBase
25
26
  from .engine_vex import SimEngineVRVEX
26
27
  from .engine_ail import SimEngineVRAIL
@@ -500,6 +501,26 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
500
501
  for tv in sorted_typevars[1:]:
501
502
  self.type_constraints[self.func_typevar].add(Equivalence(sorted_typevars[0], tv))
502
503
 
504
+ # remove default constraints with size conflicts
505
+ for func_var in self.type_constraints:
506
+ var_to_subtyping: dict[TypeVariable, list[Subtype]] = defaultdict(list)
507
+ for constraint in self.type_constraints[func_var]:
508
+ if isinstance(constraint, Subtype) and isinstance(constraint.sub_type, TypeVariable):
509
+ var_to_subtyping[constraint.sub_type].append(constraint)
510
+
511
+ for constraints in var_to_subtyping.values():
512
+ if len(constraints) <= 1:
513
+ continue
514
+ default_subtyping_constraints = set()
515
+ has_nondefault_subtyping_constraints = False
516
+ for constraint in constraints:
517
+ if isinstance(constraint.super_type, Int):
518
+ default_subtyping_constraints.add(constraint)
519
+ elif isinstance(constraint.super_type, DerivedTypeVariable) and constraint.super_type.labels:
520
+ has_nondefault_subtyping_constraints = True
521
+ if has_nondefault_subtyping_constraints:
522
+ self.type_constraints[func_var].difference_update(default_subtyping_constraints)
523
+
503
524
  self.variable_manager[self.function.addr].ret_val_size = self.ret_val_size
504
525
 
505
526
  self.delayed_type_constraints = None
angr/block.py CHANGED
@@ -1,10 +1,11 @@
1
1
  # pylint:disable=wrong-import-position,arguments-differ
2
2
  from __future__ import annotations
3
3
  import logging
4
+ from typing import TYPE_CHECKING
4
5
 
5
6
  import pyvex
6
7
  from pyvex import IRSB
7
- from archinfo import ArchARM
8
+ from archinfo import Arch, ArchARM
8
9
 
9
10
  from .protos import primitives_pb2 as pb2
10
11
  from .serializable import Serializable
@@ -14,6 +15,12 @@ try:
14
15
  except ImportError:
15
16
  pcode = None
16
17
 
18
+ if TYPE_CHECKING:
19
+ from angr import Project
20
+ from angr.engines.vex import VEXLifter
21
+ from angr.engines.pcode.lifter import PcodeLifterEngineMixin, IRSB as PcodeIRSB
22
+ from angr.engines.soot.engine import SootMixin
23
+
17
24
 
18
25
  l = logging.getLogger(name=__name__)
19
26
 
@@ -148,7 +155,7 @@ class Block(Serializable):
148
155
  self,
149
156
  addr,
150
157
  project=None,
151
- arch=None,
158
+ arch: Arch = None,
152
159
  size=None,
153
160
  max_size=None,
154
161
  byte_string=None,
@@ -168,6 +175,7 @@ class Block(Serializable):
168
175
  skip_stmts=False,
169
176
  ):
170
177
  # set up arch
178
+ self.arch: Arch
171
179
  if project is not None:
172
180
  self.arch = project.arch
173
181
  else:
@@ -187,7 +195,7 @@ class Block(Serializable):
187
195
  else:
188
196
  thumb = False
189
197
 
190
- self._project = project
198
+ self._project: Project | None = project
191
199
  self.thumb = thumb
192
200
  self.addr = addr
193
201
  self._opt_level = opt_level
@@ -206,8 +214,15 @@ class Block(Serializable):
206
214
  else:
207
215
  if self._initial_regs:
208
216
  self.set_initial_regs()
217
+ clemory = None
218
+ if project is not None:
219
+ clemory = (
220
+ project.loader.memory_ro_view
221
+ if project.loader.memory_ro_view is not None
222
+ else project.loader.memory
223
+ )
209
224
  vex = self._vex_engine.lift_vex(
210
- clemory=project.loader.memory,
225
+ clemory=clemory,
211
226
  state=backup_state,
212
227
  insn_bytes=byte_string,
213
228
  addr=addr,
@@ -243,7 +258,7 @@ class Block(Serializable):
243
258
  self._load_from_ro_regions = load_from_ro_regions
244
259
  self._const_prop = const_prop
245
260
 
246
- self._instructions = num_inst
261
+ self._instructions: int | None = num_inst
247
262
  self._instruction_addrs: list[int] = []
248
263
 
249
264
  if skip_stmts:
@@ -258,7 +273,7 @@ class Block(Serializable):
258
273
  if type(self._bytes) is memoryview:
259
274
  self._bytes = bytes(self._bytes)
260
275
  elif type(self._bytes) is not bytes:
261
- self._bytes = bytes(pyvex.ffi.buffer(self._bytes, size))
276
+ self._bytes = bytes(pyvex.ffi.buffer(self._bytes, size)) # type:ignore
262
277
  else:
263
278
  self._bytes = None
264
279
  elif type(byte_string) is bytes:
@@ -269,7 +284,7 @@ class Block(Serializable):
269
284
  else:
270
285
  # Convert bytestring to a str
271
286
  # size will ALWAYS be known at this point
272
- self._bytes = str(pyvex.ffi.buffer(byte_string, self.size))
287
+ self._bytes = bytes(pyvex.ffi.buffer(byte_string, self.size)) # type:ignore
273
288
 
274
289
  def _parse_vex_info(self, vex_block):
275
290
  if vex_block is not None:
@@ -323,16 +338,25 @@ class Block(Serializable):
323
338
  pyvex.pvc.reset_initial_register_values()
324
339
 
325
340
  @property
326
- def _vex_engine(self):
327
- return self._project.factory.default_engine
341
+ def _vex_engine(self) -> VEXLifter | PcodeLifterEngineMixin:
342
+ if self._project is None:
343
+ raise ValueError("Project is not set")
344
+ return self._project.factory.default_engine # type:ignore
328
345
 
329
346
  @property
330
- def vex(self) -> IRSB:
347
+ def vex(self) -> IRSB | PcodeIRSB:
331
348
  if not self._vex:
332
349
  if self._initial_regs:
333
350
  self.set_initial_regs()
351
+ clemory = None
352
+ if self._project is not None:
353
+ clemory = (
354
+ self._project.loader.memory_ro_view
355
+ if self._project.loader.memory_ro_view is not None
356
+ else self._project.loader.memory
357
+ )
334
358
  self._vex = self._vex_engine.lift_vex(
335
- clemory=self._project.loader.memory if self._project is not None else None,
359
+ clemory=clemory,
336
360
  insn_bytes=self._bytes,
337
361
  addr=self.addr,
338
362
  thumb=self.thumb,
@@ -350,6 +374,7 @@ class Block(Serializable):
350
374
  self.reset_initial_regs()
351
375
  self._parse_vex_info(self._vex)
352
376
 
377
+ assert self._vex is not None
353
378
  return self._vex
354
379
 
355
380
  @property
@@ -362,8 +387,15 @@ class Block(Serializable):
362
387
 
363
388
  if self._initial_regs:
364
389
  self.set_initial_regs()
390
+ clemory = None
391
+ if self._project is not None:
392
+ clemory = (
393
+ self._project.loader.memory_ro_view
394
+ if self._project.loader.memory_ro_view is not None
395
+ else self._project.loader.memory
396
+ )
365
397
  self._vex_nostmt = self._vex_engine.lift_vex(
366
- clemory=self._project.loader.memory if self._project is not None else None,
398
+ clemory=clemory,
367
399
  insn_bytes=self._bytes,
368
400
  addr=self.addr,
369
401
  thumb=self.thumb,
@@ -394,17 +426,17 @@ class Block(Serializable):
394
426
  """
395
427
  if self._disassembly is None:
396
428
  if self._using_pcode_engine:
397
- self._disassembly = self.vex.disassembly
429
+ self._disassembly = self.vex.disassembly # type:ignore
398
430
  else:
399
431
  self._disassembly = self.capstone
400
432
  return self._disassembly
401
433
 
402
434
  @property
403
- def capstone(self):
435
+ def capstone(self) -> CapstoneBlock:
404
436
  if self._capstone:
405
437
  return self._capstone
406
438
 
407
- cs = self.arch.capstone if not self.thumb else self.arch.capstone_thumb
439
+ cs = self.arch.capstone if not self.thumb else self.arch.capstone_thumb # type:ignore
408
440
 
409
441
  insns = []
410
442
 
@@ -423,12 +455,18 @@ class Block(Serializable):
423
455
  return BlockNode(self.addr, self.size, bytestr=self.bytes, thumb=self.thumb)
424
456
 
425
457
  @property
426
- def bytes(self) -> bytes:
458
+ def bytes(self) -> bytes | None:
427
459
  if self._bytes is None:
428
460
  addr = self.addr
429
461
  if self.thumb:
430
462
  addr = (addr >> 1) << 1
431
- self._bytes = self._project.loader.memory.load(addr, self.size)
463
+ if self._project is not None:
464
+ mem = (
465
+ self._project.loader.memory_ro_view
466
+ if self._project.loader.memory_ro_view is not None
467
+ else self._project.loader.memory
468
+ )
469
+ self._bytes = mem.load(addr, self.size)
432
470
  return self._bytes
433
471
 
434
472
  @property
@@ -437,6 +475,7 @@ class Block(Serializable):
437
475
  # initialize from VEX
438
476
  _ = self.vex
439
477
 
478
+ assert self._instructions is not None
440
479
  return self._instructions
441
480
 
442
481
  @property
@@ -477,17 +516,17 @@ class SootBlock:
477
516
  Represents a Soot IR basic block.
478
517
  """
479
518
 
480
- def __init__(self, addr, project=None, arch=None):
519
+ def __init__(self, addr, *, project: Project, arch: Arch):
481
520
  self.addr = addr
482
521
  self.arch = arch
483
522
  self._project = project
484
523
  self._the_binary = project.loader.main_object
485
524
 
486
525
  @property
487
- def _soot_engine(self):
526
+ def _soot_engine(self) -> SootMixin:
488
527
  if self._project is None:
489
528
  assert False, "This should be unreachable"
490
- return self._project.factory.default_engine
529
+ return self._project.factory.default_engine # type:ignore
491
530
 
492
531
  @property
493
532
  def soot(self):
@@ -92,7 +92,7 @@ class PcodeEmulatorMixin(SimEngineBase):
92
92
  self.state,
93
93
  fallthru_addr,
94
94
  self.state.scratch.guard,
95
- "Ijk_Boring",
95
+ irsb.jumpkind,
96
96
  exit_stmt_idx=DEFAULT_STATEMENT,
97
97
  exit_ins_addr=self.state.scratch.ins_addr,
98
98
  )