angr 9.2.123__py3-none-macosx_11_0_arm64.whl → 9.2.125__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 (104) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +9 -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/codecave.py +77 -0
  6. angr/analyses/decompiler/ail_simplifier.py +16 -19
  7. angr/analyses/decompiler/callsite_maker.py +8 -7
  8. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
  9. angr/analyses/decompiler/clinic.py +58 -2
  10. angr/analyses/decompiler/condition_processor.py +10 -3
  11. angr/analyses/decompiler/decompilation_cache.py +2 -0
  12. angr/analyses/decompiler/decompiler.py +54 -8
  13. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
  14. angr/analyses/decompiler/dephication/rewriting_engine.py +64 -1
  15. angr/analyses/decompiler/expression_narrower.py +5 -1
  16. angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
  17. angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
  18. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +13 -0
  19. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +23 -4
  20. angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
  21. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
  22. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
  23. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
  24. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
  25. angr/analyses/decompiler/optimization_passes/tag_slicer.py +41 -0
  26. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
  27. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +2 -0
  28. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +2 -2
  29. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
  30. angr/analyses/decompiler/region_identifier.py +36 -0
  31. angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
  32. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
  33. angr/analyses/decompiler/ssailification/rewriting.py +5 -2
  34. angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
  35. angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
  36. angr/analyses/decompiler/ssailification/ssailification.py +17 -9
  37. angr/analyses/decompiler/ssailification/traversal.py +3 -1
  38. angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
  39. angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
  40. angr/analyses/decompiler/structured_codegen/c.py +42 -4
  41. angr/analyses/decompiler/structuring/phoenix.py +3 -0
  42. angr/analyses/patchfinder.py +137 -0
  43. angr/analyses/pathfinder.py +282 -0
  44. angr/analyses/propagator/engine_ail.py +10 -3
  45. angr/analyses/reaching_definitions/engine_ail.py +10 -15
  46. angr/analyses/s_propagator.py +16 -9
  47. angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
  48. angr/analyses/smc.py +159 -0
  49. angr/analyses/variable_recovery/engine_ail.py +14 -0
  50. angr/analyses/variable_recovery/engine_base.py +11 -0
  51. angr/angrdb/models.py +1 -2
  52. angr/engines/light/engine.py +12 -0
  53. angr/engines/vex/heavy/heavy.py +2 -0
  54. angr/exploration_techniques/spiller_db.py +1 -2
  55. angr/knowledge_plugins/__init__.py +2 -0
  56. angr/knowledge_plugins/decompilation.py +45 -0
  57. angr/knowledge_plugins/functions/function.py +4 -0
  58. angr/knowledge_plugins/functions/function_manager.py +18 -9
  59. angr/knowledge_plugins/functions/function_parser.py +1 -1
  60. angr/knowledge_plugins/functions/soot_function.py +1 -0
  61. angr/knowledge_plugins/key_definitions/atoms.py +8 -0
  62. angr/lib/angr_native.dylib +0 -0
  63. angr/misc/ux.py +2 -2
  64. angr/procedures/definitions/parse_win32json.py +2 -1
  65. angr/project.py +17 -1
  66. angr/state_plugins/history.py +6 -4
  67. angr/storage/memory_mixins/actions_mixin.py +7 -7
  68. angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
  69. angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
  70. angr/storage/memory_mixins/clouseau_mixin.py +3 -3
  71. angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
  72. angr/storage/memory_mixins/default_filler_mixin.py +3 -3
  73. angr/storage/memory_mixins/memory_mixin.py +45 -34
  74. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
  75. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
  76. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
  77. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
  78. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
  79. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
  80. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
  81. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
  82. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
  83. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
  84. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
  85. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
  86. angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
  87. angr/storage/memory_mixins/simplification_mixin.py +2 -2
  88. angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
  89. angr/storage/memory_mixins/slotted_memory.py +3 -3
  90. angr/storage/memory_mixins/smart_find_mixin.py +1 -0
  91. angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
  92. angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
  93. angr/storage/memory_object.py +4 -3
  94. angr/utils/bits.py +4 -0
  95. angr/utils/constants.py +1 -1
  96. angr/utils/graph.py +15 -0
  97. angr/utils/tagged_interval_map.py +112 -0
  98. angr/vaults.py +2 -2
  99. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/METADATA +6 -6
  100. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/RECORD +104 -97
  101. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/WHEEL +1 -1
  102. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/LICENSE +0 -0
  103. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/entry_points.txt +0 -0
  104. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/top_level.txt +0 -0
@@ -56,6 +56,7 @@ class Function(Serializable):
56
56
  "addr",
57
57
  "is_simprocedure",
58
58
  "_name",
59
+ "previous_names",
59
60
  "is_default_name",
60
61
  "from_signature",
61
62
  "binary_name",
@@ -224,6 +225,7 @@ class Function(Serializable):
224
225
  else:
225
226
  self.is_default_name = False
226
227
  self._name = name
228
+ self.previous_names = []
227
229
  self.from_signature = None
228
230
 
229
231
  # Determine the name the binary where this function is.
@@ -274,6 +276,7 @@ class Function(Serializable):
274
276
 
275
277
  @name.setter
276
278
  def name(self, v):
279
+ self.previous_names.append(self._name)
277
280
  self._name = v
278
281
  self._function_manager._kb.labels[self.addr] = v
279
282
 
@@ -1667,6 +1670,7 @@ class Function(Serializable):
1667
1670
  func._endpoints = self._endpoints.copy()
1668
1671
  func._call_sites = self._call_sites.copy()
1669
1672
  func._project = self._project
1673
+ func.previous_names = list(self.previous_names)
1670
1674
  func.is_plt = self.is_plt
1671
1675
  func.is_simprocedure = self.is_simprocedure
1672
1676
  func.binary_name = self.binary_name
@@ -313,7 +313,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
313
313
  if isinstance(k, self.function_address_types):
314
314
  f = self.function(addr=k)
315
315
  elif type(k) is str:
316
- f = self.function(name=k)
316
+ f = self.function(name=k) or self.function(name=k, check_previous_names=True)
317
317
  else:
318
318
  raise ValueError(f"FunctionManager.__getitem__ does not support keys of type {type(k)}")
319
319
 
@@ -350,9 +350,9 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
350
350
  def get_by_addr(self, addr) -> Function:
351
351
  return self._function_map.get(addr)
352
352
 
353
- def get_by_name(self, name: str) -> Generator[Function]:
353
+ def get_by_name(self, name: str, check_previous_names: bool = False) -> Generator[Function]:
354
354
  for f in self._function_map.values():
355
- if f.name == name:
355
+ if f.name == name or (check_previous_names and name in f.previous_names):
356
356
  yield f
357
357
 
358
358
  def _function_added(self, func: Function):
@@ -411,7 +411,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
411
411
  except KeyError:
412
412
  return None
413
413
 
414
- def query(self, query: str) -> Function | None:
414
+ def query(self, query: str, check_previous_names: bool = False) -> Function | None:
415
415
  """
416
416
  Query for a function using selectors to disambiguate. Supported variations:
417
417
 
@@ -430,19 +430,21 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
430
430
  addr = int(matches.group(2), 0)
431
431
  try:
432
432
  func = self._function_map.get(addr)
433
- if func.name == name:
433
+ if func.name == name or (check_previous_names and name in func.previous_names):
434
434
  return func
435
435
  except KeyError:
436
436
  pass
437
437
 
438
438
  obj_name = selector or self._kb._project.loader.main_object.binary_basename
439
- for func in self.get_by_name(name):
439
+ for func in self.get_by_name(name, check_previous_names=check_previous_names):
440
440
  if func.binary_name == obj_name:
441
441
  return func
442
442
 
443
443
  return None
444
444
 
445
- def function(self, addr=None, name=None, create=False, syscall=False, plt=None) -> Function | None:
445
+ def function(
446
+ self, addr=None, name=None, check_previous_names=False, create=False, syscall=False, plt=None
447
+ ) -> Function | None:
446
448
  """
447
449
  Get a function object from the function manager.
448
450
 
@@ -457,6 +459,13 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
457
459
  :return: The Function instance, or None if the function is not found and create is False.
458
460
  :rtype: Function or None
459
461
  """
462
+ if name is not None and name.startswith("sub_"):
463
+ try:
464
+ addr = int(name.split("_")[-1], 16)
465
+ name = None
466
+ except ValueError:
467
+ pass
468
+
460
469
  if addr is not None:
461
470
  try:
462
471
  f = self._function_map.get(addr)
@@ -472,11 +481,11 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
472
481
  f.is_syscall = True
473
482
  return f
474
483
  elif name is not None:
475
- func = self.query(name)
484
+ func = self.query(name, check_previous_names=check_previous_names)
476
485
  if func is not None:
477
486
  return func
478
487
 
479
- for func in self.get_by_name(name):
488
+ for func in self.get_by_name(name, check_previous_names=check_previous_names):
480
489
  if plt is None or func.is_plt == plt:
481
490
  return func
482
491
 
@@ -33,7 +33,7 @@ class FunctionParser:
33
33
  obj.is_syscall = function.is_syscall
34
34
  obj.is_simprocedure = function.is_simprocedure
35
35
  obj.returning = function.returning
36
- obj.alignment = function.alignment
36
+ obj.alignment = function.is_alignment
37
37
  obj.binary_name = function.binary_name or ""
38
38
  obj.normalized = function.normalized
39
39
 
@@ -34,6 +34,7 @@ class SootFunction(Function):
34
34
  # block nodes (basic block nodes) at whose ends the function terminates
35
35
  # in theory, if everything works fine, endpoints == ret_sites | jumpout_sites | callout_sites
36
36
  self._endpoints = defaultdict(set)
37
+ self.previous_names = []
37
38
 
38
39
  self._call_sites = {}
39
40
  self.addr = addr
@@ -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
  """
Binary file
angr/misc/ux.py CHANGED
@@ -20,9 +20,9 @@ def deprecated(replacement=None):
20
20
  def inner(*args, **kwargs):
21
21
  if func not in already_complained:
22
22
  if replacement is None:
23
- warnings.warn(f"Don't use {func.__name__}", DeprecationWarning, stacklevel=1)
23
+ warnings.warn(f"Don't use {func.__name__}", DeprecationWarning, stacklevel=2)
24
24
  else:
25
- warnings.warn(f"Use {replacement} instead of {func.__name__}", DeprecationWarning, stacklevel=1)
25
+ warnings.warn(f"Use {replacement} instead of {func.__name__}", DeprecationWarning, stacklevel=2)
26
26
  already_complained.add(func)
27
27
  return func(*args, **kwargs)
28
28
 
@@ -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()
angr/project.py CHANGED
@@ -236,7 +236,7 @@ class Project:
236
236
  self._initialize_analyses_hub()
237
237
 
238
238
  # Step 5.3: ...etc
239
- self.kb = KnowledgeBase(self, name="global")
239
+ self._knowledge_bases = {"default": KnowledgeBase(self, name="global")}
240
240
 
241
241
  self.is_java_project = isinstance(self.arch, ArchSoot)
242
242
  self.is_java_jni_project = isinstance(self.arch, ArchSoot) and getattr(
@@ -257,6 +257,22 @@ class Project:
257
257
  # Step 7: Run OS-specific configuration
258
258
  self.simos.configure_project()
259
259
 
260
+ @property
261
+ def kb(self):
262
+ return self._knowledge_bases["default"]
263
+
264
+ @kb.setter
265
+ def kb(self, kb):
266
+ self._knowledge_bases["default"] = kb
267
+
268
+ def get_kb(self, name):
269
+ try:
270
+ return self._knowledge_bases[name]
271
+ except KeyError:
272
+ kb = KnowledgeBase(self, name)
273
+ self._knowledge_bases[name] = kb
274
+ return kb
275
+
260
276
  @property
261
277
  def analyses(self) -> AnalysesHubWithDefault:
262
278
  result = self._analyses
@@ -63,9 +63,11 @@ class SimStateHistory(SimStatePlugin):
63
63
  self.successor_ip = None if clone is None else clone.successor_ip
64
64
 
65
65
  self.strongref_state = None if clone is None else clone.strongref_state
66
+ self.arch = None
66
67
 
67
68
  def init_state(self):
68
69
  self.successor_ip = self.state._ip
70
+ self.arch = self.state.arch
69
71
 
70
72
  def __getstate__(self):
71
73
  # flatten ancestry, otherwise we hit recursion errors trying to get the entire history...
@@ -217,7 +219,7 @@ class SimStateHistory(SimStatePlugin):
217
219
  read_offset = None
218
220
  elif isinstance(read_from, str):
219
221
  read_type = "reg"
220
- read_offset = self.state.project.arch.registers[read_from][0]
222
+ read_offset = self.arch.registers[read_from][0]
221
223
  else:
222
224
  read_type = "mem"
223
225
  read_offset = read_from
@@ -227,7 +229,7 @@ class SimStateHistory(SimStatePlugin):
227
229
  write_offset = None
228
230
  elif isinstance(write_to, str):
229
231
  write_type = "reg"
230
- write_offset = self.state.project.arch.registers[write_to][0]
232
+ write_offset = self.arch.registers[write_to][0]
231
233
  else:
232
234
  write_type = "mem"
233
235
  write_offset = write_to
@@ -256,7 +258,7 @@ class SimStateHistory(SimStatePlugin):
256
258
  if isinstance(addr, claripy.ast.Base):
257
259
  if addr.symbolic:
258
260
  return False
259
- addr = self.state.solver.eval(addr)
261
+ addr = addr.concrete_value
260
262
  return addr == read_offset
261
263
 
262
264
  def action_writes(action):
@@ -272,7 +274,7 @@ class SimStateHistory(SimStatePlugin):
272
274
  if isinstance(addr, claripy.ast.Base):
273
275
  if addr.symbolic:
274
276
  return False
275
- addr = self.state.solver.eval(addr)
277
+ addr = addr.concrete_value
276
278
  return addr == write_offset
277
279
 
278
280
  return [
@@ -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):
@@ -13,7 +13,7 @@ l = logging.getLogger(__name__)
13
13
 
14
14
  class DefaultFillerMixin(MemoryMixin):
15
15
  def _default_value(
16
- self, addr, size, name=None, inspect=True, events=True, key=None, fill_missing: bool = True, **kwargs
16
+ self, addr, size, *, name=None, inspect=True, events=True, key=None, fill_missing: bool = True, **kwargs
17
17
  ):
18
18
  if self.state.project and self.state.project.concrete_target:
19
19
  mem = self.state.project.concrete_target.read_memory(addr, size)
@@ -115,7 +115,7 @@ class SpecialFillerMixin(MemoryMixin):
115
115
  super().__init__(**kwargs)
116
116
  self._special_memory_filler = special_memory_filler
117
117
 
118
- def _default_value(self, addr, size, name=None, **kwargs):
118
+ def _default_value(self, addr, size, *, name=None, **kwargs):
119
119
  if (
120
120
  options.SPECIAL_MEMORY_FILL in self.state.options
121
121
  and self.state._special_memory_filler is not None
@@ -135,7 +135,7 @@ class ExplicitFillerMixin(MemoryMixin):
135
135
  super().__init__(**kwargs)
136
136
  self._uninitialized_read_handler = uninitialized_read_handler
137
137
 
138
- def _default_value(self, addr, size, inspect=True, events=True, **kwargs):
138
+ def _default_value(self, addr, size, *, inspect=True, events=True, **kwargs):
139
139
  if self._uninitialized_read_handler is not None:
140
140
  return self._uninitialized_read_handler(addr, size, inspect=inspect, events=events)
141
141
  return super()._default_value(addr, size, inspect=inspect, events=events, **kwargs)
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Iterable
4
- from typing import Any
4
+ from typing import Any, Generic, TypeVar
5
+ from typing_extensions import Self
5
6
 
6
7
  import claripy
7
8
 
@@ -9,33 +10,44 @@ from angr.errors import SimMemoryError
9
10
  from angr.state_plugins.plugin import SimStatePlugin
10
11
 
11
12
 
12
- class MemoryMixin(SimStatePlugin):
13
+ InData = TypeVar("InData")
14
+ OutData = TypeVar("OutData")
15
+ Addr = TypeVar("Addr")
16
+
17
+
18
+ class MemoryMixin(Generic[InData, OutData, Addr], SimStatePlugin):
13
19
  """
14
- Base class for memory mixins. In angr, all memory objects are made by
15
- subclassing one or more MemoryMixins, each adding some functionality to the
16
- memory object.
20
+ MemoryMixin is the base class for the memory model in angr. It provides a
21
+ set of methods that should be implemented by memory models. This is done
22
+ using mixins, where each mixin handles some specific feature of the memory
23
+ model, only overriding methods that it needs to implement its function. The
24
+ memory model class itself then combines a set of mixins using inheritence to
25
+ form the final memory model class.
17
26
  """
18
27
 
19
- SUPPORTS_CONCRETE_LOAD = False
28
+ # pylint: disable=no-self-use,unused-argument
20
29
 
21
- def __init__(self, memory_id=None, endness="Iend_BE"):
30
+ SUPPORTS_CONCRETE_LOAD: bool = False
31
+
32
+ def __init__(self, memory_id: str | None = None, endness: str = "Iend_BE"):
22
33
  super().__init__()
23
34
  self.id = memory_id
24
35
  self.endness = endness
25
36
 
26
- def copy(self, memo): # pylint:disable=unused-argument
37
+ def copy(self, memo) -> Self:
27
38
  o = type(self).__new__(type(self))
28
39
  o.id = self.id
29
40
  o.endness = self.endness
30
41
  return o
31
42
 
32
43
  @property
33
- def category(self):
44
+ def category(self) -> str:
34
45
  """
35
46
  Return the category of this SimMemory instance. It can be one of the three following categories: reg, mem,
36
47
  or file.
37
48
  """
38
49
 
50
+ assert isinstance(self.id, str)
39
51
  if self.id in ("reg", "mem"):
40
52
  return self.id
41
53
 
@@ -48,46 +60,46 @@ class MemoryMixin(SimStatePlugin):
48
60
  raise SimMemoryError(f'Unknown SimMemory category for memory_id "{self.id}"')
49
61
 
50
62
  @property
51
- def variable_key_prefix(self):
63
+ def variable_key_prefix(self) -> tuple[Any, ...]:
52
64
  s = self.category
53
65
  if s == "file":
54
66
  return (s, self.id)
55
67
  return (s,)
56
68
 
57
- def find(self, addr, data, max_search, **kwargs):
58
- pass
69
+ def find(
70
+ self, addr: Addr, data: InData, max_search: int, **kwargs
71
+ ) -> tuple[Addr, list[claripy.ast.Bool], list[int]]: ...
59
72
 
60
- def _add_constraints(self, c, add_constraints=True, condition=None, **kwargs): # pylint:disable=unused-argument
73
+ def _add_constraints(self, c, *, add_constraints=True, condition=None, **kwargs):
61
74
  if add_constraints:
62
75
  to_add = c & condition | ~condition if condition is not None else c
63
76
  self.state.add_constraints(to_add)
64
77
 
65
- def load(self, addr, size=None, **kwargs):
66
- pass
78
+ def load(self, addr: Addr, size: InData | None = None, **kwargs) -> OutData: ...
67
79
 
68
- def store(self, addr, data, **kwargs):
69
- pass
80
+ def store(self, addr: Addr, data: InData, size: InData | None = None, **kwargs) -> None: ...
70
81
 
71
- def merge(self, others, merge_conditions, common_ancestor=None) -> bool:
72
- pass
82
+ def merge(
83
+ self, others: list[Self], merge_conditions: list[claripy.ast.Bool], common_ancestor: Self | None = None
84
+ ) -> bool: ...
73
85
 
74
- def compare(self, other) -> bool:
75
- pass
86
+ def compare(self, other: Self) -> bool: ...
76
87
 
77
- def widen(self, others):
78
- pass
88
+ def widen(self, others: list[Self]) -> bool: ...
79
89
 
80
- def permissions(self, addr, permissions=None, **kwargs):
81
- pass
90
+ def permissions(self, addr: Addr, permissions: int | claripy.ast.BV | None = None, **kwargs) -> claripy.ast.BV: ...
82
91
 
83
- def map_region(self, addr, length, permissions, init_zero=False, **kwargs):
92
+ def map_region(
93
+ self, addr: Addr, length: int, permissions: int | claripy.ast.BV, *, init_zero: bool = False, **kwargs
94
+ ):
84
95
  pass
85
96
 
86
- def unmap_region(self, addr, length, **kwargs):
97
+ def unmap_region(self, addr: Addr, length: int, **kwargs):
87
98
  pass
88
99
 
89
100
  # Optional interface:
90
- def concrete_load(self, addr, size, writing=False, **kwargs) -> memoryview:
101
+ # TODO type this correctly. maybe split the bitmap version into another function?
102
+ def concrete_load(self, addr, size, writing=False, **kwargs) -> Any:
91
103
  """
92
104
  Set SUPPORTS_CONCRETE_LOAD to True and implement concrete_load if reading concrete bytes is faster in this
93
105
  memory model.
@@ -99,7 +111,7 @@ class MemoryMixin(SimStatePlugin):
99
111
  """
100
112
  raise NotImplementedError
101
113
 
102
- def erase(self, addr, size=None, **kwargs) -> None:
114
+ def erase(self, addr: Addr, size: int | None = None, **kwargs) -> None:
103
115
  """
104
116
  Set [addr:addr+size) to uninitialized. In many cases this will be faster than overwriting those locations with
105
117
  new values. This is commonly used during static data flow analysis.
@@ -110,9 +122,7 @@ class MemoryMixin(SimStatePlugin):
110
122
  """
111
123
  raise NotImplementedError
112
124
 
113
- def _default_value( # pylint:disable=too-many-positional-arguments
114
- self, addr, size, name=None, inspect=True, events=True, key=None, **kwargs
115
- ):
125
+ def _default_value(self, addr, size, *, name=None, inspect=True, events=True, key=None, **kwargs) -> OutData:
116
126
  """
117
127
  Override this method to provide default values for a variety of edge cases and base cases.
118
128
 
@@ -123,8 +133,9 @@ class MemoryMixin(SimStatePlugin):
123
133
 
124
134
  The ``inspect``, ``events``, and ``key`` parameters are for ``state.solver.Unconstrained``, if it is used.
125
135
  """
136
+ raise NotImplementedError
126
137
 
127
- def _merge_values(self, values: Iterable[tuple[Any, Any]], merged_size: int, **kwargs) -> Any | None:
138
+ def _merge_values(self, values: Iterable[tuple[Any, Any]], merged_size: int, **kwargs) -> OutData | None:
128
139
  """
129
140
  Override this method to provide value merging support.
130
141
 
@@ -149,7 +160,7 @@ class MemoryMixin(SimStatePlugin):
149
160
  def _replace_all(self, addrs: Iterable[int], old: claripy.ast.BV, new: claripy.ast.BV):
150
161
  raise NotImplementedError
151
162
 
152
- def copy_contents(self, dst, src, size, condition=None, **kwargs):
163
+ def copy_contents(self, dst: Addr, src: Addr, size: InData, condition: claripy.ast.Bool | None = None, **kwargs):
153
164
  """
154
165
  Override this method to provide faster copying of large chunks of data.
155
166