angr 9.2.122__py3-none-macosx_11_0_arm64.whl → 9.2.124__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 (96) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention.py +6 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
  4. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
  5. angr/analyses/decompiler/ail_simplifier.py +38 -342
  6. angr/analyses/decompiler/callsite_maker.py +8 -7
  7. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
  8. angr/analyses/decompiler/clinic.py +30 -3
  9. angr/analyses/decompiler/condition_processor.py +10 -3
  10. angr/analyses/decompiler/decompilation_cache.py +2 -0
  11. angr/analyses/decompiler/decompiler.py +50 -8
  12. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
  13. angr/analyses/decompiler/dephication/rewriting_engine.py +65 -2
  14. angr/analyses/decompiler/expression_narrower.py +206 -6
  15. angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
  16. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +7 -0
  17. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +34 -11
  18. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +10 -1
  19. angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
  20. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
  21. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
  22. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
  23. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
  24. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
  25. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +75 -42
  26. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
  27. angr/analyses/decompiler/region_identifier.py +36 -0
  28. angr/analyses/decompiler/region_simplifiers/expr_folding.py +4 -0
  29. angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
  30. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
  31. angr/analyses/decompiler/sequence_walker.py +20 -4
  32. angr/analyses/decompiler/ssailification/rewriting.py +5 -2
  33. angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
  34. angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
  35. angr/analyses/decompiler/ssailification/ssailification.py +17 -9
  36. angr/analyses/decompiler/ssailification/traversal.py +3 -1
  37. angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
  38. angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
  39. angr/analyses/decompiler/structured_codegen/c.py +42 -4
  40. angr/analyses/decompiler/structuring/phoenix.py +3 -0
  41. angr/analyses/propagator/engine_ail.py +10 -3
  42. angr/analyses/reaching_definitions/engine_ail.py +10 -15
  43. angr/analyses/s_propagator.py +26 -15
  44. angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
  45. angr/analyses/variable_recovery/engine_ail.py +14 -0
  46. angr/analyses/variable_recovery/engine_base.py +11 -0
  47. angr/calling_conventions.py +2 -2
  48. angr/engines/light/engine.py +24 -2
  49. angr/engines/soot/expressions/instanceOf.py +4 -1
  50. angr/engines/successors.py +1 -1
  51. angr/engines/vex/heavy/concretizers.py +47 -47
  52. angr/engines/vex/heavy/dirty.py +4 -4
  53. angr/knowledge_plugins/__init__.py +2 -0
  54. angr/knowledge_plugins/decompilation.py +45 -0
  55. angr/knowledge_plugins/key_definitions/atoms.py +8 -0
  56. angr/lib/angr_native.dylib +0 -0
  57. angr/procedures/definitions/parse_win32json.py +2 -1
  58. angr/procedures/java_lang/getsimplename.py +4 -1
  59. angr/procedures/linux_kernel/iovec.py +5 -2
  60. angr/sim_type.py +3 -1
  61. angr/storage/memory_mixins/actions_mixin.py +7 -7
  62. angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
  63. angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
  64. angr/storage/memory_mixins/clouseau_mixin.py +3 -3
  65. angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
  66. angr/storage/memory_mixins/default_filler_mixin.py +3 -3
  67. angr/storage/memory_mixins/memory_mixin.py +45 -34
  68. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
  69. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
  70. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
  71. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
  72. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
  73. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
  74. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
  75. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
  76. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
  77. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
  78. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
  79. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
  80. angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
  81. angr/storage/memory_mixins/simplification_mixin.py +2 -2
  82. angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
  83. angr/storage/memory_mixins/slotted_memory.py +3 -3
  84. angr/storage/memory_mixins/smart_find_mixin.py +1 -0
  85. angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
  86. angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
  87. angr/storage/memory_object.py +4 -3
  88. angr/utils/constants.py +1 -1
  89. angr/utils/graph.py +15 -0
  90. angr/vaults.py +2 -2
  91. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/METADATA +7 -6
  92. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/RECORD +96 -95
  93. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
  94. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
  95. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
  96. {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
@@ -1408,7 +1408,7 @@ class CUnsupportedStatement(CStatement):
1408
1408
  class CDirtyStatement(CExpression):
1409
1409
  __slots__ = ("dirty",)
1410
1410
 
1411
- def __init__(self, dirty, **kwargs):
1411
+ def __init__(self, dirty: CDirtyExpression, **kwargs):
1412
1412
  super().__init__(**kwargs)
1413
1413
  self.dirty = dirty
1414
1414
 
@@ -1420,7 +1420,7 @@ class CDirtyStatement(CExpression):
1420
1420
  indent_str = self.indent_str(indent=indent)
1421
1421
 
1422
1422
  yield indent_str, None
1423
- yield str(self.dirty), None
1423
+ yield from self.dirty.c_repr_chunks()
1424
1424
  yield "\n", None
1425
1425
 
1426
1426
 
@@ -2303,6 +2303,38 @@ class CMultiStatementExpression(CExpression):
2303
2303
  yield ")", paren
2304
2304
 
2305
2305
 
2306
+ class CVEXCCallExpression(CExpression):
2307
+ """
2308
+ ccall_name(arg0, arg1, ...)
2309
+ """
2310
+
2311
+ __slots__ = (
2312
+ "callee",
2313
+ "operands",
2314
+ "tags",
2315
+ )
2316
+
2317
+ def __init__(self, callee: str, operands: list[CExpression], tags=None, **kwargs):
2318
+ super().__init__(**kwargs)
2319
+ self.callee = callee
2320
+ self.operands = operands
2321
+ self.tags = tags
2322
+
2323
+ @property
2324
+ def type(self):
2325
+ return SimTypeInt().with_arch(self.codegen.project.arch)
2326
+
2327
+ def c_repr_chunks(self, indent=0, asexpr=False):
2328
+ paren = CClosingObject("(")
2329
+ yield f"{self.callee}", self
2330
+ yield "(", paren
2331
+ for idx, operand in enumerate(self.operands):
2332
+ if idx != 0:
2333
+ yield ", ", None
2334
+ yield from operand.c_repr_chunks()
2335
+ yield ")", paren
2336
+
2337
+
2306
2338
  class CDirtyExpression(CExpression):
2307
2339
  """
2308
2340
  Ideally all dirty expressions should be handled and converted to proper conversions during conversion from VEX to
@@ -2424,6 +2456,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2424
2456
  Expr.BinaryOp: self._handle_Expr_BinaryOp,
2425
2457
  Expr.Convert: self._handle_Expr_Convert,
2426
2458
  Expr.StackBaseOffset: self._handle_Expr_StackBaseOffset,
2459
+ Expr.VEXCCallExpression: self._handle_Expr_VEXCCallExpression,
2427
2460
  Expr.DirtyExpression: self._handle_Expr_Dirty,
2428
2461
  Expr.ITE: self._handle_Expr_ITE,
2429
2462
  Expr.Reinterpret: self._handle_Reinterpret,
@@ -3318,7 +3351,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3318
3351
  return clabel
3319
3352
 
3320
3353
  def _handle_Stmt_Dirty(self, stmt: Stmt.DirtyStatement, **kwargs):
3321
- return CDirtyStatement(stmt, codegen=self)
3354
+ dirty = self._handle(stmt.dirty)
3355
+ return CDirtyStatement(dirty, codegen=self)
3322
3356
 
3323
3357
  #
3324
3358
  # AIL expression handlers
@@ -3519,7 +3553,11 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3519
3553
 
3520
3554
  return CTypeCast(None, dst_type.with_arch(self.project.arch), child, tags=expr.tags, codegen=self)
3521
3555
 
3522
- def _handle_Expr_Dirty(self, expr, **kwargs):
3556
+ def _handle_Expr_VEXCCallExpression(self, expr: Expr.VEXCCallExpression, **kwargs):
3557
+ operands = [self._handle(arg) for arg in expr.operands]
3558
+ return CVEXCCallExpression(expr.callee, operands, tags=expr.tags, codegen=self)
3559
+
3560
+ def _handle_Expr_Dirty(self, expr: Expr.DirtyExpression, **kwargs):
3523
3561
  return CDirtyExpression(expr, codegen=self)
3524
3562
 
3525
3563
  def _handle_Expr_ITE(self, expr: Expr.ITE, **kwargs):
@@ -566,6 +566,9 @@ class PhoenixStructurer(StructurerBase):
566
566
 
567
567
  if next_node is node:
568
568
  break
569
+ if next_node is head:
570
+ # we don't want a loop with region head not as the first node of the body!
571
+ return False, None
569
572
  if next_node is not node and next_node in seen_nodes:
570
573
  return False, None
571
574
 
@@ -740,9 +740,16 @@ class SimEnginePropagatorAIL(
740
740
  return PropValue.from_value_and_details(v, expr.size, expr, self._codeloc())
741
741
 
742
742
  def _ail_handle_DirtyExpression(self, expr: Expr.DirtyExpression) -> PropValue | None: # pylint:disable=no-self-use
743
- if isinstance(expr.dirty_expr, Expr.VEXCCallExpression):
744
- for operand in expr.dirty_expr.operands:
745
- _ = self._expr(operand)
743
+ for operand in expr.operands:
744
+ _ = self._expr(operand)
745
+
746
+ return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
747
+
748
+ def _ail_handle_VEXCCallExpression(
749
+ self, expr: Expr.VEXCCallExpression
750
+ ) -> PropValue | None: # pylint:disable=no-self-use
751
+ for operand in expr.operands:
752
+ _ = self._expr(operand)
746
753
 
747
754
  return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
748
755
 
@@ -7,7 +7,6 @@ import logging
7
7
  import archinfo
8
8
  import claripy
9
9
  import ailment
10
- import pyvex
11
10
  from claripy import FSORT_DOUBLE, FSORT_FLOAT
12
11
 
13
12
  from angr.engines.light import SimEngineLight, SimEngineLightAILMixin, SpOffset
@@ -364,17 +363,7 @@ class SimEngineRDAIL(
364
363
  # self.state.add_use(Register(self.project.arch.sp_offset, self.project.arch.bits // 8))
365
364
 
366
365
  def _ail_handle_DirtyStatement(self, stmt: ailment.Stmt.DirtyStatement):
367
- # TODO: The logic below is subject to change when ailment.Stmt.DirtyStatement is changed
368
-
369
- if isinstance(stmt.dirty_stmt, pyvex.stmt.Dirty):
370
- # TODO: We need dirty helpers for a more complete understanding of clobbered registers
371
- tmp = stmt.dirty_stmt.tmp
372
- if tmp in (-1, 0xFFFFFFFF):
373
- return
374
- size = 32 # FIXME: We don't know the size.
375
- self.state.kill_and_add_definition(Tmp(tmp, size), MultiValues(self.state.top(size)))
376
- else:
377
- l.warning("Unexpected type of dirty statement %s.", type(stmt.dirty_stmt))
366
+ self._expr(stmt.dirty)
378
367
 
379
368
  #
380
369
  # AIL expression handlers
@@ -1125,12 +1114,18 @@ class SimEngineRDAIL(
1125
1114
  stack_addr = self.state.stack_address(expr.offset)
1126
1115
  return MultiValues(stack_addr)
1127
1116
 
1117
+ def _ail_handle_VEXCCallExpression(self, expr: ailment.Expr.VEXCCallExpression) -> MultiValues:
1118
+ for operand in expr.operands:
1119
+ self._expr(operand)
1120
+
1121
+ top = self.state.top(expr.bits)
1122
+ return MultiValues(top)
1123
+
1128
1124
  def _ail_handle_DirtyExpression(
1129
1125
  self, expr: ailment.Expr.DirtyExpression
1130
1126
  ) -> MultiValues: # pylint:disable=no-self-use
1131
- if isinstance(expr.dirty_expr, ailment.Expr.VEXCCallExpression):
1132
- for operand in expr.dirty_expr.operands:
1133
- self._expr(operand)
1127
+ for operand in expr.operands:
1128
+ self._expr(operand)
1134
1129
 
1135
1130
  top = self.state.top(expr.bits)
1136
1131
  return MultiValues(top)
@@ -5,7 +5,7 @@ from collections import defaultdict
5
5
 
6
6
  from ailment.block import Block
7
7
  from ailment.expression import Const, VirtualVariable, VirtualVariableCategory, StackBaseOffset
8
- from ailment.statement import Assignment, Store, Return
8
+ from ailment.statement import Assignment, Store, Return, Jump
9
9
 
10
10
  from angr.knowledge_plugins.functions import Function
11
11
  from angr.code_location import CodeLocation
@@ -98,11 +98,15 @@ class SPropagatorAnalysis(Analysis):
98
98
  # find all vvar uses
99
99
  vvar_uselocs = get_vvar_uselocs(blocks.values())
100
100
 
101
- # find all ret sites
101
+ # find all ret sites and indirect jump sites
102
102
  retsites: set[tuple[int, int | None, int]] = set()
103
+ jumpsites: set[tuple[int, int | None, int]] = set()
103
104
  for bb in blocks.values():
104
- if bb.statements and isinstance(bb.statements[-1], Return):
105
- retsites.add((bb.addr, bb.idx, len(bb.statements) - 1))
105
+ if bb.statements:
106
+ if isinstance(bb.statements[-1], Return):
107
+ retsites.add((bb.addr, bb.idx, len(bb.statements) - 1))
108
+ elif isinstance(bb.statements[-1], Jump):
109
+ jumpsites.add((bb.addr, bb.idx, len(bb.statements) - 1))
106
110
 
107
111
  replacements = defaultdict(dict)
108
112
 
@@ -169,13 +173,13 @@ class SPropagatorAnalysis(Analysis):
169
173
  {
170
174
  loc
171
175
  for _, loc in vvar_uselocs[vvar.varid]
172
- if (loc.block_addr, loc.block_idx, loc.stmt_idx) not in retsites
176
+ if (loc.block_addr, loc.block_idx, loc.stmt_idx) not in (retsites | jumpsites)
173
177
  }
174
178
  )
175
179
  == 1
176
180
  ):
177
181
  if is_const_and_vvar_assignment(stmt):
178
- # this vvar is used once if we exclude its uses at ret sites. we can propagate it
182
+ # this vvar is used once if we exclude its uses at ret sites or jump sites. we can propagate it
179
183
  for vvar_used, vvar_useloc in vvar_uselocs[vvar.varid]:
180
184
  replacements[vvar_useloc][vvar_used] = stmt.src
181
185
 
@@ -234,15 +238,22 @@ class SPropagatorAnalysis(Analysis):
234
238
 
235
239
  if len(tmp_uses) <= 2:
236
240
  tmp_used, tmp_use_stmtidx = next(iter(tmp_uses))
237
- if is_const_vvar_load_dirty_assignment(stmt) and not any(
238
- isinstance(stmt_, Store)
239
- for stmt_ in block.statements[tmp_def_stmtidx + 1 : tmp_use_stmtidx]
240
- ):
241
- # we can propagate this load because there is no store between its def and use
242
- replacements[
243
- CodeLocation(block_loc.block_addr, tmp_use_stmtidx, block_idx=block_loc.block_idx)
244
- ][tmp_used] = stmt.src
245
- continue
241
+ if is_const_vvar_load_dirty_assignment(stmt):
242
+ same_inst = (
243
+ block.statements[tmp_def_stmtidx].ins_addr == block.statements[tmp_use_stmtidx].ins_addr
244
+ )
245
+ has_store = any(
246
+ isinstance(stmt_, Store)
247
+ for stmt_ in block.statements[tmp_def_stmtidx + 1 : tmp_use_stmtidx]
248
+ )
249
+ if same_inst or not has_store:
250
+ # we can propagate this load because either we do not consider memory aliasing problem
251
+ # within the same instruction (blocks must be originally lifted with
252
+ # CROSS_INSN_OPT=False), or there is no store between its def and use.
253
+ replacements[
254
+ CodeLocation(block_loc.block_addr, tmp_use_stmtidx, block_idx=block_loc.block_idx)
255
+ ][tmp_used] = stmt.src
256
+ continue
246
257
 
247
258
  self.model.replacements = replacements
248
259
 
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import logging
4
4
  from collections import defaultdict
5
5
 
6
- from ailment.statement import Assignment, Call, Label
6
+ from ailment.statement import Statement, Assignment, Call, Label
7
7
  from ailment.expression import VirtualVariable, Expression
8
8
 
9
9
  from angr.utils.ail import is_phi_assignment
@@ -17,27 +17,141 @@ from .s_rda_model import SRDAModel
17
17
  log = logging.getLogger(__name__)
18
18
 
19
19
 
20
- class SRDAView:
20
+ class RegVVarPredicate:
21
21
  """
22
- A view of SRDA model that provides various functionalities for querying the model.
22
+ Implements a predicate that is used in get_reg_vvar_by_stmt_idx and get_reg_vvar_by_insn.
23
23
  """
24
24
 
25
- def __init__(self, model: SRDAModel):
26
- self.model = model
25
+ def __init__(self, reg_offset: int, vvars: set[VirtualVariable], arch):
26
+ self.reg_offset = reg_offset
27
+ self.vvars = vvars
28
+ self.arch = arch
27
29
 
28
30
  def _get_call_clobbered_regs(self, stmt: Call) -> set[int]:
29
31
  cc = stmt.calling_convention
30
32
  if cc is None:
31
33
  # get the default calling convention
32
- cc = default_cc(self.model.arch.name) # TODO: platform and language
34
+ cc = default_cc(self.arch.name) # TODO: platform and language
33
35
  if cc is not None:
34
36
  reg_list = cc.CALLER_SAVED_REGS
35
37
  if isinstance(cc.RETURN_VAL, SimRegArg):
36
38
  reg_list.append(cc.RETURN_VAL.reg_name)
37
- return {self.model.arch.registers[reg_name][0] for reg_name in reg_list}
39
+ return {self.arch.registers[reg_name][0] for reg_name in reg_list}
38
40
  log.warning("Cannot determine registers that are clobbered by call statement %r.", stmt)
39
41
  return set()
40
42
 
43
+ def predicate(self, stmt: Statement) -> bool:
44
+ if (
45
+ isinstance(stmt, Assignment)
46
+ and isinstance(stmt.dst, VirtualVariable)
47
+ and stmt.dst.was_reg
48
+ and stmt.dst.reg_offset == self.reg_offset
49
+ ):
50
+ self.vvars.add(stmt.dst)
51
+ return True
52
+ if isinstance(stmt, Call):
53
+ if (
54
+ isinstance(stmt.ret_expr, VirtualVariable)
55
+ and stmt.ret_expr.was_reg
56
+ and stmt.ret_expr.reg_offset == self.reg_offset
57
+ ):
58
+ self.vvars.add(stmt.ret_expr)
59
+ return True
60
+ # is it clobbered maybe?
61
+ clobbered_regs = self._get_call_clobbered_regs(stmt)
62
+ if self.reg_offset in clobbered_regs:
63
+ return True
64
+ return False
65
+
66
+
67
+ class StackVVarPredicate:
68
+ """
69
+ Implements a predicate that is used in get_stack_vvar_by_stmt_idx and get_stack_vvar_by_insn.
70
+ """
71
+
72
+ def __init__(self, stack_offset: int, size: int, vvars: set[VirtualVariable]):
73
+ self.stack_offset = stack_offset
74
+ self.size = size
75
+ self.vvars = vvars
76
+
77
+ def predicate(self, stmt: Statement) -> bool:
78
+ if (
79
+ isinstance(stmt, Assignment)
80
+ and isinstance(stmt.dst, VirtualVariable)
81
+ and stmt.dst.was_stack
82
+ and stmt.dst.stack_offset == self.stack_offset
83
+ and stmt.dst.size == self.size
84
+ ):
85
+ self.vvars.add(stmt.dst)
86
+ return True
87
+ return False
88
+
89
+
90
+ class SRDAView:
91
+ """
92
+ A view of SRDA model that provides various functionalities for querying the model.
93
+ """
94
+
95
+ def __init__(self, model: SRDAModel):
96
+ self.model = model
97
+
98
+ def _get_vvar_by_stmt(
99
+ self, block_addr: int, block_idx: int | None, stmt_idx: int, op_type: ObservationPointType, predicate
100
+ ):
101
+ # find the starting block
102
+ for block in self.model.func_graph:
103
+ if block.addr == block_addr and block.idx == block_idx:
104
+ the_block = block
105
+ break
106
+ else:
107
+ return
108
+
109
+ traversed = set()
110
+ queue = [(the_block, stmt_idx if op_type == ObservationPointType.OP_BEFORE else stmt_idx + 1)]
111
+ while queue:
112
+ block, start_stmt_idx = queue.pop(0)
113
+ traversed.add(block)
114
+
115
+ stmts = block.statements[:start_stmt_idx] if start_stmt_idx is not None else block.statements
116
+
117
+ for stmt in reversed(stmts):
118
+ should_break = predicate(stmt)
119
+ if should_break:
120
+ break
121
+ else:
122
+ # not found
123
+ for pred in self.model.func_graph.predecessors(block):
124
+ if pred not in traversed:
125
+ traversed.add(pred)
126
+ queue.append((pred, None))
127
+
128
+ def get_reg_vvar_by_stmt(
129
+ self, reg_offset: int, block_addr: int, block_idx: int | None, stmt_idx: int, op_type: ObservationPointType
130
+ ) -> VirtualVariable | None:
131
+ reg_offset = get_reg_offset_base(reg_offset, self.model.arch)
132
+ vvars = set()
133
+ predicater = RegVVarPredicate(reg_offset, vvars, self.model.arch)
134
+ self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
135
+
136
+ assert len(vvars) <= 1
137
+ return next(iter(vvars), None)
138
+
139
+ def get_stack_vvar_by_stmt( # pylint: disable=too-many-positional-arguments
140
+ self,
141
+ stack_offset: int,
142
+ size: int,
143
+ block_addr: int,
144
+ block_idx: int | None,
145
+ stmt_idx: int,
146
+ op_type: ObservationPointType,
147
+ ) -> VirtualVariable | None:
148
+ vvars = set()
149
+ predicater = StackVVarPredicate(stack_offset, size, vvars)
150
+ self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
151
+
152
+ assert len(vvars) <= 1
153
+ return next(iter(vvars), None)
154
+
41
155
  def _get_vvar_by_insn(self, addr: int, op_type: ObservationPointType, predicate, block_idx: int | None = None):
42
156
  # find the starting block
43
157
  for block in self.model.func_graph:
@@ -47,6 +161,7 @@ class SRDAView:
47
161
  else:
48
162
  return
49
163
 
164
+ # determine the starting stmt_idx
50
165
  starting_stmt_idx = len(the_block.statements) if op_type == ObservationPointType.OP_AFTER else 0
51
166
  for stmt_idx, stmt in enumerate(the_block.statements):
52
167
  # skip all labels and phi assignments
@@ -65,55 +180,16 @@ class SRDAView:
65
180
  starting_stmt_idx = stmt_idx
66
181
  break
67
182
 
68
- traversed = set()
69
- queue = [(the_block, starting_stmt_idx)]
70
- while queue:
71
- block, start_stmt_idx = queue.pop(0)
72
- traversed.add(block)
73
-
74
- stmts = block.statements[:start_stmt_idx] if start_stmt_idx is not None else block.statements
75
-
76
- for stmt in reversed(stmts):
77
- should_break = predicate(stmt)
78
- if should_break:
79
- break
80
- else:
81
- # not found
82
- for pred in self.model.func_graph.predecessors(block):
83
- if pred not in traversed:
84
- traversed.add(pred)
85
- queue.append((pred, None))
183
+ self._get_vvar_by_stmt(the_block.addr, the_block.idx, starting_stmt_idx, op_type, predicate)
86
184
 
87
185
  def get_reg_vvar_by_insn(
88
186
  self, reg_offset: int, addr: int, op_type: ObservationPointType, block_idx: int | None = None
89
187
  ) -> VirtualVariable | None:
90
188
  reg_offset = get_reg_offset_base(reg_offset, self.model.arch)
91
189
  vvars = set()
190
+ predicater = RegVVarPredicate(reg_offset, vvars, self.model.arch)
92
191
 
93
- def _predicate(stmt) -> bool:
94
- if (
95
- isinstance(stmt, Assignment)
96
- and isinstance(stmt.dst, VirtualVariable)
97
- and stmt.dst.was_reg
98
- and stmt.dst.reg_offset == reg_offset
99
- ):
100
- vvars.add(stmt.dst)
101
- return True
102
- if isinstance(stmt, Call):
103
- if (
104
- isinstance(stmt.ret_expr, VirtualVariable)
105
- and stmt.ret_expr.was_reg
106
- and stmt.ret_expr.reg_offset == reg_offset
107
- ):
108
- vvars.add(stmt.ret_expr)
109
- return True
110
- # is it clobbered maybe?
111
- clobbered_regs = self._get_call_clobbered_regs(stmt)
112
- if reg_offset in clobbered_regs:
113
- return True
114
- return False
115
-
116
- self._get_vvar_by_insn(addr, op_type, _predicate, block_idx=block_idx)
192
+ self._get_vvar_by_insn(addr, op_type, predicater.predicate, block_idx=block_idx)
117
193
 
118
194
  assert len(vvars) <= 1
119
195
  return next(iter(vvars), None)
@@ -122,20 +198,8 @@ class SRDAView:
122
198
  self, stack_offset: int, size: int, addr: int, op_type: ObservationPointType, block_idx: int | None = None
123
199
  ) -> VirtualVariable | None:
124
200
  vvars = set()
125
-
126
- def _predicate(stmt) -> bool:
127
- if (
128
- isinstance(stmt, Assignment)
129
- and isinstance(stmt.dst, VirtualVariable)
130
- and stmt.dst.was_stack
131
- and stmt.dst.stack_offset == stack_offset
132
- and stmt.dst.size == size
133
- ):
134
- vvars.add(stmt.dst)
135
- return True
136
- return False
137
-
138
- self._get_vvar_by_insn(addr, op_type, _predicate, block_idx=block_idx)
201
+ predicater = StackVVarPredicate(stack_offset, size, vvars)
202
+ self._get_vvar_by_insn(addr, op_type, predicater.predicate, block_idx=block_idx)
139
203
 
140
204
  assert len(vvars) <= 1
141
205
  return next(iter(vvars), None)
@@ -223,6 +223,20 @@ class SimEngineVRAIL(
223
223
  for ret_expr in stmt.ret_exprs:
224
224
  self._expr(ret_expr)
225
225
 
226
+ def _ail_handle_DirtyExpression(self, expr: ailment.Expr.DirtyExpression) -> RichR:
227
+ for op in expr.operands:
228
+ self._expr(op)
229
+ if expr.guard:
230
+ self._expr(expr.guard)
231
+ if expr.maddr:
232
+ self._expr(expr.maddr)
233
+ return RichR(self.state.top(expr.bits))
234
+
235
+ def _ail_handle_VEXCCallExpression(self, expr: ailment.Expr.VEXCCallExpression) -> RichR:
236
+ for op in expr.operands:
237
+ self._expr(op)
238
+ return RichR(self.state.top(expr.bits))
239
+
226
240
  # Expression handlers
227
241
 
228
242
  def _expr(self, expr: ailment.Expr.Expression):
@@ -435,6 +435,14 @@ class SimEngineVRBase(SimEngineLight):
435
435
  region=self.func_addr,
436
436
  )
437
437
  self.variable_manager[self.func_addr].add_variable("register", vvar.oident, variable)
438
+ elif vvar.was_tmp:
439
+ # FIXME: we treat all tmp vvars as registers
440
+ variable = SimRegisterVariable(
441
+ 4096 + vvar.tmp_idx,
442
+ vvar.size,
443
+ ident=self.variable_manager[self.func_addr].next_variable_ident("register"),
444
+ region=self.func_addr,
445
+ )
438
446
  else:
439
447
  raise NotImplementedError
440
448
  else:
@@ -1071,6 +1079,9 @@ class SimEngineVRBase(SimEngineLight):
1071
1079
  self.variable_manager[self.func_addr].add_variable("stack", vvar.stack_offset, variable)
1072
1080
  elif vvar.category == ailment.Expr.VirtualVariableCategory.PARAMETER:
1073
1081
  raise KeyError(f"Missing virtual variable for parameter {vvar}")
1082
+ elif vvar.category == ailment.Expr.VirtualVariableCategory.TMP:
1083
+ # we don't track variables for tmps
1084
+ pass
1074
1085
  else:
1075
1086
  raise NotImplementedError
1076
1087
 
@@ -1212,7 +1212,7 @@ class SimCCCdecl(SimCC):
1212
1212
  if isinstance(arg_type, (SimTypeArray, SimTypeFixedSizeArray)): # hack
1213
1213
  arg_type = SimTypePointer(arg_type.elem_type).with_arch(self.arch)
1214
1214
  locs_size = 0
1215
- byte_size = arg_type.size // self.arch.byte_width
1215
+ byte_size = arg_type.size // self.arch.byte_width if arg_type.size is not None else self.arch.bytes
1216
1216
  locs = []
1217
1217
  while locs_size < byte_size:
1218
1218
  locs.append(next(session.both_iter))
@@ -1293,7 +1293,7 @@ class SimCCMicrosoftAMD64(SimCC):
1293
1293
  except StopIteration:
1294
1294
  int_loc = fp_loc = next(session.both_iter)
1295
1295
 
1296
- byte_size = arg_type.size // self.arch.byte_width
1296
+ byte_size = arg_type.size // self.arch.byte_width if arg_type.size is not None else self.arch.bytes
1297
1297
 
1298
1298
  if isinstance(arg_type, SimTypeFloat):
1299
1299
  return fp_loc.refine(size=byte_size, is_fp=True, arch=self.arch)
@@ -604,6 +604,9 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
604
604
  if self._is_top(expr_0) or self._is_top(expr_1):
605
605
  return self._top(expr.result_size(self.tyenv))
606
606
 
607
+ if expr_1.concrete and expr_1.concrete_value == 0:
608
+ return self._top(expr.result_size(self.tyenv))
609
+
607
610
  signed = "U" in expr.op # Iop_DivModU64to32 vs Iop_DivMod
608
611
  from_size = expr_0.size()
609
612
  to_size = expr_1.size()
@@ -632,10 +635,13 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
632
635
  if self._is_top(expr_0) or self._is_top(expr_1):
633
636
  return self._top(expr_0.size())
634
637
 
638
+ if expr_1.concrete and expr_1.concrete_value == 0:
639
+ return self._top(expr.result_size(self.tyenv))
640
+
635
641
  try:
636
642
  return expr_0 / expr_1
637
643
  except ZeroDivisionError:
638
- return self._top(expr_0.size())
644
+ return self._top(expr.result_size(self.tyenv))
639
645
 
640
646
  def _handle_Mod(self, expr):
641
647
  args, r = self._binop_get_args(expr)
@@ -646,6 +652,9 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
646
652
  if self._is_top(expr_0) or self._is_top(expr_1):
647
653
  return self._top(expr_0.size())
648
654
 
655
+ if expr_1.concrete and expr_1.concrete_value == 0:
656
+ return self._top(expr.result_size(self.tyenv))
657
+
649
658
  try:
650
659
  return expr_0 - (expr_1 // expr_1) * expr_1
651
660
  except ZeroDivisionError:
@@ -948,6 +957,9 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
948
957
  def _ail_handle_Return(self, stmt):
949
958
  pass
950
959
 
960
+ def _ail_handle_DirtyStatement(self, stmt):
961
+ self._expr(stmt.dirty)
962
+
951
963
  #
952
964
  # Expression handlers
953
965
  #
@@ -974,7 +986,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
974
986
  return expr
975
987
 
976
988
  def _ail_handle_CallExpr(self, expr: ailment.Stmt.Call):
977
- self._expr(expr.target)
989
+ if not isinstance(expr.target, str):
990
+ self._expr(expr.target)
978
991
  return expr
979
992
 
980
993
  def _ail_handle_Reinterpret(self, expr: ailment.Expr.Reinterpret):
@@ -999,6 +1012,15 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
999
1012
 
1000
1013
  return expr
1001
1014
 
1015
+ def _ail_handle_DirtyExpression(self, expr: ailment.Expr.DirtyExpression):
1016
+ for operand in expr.operands:
1017
+ self._expr(operand)
1018
+ if expr.guard is not None:
1019
+ self._expr(expr.guard)
1020
+ if expr.maddr is not None:
1021
+ self._expr(expr.maddr)
1022
+ return expr
1023
+
1002
1024
  def _ail_handle_UnaryOp(self, expr):
1003
1025
  handler_name = f"_handle_{expr.op}"
1004
1026
  try:
@@ -1,6 +1,9 @@
1
1
  from __future__ import annotations
2
+
2
3
  import logging
3
4
 
5
+ import claripy
6
+
4
7
  from .base import SimSootExpr
5
8
 
6
9
  l = logging.getLogger(name=__name__)
@@ -9,4 +12,4 @@ l = logging.getLogger(name=__name__)
9
12
  class SimSootExpr_InstanceOf(SimSootExpr):
10
13
  def _execute(self):
11
14
  obj = self._translate_value(self.expr.value)
12
- self.expr = self.state.solver.StringV(obj.type) == self.state.solver.StringV(self.expr.check_type)
15
+ self.expr = claripy.StringV(obj.type) == claripy.StringV(self.expr.check_type)
@@ -504,7 +504,7 @@ class SimSuccessors:
504
504
  fallback = True
505
505
  break
506
506
 
507
- cond_and_targets.append((cond, target if not outer_reverse else state.solver.Reverse(target)))
507
+ cond_and_targets.append((cond, target if not outer_reverse else claripy.Reverse(target)))
508
508
 
509
509
  if reached_sentinel is False:
510
510
  # huh?