angr 9.2.123__py3-none-win_amd64.whl → 9.2.124__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 (84) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
  3. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
  4. angr/analyses/decompiler/ail_simplifier.py +16 -19
  5. angr/analyses/decompiler/callsite_maker.py +8 -7
  6. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
  7. angr/analyses/decompiler/clinic.py +27 -1
  8. angr/analyses/decompiler/condition_processor.py +10 -3
  9. angr/analyses/decompiler/decompilation_cache.py +2 -0
  10. angr/analyses/decompiler/decompiler.py +50 -8
  11. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
  12. angr/analyses/decompiler/dephication/rewriting_engine.py +64 -1
  13. angr/analyses/decompiler/expression_narrower.py +5 -1
  14. angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
  15. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +7 -0
  16. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +23 -4
  17. angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
  18. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
  19. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
  20. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
  21. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
  22. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
  23. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +2 -0
  24. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
  25. angr/analyses/decompiler/region_identifier.py +36 -0
  26. angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
  27. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
  28. angr/analyses/decompiler/ssailification/rewriting.py +5 -2
  29. angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
  30. angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
  31. angr/analyses/decompiler/ssailification/ssailification.py +17 -9
  32. angr/analyses/decompiler/ssailification/traversal.py +3 -1
  33. angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
  34. angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
  35. angr/analyses/decompiler/structured_codegen/c.py +42 -4
  36. angr/analyses/decompiler/structuring/phoenix.py +3 -0
  37. angr/analyses/propagator/engine_ail.py +10 -3
  38. angr/analyses/reaching_definitions/engine_ail.py +10 -15
  39. angr/analyses/s_propagator.py +16 -9
  40. angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
  41. angr/analyses/variable_recovery/engine_ail.py +14 -0
  42. angr/analyses/variable_recovery/engine_base.py +11 -0
  43. angr/engines/light/engine.py +12 -0
  44. angr/knowledge_plugins/__init__.py +2 -0
  45. angr/knowledge_plugins/decompilation.py +45 -0
  46. angr/knowledge_plugins/key_definitions/atoms.py +8 -0
  47. angr/lib/angr_native.dll +0 -0
  48. angr/procedures/definitions/parse_win32json.py +2 -1
  49. angr/storage/memory_mixins/actions_mixin.py +7 -7
  50. angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
  51. angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
  52. angr/storage/memory_mixins/clouseau_mixin.py +3 -3
  53. angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
  54. angr/storage/memory_mixins/default_filler_mixin.py +3 -3
  55. angr/storage/memory_mixins/memory_mixin.py +45 -34
  56. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
  57. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
  58. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
  59. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
  60. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
  61. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
  62. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
  63. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
  64. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
  65. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
  66. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
  67. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
  68. angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
  69. angr/storage/memory_mixins/simplification_mixin.py +2 -2
  70. angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
  71. angr/storage/memory_mixins/slotted_memory.py +3 -3
  72. angr/storage/memory_mixins/smart_find_mixin.py +1 -0
  73. angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
  74. angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
  75. angr/storage/memory_object.py +4 -3
  76. angr/utils/constants.py +1 -1
  77. angr/utils/graph.py +15 -0
  78. angr/vaults.py +2 -2
  79. {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/METADATA +6 -6
  80. {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/RECORD +84 -83
  81. {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
  82. {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
  83. {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
  84. {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
@@ -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)
@@ -238,15 +238,22 @@ class SPropagatorAnalysis(Analysis):
238
238
 
239
239
  if len(tmp_uses) <= 2:
240
240
  tmp_used, tmp_use_stmtidx = next(iter(tmp_uses))
241
- if is_const_vvar_load_dirty_assignment(stmt) and not any(
242
- isinstance(stmt_, Store)
243
- for stmt_ in block.statements[tmp_def_stmtidx + 1 : tmp_use_stmtidx]
244
- ):
245
- # we can propagate this load because there is no store between its def and use
246
- replacements[
247
- CodeLocation(block_loc.block_addr, tmp_use_stmtidx, block_idx=block_loc.block_idx)
248
- ][tmp_used] = stmt.src
249
- 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
250
257
 
251
258
  self.model.replacements = replacements
252
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
 
@@ -957,6 +957,9 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
957
957
  def _ail_handle_Return(self, stmt):
958
958
  pass
959
959
 
960
+ def _ail_handle_DirtyStatement(self, stmt):
961
+ self._expr(stmt.dirty)
962
+
960
963
  #
961
964
  # Expression handlers
962
965
  #
@@ -1009,6 +1012,15 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
1009
1012
 
1010
1013
  return expr
1011
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
+
1012
1024
  def _ail_handle_UnaryOp(self, expr):
1013
1025
  handler_name = f"_handle_{expr.op}"
1014
1026
  try:
@@ -17,6 +17,7 @@ from .structured_code import StructuredCodeManager
17
17
  from .types import TypesStore
18
18
  from .callsite_prototypes import CallsitePrototypes
19
19
  from .custom_strings import CustomStrings
20
+ from .decompilation import DecompilationManager
20
21
 
21
22
 
22
23
  __all__ = (
@@ -38,4 +39,5 @@ __all__ = (
38
39
  "TypesStore",
39
40
  "CallsitePrototypes",
40
41
  "CustomStrings",
42
+ "DecompilationManager",
41
43
  )
@@ -0,0 +1,45 @@
1
+ # pylint:disable=import-outside-toplevel
2
+ from __future__ import annotations
3
+
4
+ from typing import Any, TYPE_CHECKING
5
+
6
+ from .plugin import KnowledgeBasePlugin
7
+
8
+ if TYPE_CHECKING:
9
+ from angr.analyses.decompiler.decompilation_cache import DecompilationCache
10
+
11
+
12
+ class DecompilationManager(KnowledgeBasePlugin):
13
+ """A knowledge base plugin to store decompilation results."""
14
+
15
+ def __init__(self, kb):
16
+ super().__init__(kb=kb)
17
+ self.cached: dict[Any, DecompilationCache] = {}
18
+
19
+ def _normalize_key(self, item: int | str):
20
+ if type(item) is str:
21
+ item = (self._kb.labels.lookup(item[0]), *item[1:])
22
+ return item
23
+
24
+ def __getitem__(self, item) -> DecompilationCache:
25
+ return self.cached[self._normalize_key(item)]
26
+
27
+ def __setitem__(self, key, value: DecompilationCache):
28
+ self.cached[self._normalize_key(key)] = value
29
+
30
+ def __contains__(self, key):
31
+ return self._normalize_key(key) in self.cached
32
+
33
+ def __delitem__(self, key):
34
+ del self.cached[self._normalize_key(key)]
35
+
36
+ def discard(self, key):
37
+ normalized_key = self._normalize_key(key)
38
+ if normalized_key in self.cached:
39
+ del self.cached[normalized_key]
40
+
41
+ def copy(self):
42
+ raise NotImplementedError
43
+
44
+
45
+ KnowledgeBasePlugin.register_default("decompilations", DecompilationManager)
@@ -277,6 +277,10 @@ class VirtualVariable(Atom):
277
277
  def was_parameter(self) -> bool:
278
278
  return self.category == ailment.Expr.VirtualVariableCategory.PARAMETER
279
279
 
280
+ @property
281
+ def was_tmp(self) -> bool:
282
+ return self.category == ailment.Expr.VirtualVariableCategory.TMP
283
+
280
284
  @property
281
285
  def reg_offset(self) -> int | None:
282
286
  if self.was_reg:
@@ -289,6 +293,10 @@ class VirtualVariable(Atom):
289
293
  return self.oident
290
294
  return None
291
295
 
296
+ @property
297
+ def tmp_idx(self) -> int | None:
298
+ return self.oident if self.was_tmp else None
299
+
292
300
 
293
301
  class MemoryLocation(Atom):
294
302
  """
angr/lib/angr_native.dll CHANGED
Binary file
@@ -162,7 +162,8 @@ def do_it(in_dir, out_file):
162
162
 
163
163
  for file in files:
164
164
  logging.info("Found file %s", file)
165
- api_namespaces[file.stem] = json.load(codecs.open(file, "r", "utf-8-sig"))
165
+ with codecs.open(file, "r", "utf-8-sig") as f:
166
+ api_namespaces[file.stem] = json.load(f)
166
167
 
167
168
  logging.info("Making a bunch of types...")
168
169
  missing_types_last_round = set()
@@ -7,7 +7,7 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
7
7
 
8
8
 
9
9
  class ActionsMixinHigh(MemoryMixin):
10
- def load(self, addr, size=None, condition=None, fallback=None, disable_actions=False, action=None, **kwargs):
10
+ def load(self, addr, size=None, *, condition=None, fallback=None, disable_actions=False, action=None, **kwargs):
11
11
  if not disable_actions and o.AUTO_REFS in self.state.options and action is None:
12
12
  action = self.__make_action("read", addr, size, None, condition, fallback)
13
13
 
@@ -28,7 +28,7 @@ class ActionsMixinHigh(MemoryMixin):
28
28
 
29
29
  return r
30
30
 
31
- def store(self, addr, data, size=None, disable_actions=False, action=None, condition=None, **kwargs):
31
+ def store(self, addr, data, size=None, *, disable_actions=False, action=None, condition=None, **kwargs):
32
32
  if not disable_actions and o.AUTO_REFS in self.state.options and action is None:
33
33
  action = self.__make_action("write", addr, size, data, condition, None)
34
34
 
@@ -49,24 +49,24 @@ class ActionsMixinHigh(MemoryMixin):
49
49
  action.added_constraints = claripy.true()
50
50
  return action
51
51
 
52
- def _add_constraints(self, c, action=None, **kwargs):
52
+ def _add_constraints(self, c, *, action=None, **kwargs):
53
53
  if action is not None:
54
54
  action.added_constraints = claripy.And(action.added_constraints, c)
55
55
  return super()._add_constraints(c, action=action, **kwargs)
56
56
 
57
57
 
58
58
  class ActionsMixinLow(MemoryMixin):
59
- def load(self, addr, action=None, **kwargs):
59
+ def load(self, addr, size=None, *, action=None, **kwargs):
60
60
  if action is not None:
61
61
  if action.actual_addrs is None:
62
62
  action.actual_addrs = []
63
63
  action.actual_addrs.append(addr)
64
- return super().load(addr, action=action, **kwargs)
64
+ return super().load(addr, size, action=action, **kwargs)
65
65
 
66
- def store(self, addr, data, action: SimActionData | None = None, **kwargs):
66
+ def store(self, addr, data, size=None, *, action: SimActionData | None = None, **kwargs):
67
67
  if action is not None:
68
68
  if action.actual_addrs is None:
69
69
  action.actual_addrs = []
70
70
  action.actual_addrs.append(addr)
71
71
  action.actual_value = action._make_object(data)
72
- return super().store(addr, data, action=action, **kwargs)
72
+ return super().store(addr, data, size, action=action, **kwargs)
@@ -230,7 +230,7 @@ class AddressConcretizationMixin(MemoryMixin):
230
230
  """
231
231
  Take a list of integers and return a new list of integers where front and back integers interleave.
232
232
  """
233
- lst = [None] * len(addrs)
233
+ lst = [0xFACE] * len(addrs)
234
234
  front, back = 0, len(addrs) - 1
235
235
  i = 0
236
236
  while front <= back:
@@ -257,7 +257,7 @@ class AddressConcretizationMixin(MemoryMixin):
257
257
  return sub_value
258
258
  return claripy.If(addr == concrete_addr, sub_value, read_value)
259
259
 
260
- def load(self, addr, size=None, condition=None, **kwargs):
260
+ def load(self, addr, size=None, *, condition=None, **kwargs):
261
261
  if type(size) is not int:
262
262
  raise TypeError("Size must have been specified as an int before reaching address concretization")
263
263
 
@@ -309,7 +309,7 @@ class AddressConcretizationMixin(MemoryMixin):
309
309
  sub_condition = condition & sub_condition
310
310
  super().store(concrete_addr, data, size=size, condition=sub_condition, **kwargs)
311
311
 
312
- def store(self, addr, data, size=None, condition=None, **kwargs):
312
+ def store(self, addr, data, size=None, *, condition=None, **kwargs):
313
313
  # Fast path
314
314
  if type(addr) is int:
315
315
  self._store_one_addr(addr, data, True, addr, condition, size, **kwargs)
@@ -374,11 +374,11 @@ class AddressConcretizationMixin(MemoryMixin):
374
374
  raise SimMemoryAddressError("Cannot unmap a region for a symbolic address")
375
375
  return super().unmap_region(addr, length, **kwargs)
376
376
 
377
- def concrete_load(self, addr, size, *args, **kwargs):
377
+ def concrete_load(self, addr, size, writing=False, **kwargs):
378
378
  if type(addr) is int:
379
379
  pass
380
380
  elif getattr(addr, "op", None) == "BVV":
381
381
  addr = addr.args[0]
382
382
  else:
383
383
  raise SimMemoryAddressError("Cannot unmap a region for a symbolic address")
384
- return super().concrete_load(addr, size, *args, **kwargs)
384
+ return super().concrete_load(addr, size, writing=writing, **kwargs)
@@ -26,7 +26,7 @@ class DataNormalizationMixin(MemoryMixin):
26
26
 
27
27
  super().store(addr, data_bv, size=size, **kwargs)
28
28
 
29
- def load(self, addr, size=None, fallback=None, **kwargs):
29
+ def load(self, addr, size=None, *, fallback=None, **kwargs):
30
30
  fallback_bv = self._convert_to_ast(fallback, size, self.state.arch.byte_width) if fallback is not None else None
31
31
  return super().load(addr, size=size, fallback=fallback_bv, **kwargs)
32
32
 
@@ -4,7 +4,7 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
4
4
 
5
5
 
6
6
  class InspectMixinHigh(MemoryMixin):
7
- def store(self, addr, data, size=None, condition=None, endness=None, inspect=True, **kwargs):
7
+ def store(self, addr, data, size=None, *, condition=None, endness=None, inspect=True, **kwargs):
8
8
  if not inspect or not self.state.supports_inspect:
9
9
  super().store(addr, data, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
10
10
  return
@@ -63,7 +63,7 @@ class InspectMixinHigh(MemoryMixin):
63
63
  mem_write_endness=endness,
64
64
  )
65
65
 
66
- def load(self, addr, size=None, condition=None, endness=None, inspect=True, **kwargs):
66
+ def load(self, addr, size=None, *, condition=None, endness=None, inspect=True, **kwargs):
67
67
  if not inspect or not self.state.supports_inspect:
68
68
  return super().load(addr, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
69
69
 
@@ -122,7 +122,7 @@ class InspectMixinHigh(MemoryMixin):
122
122
 
123
123
  return r
124
124
 
125
- def _add_constraints(self, c, add_constraints=True, inspect=True, **kwargs):
125
+ def _add_constraints(self, c, *, add_constraints=True, inspect=True, **kwargs):
126
126
  if inspect and self.state.supports_inspect:
127
127
  # tracer uses address_concretization_add_constraints
128
128
  add_constraints = self.state._inspect_getattr("address_concretization_add_constraints", add_constraints)
@@ -5,13 +5,13 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
5
5
 
6
6
 
7
7
  class ConditionalMixin(MemoryMixin):
8
- def load(self, addr, condition=None, fallback=None, **kwargs):
9
- res = super().load(addr, condition=condition, **kwargs)
8
+ def load(self, addr, size=None, *, condition=None, fallback=None, **kwargs):
9
+ res = super().load(addr, size, condition=condition, **kwargs)
10
10
  if condition is not None and fallback is not None:
11
11
  res = claripy.If(condition, res, fallback)
12
12
  return res
13
13
 
14
- def store(self, addr, data, size=None, condition=None, **kwargs):
14
+ def store(self, addr, data, size=None, *, condition=None, **kwargs):
15
15
  condition = self.state._adjust_condition(condition)
16
16
 
17
17
  if condition is None or self.state.solver.is_true(condition):