angr 9.2.75__py3-none-manylinux2014_x86_64.whl → 9.2.77__py3-none-manylinux2014_x86_64.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 (50) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_fast.py +37 -0
  3. angr/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +7 -1
  4. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +7 -1
  5. angr/analyses/decompiler/clinic.py +4 -1
  6. angr/analyses/decompiler/condition_processor.py +4 -0
  7. angr/analyses/decompiler/decompiler.py +4 -0
  8. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +4 -3
  9. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +1 -1
  10. angr/analyses/decompiler/structured_codegen/c.py +32 -21
  11. angr/analyses/propagator/engine_ail.py +1 -1
  12. angr/analyses/reaching_definitions/engine_ail.py +3 -6
  13. angr/analyses/reaching_definitions/engine_vex.py +32 -2
  14. angr/analyses/reaching_definitions/function_handler.py +1 -1
  15. angr/analyses/reaching_definitions/rd_initializer.py +6 -6
  16. angr/analyses/reaching_definitions/rd_state.py +9 -11
  17. angr/analyses/typehoon/typevars.py +19 -29
  18. angr/analyses/variable_recovery/irsb_scanner.py +16 -0
  19. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -31
  20. angr/engines/light/engine.py +1 -1
  21. angr/keyed_region.py +19 -3
  22. angr/knowledge_plugins/cfg/cfg_model.py +25 -16
  23. angr/knowledge_plugins/cfg/memory_data.py +1 -1
  24. angr/knowledge_plugins/functions/function.py +8 -0
  25. angr/knowledge_plugins/key_definitions/live_definitions.py +53 -44
  26. angr/knowledge_plugins/key_definitions/liveness.py +102 -34
  27. angr/knowledge_plugins/key_definitions/rd_model.py +4 -4
  28. angr/knowledge_plugins/propagations/states.py +3 -1
  29. angr/knowledge_plugins/variables/variable_manager.py +51 -25
  30. angr/misc/bug_report.py +2 -2
  31. angr/sim_type.py +46 -0
  32. angr/storage/memory_mixins/__init__.py +3 -2
  33. angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +63 -0
  34. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +5 -0
  35. {angr-9.2.75.dist-info → angr-9.2.77.dist-info}/METADATA +6 -6
  36. {angr-9.2.75.dist-info → angr-9.2.77.dist-info}/RECORD +50 -49
  37. tests/analyses/cfg/test_cfgfast.py +21 -0
  38. tests/analyses/decompiler/test_decompiler.py +22 -1
  39. tests/analyses/test_flirt.py +3 -1
  40. tests/analyses/test_identifier.py +2 -0
  41. tests/engines/test_unicorn.py +4 -0
  42. tests/exploration_techniques/test_driller_core.py +4 -0
  43. tests/exploration_techniques/test_oppologist.py +2 -0
  44. tests/exploration_techniques/test_tracer.py +9 -0
  45. tests/procedures/libc/test_string.py +2 -1
  46. tests/sim/options/test_0div.py +2 -0
  47. tests/state_plugins/posix/test_files.py +2 -0
  48. {angr-9.2.75.dist-info → angr-9.2.77.dist-info}/LICENSE +0 -0
  49. {angr-9.2.75.dist-info → angr-9.2.77.dist-info}/WHEEL +0 -0
  50. {angr-9.2.75.dist-info → angr-9.2.77.dist-info}/top_level.txt +0 -0
@@ -32,9 +32,9 @@ class ReachingDefinitionsModel:
32
32
  len(self.observed_results),
33
33
  )
34
34
 
35
- def add_def(self, d: "Definition", codeloc: "CodeLocation") -> None:
35
+ def add_def(self, d: "Definition") -> None:
36
36
  if self.liveness is not None:
37
- self.liveness.add_def(d, codeloc)
37
+ self.liveness.add_def(d)
38
38
 
39
39
  def kill_def(self, d: "Definition") -> None:
40
40
  if self.liveness is not None:
@@ -48,9 +48,9 @@ class ReachingDefinitionsModel:
48
48
  if self.liveness is not None:
49
49
  self.liveness.at_new_block(code_loc, pred_codelocs)
50
50
 
51
- def complete_loc(self) -> None:
51
+ def make_liveness_snapshot(self) -> None:
52
52
  if self.liveness is not None:
53
- self.liveness.complete_loc()
53
+ self.liveness.make_liveness_snapshot()
54
54
 
55
55
  def find_defs_at(self, code_loc: "CodeLocation", op: int = OP_BEFORE) -> Set["Definition"]:
56
56
  return self.liveness.find_defs_at(code_loc, op=op)
@@ -808,7 +808,9 @@ class PropagatorAILState(PropagatorState):
808
808
  or isinstance(old, ailment.Expr.Register)
809
809
  and (old.reg_offset == self.arch.sp_offset or (not bp_as_gpr and old.reg_offset == self.arch.bp_offset))
810
810
  ):
811
- self._replacements[codeloc][old] = new
811
+ self._replacements[codeloc][old] = (
812
+ new if stmt_to_remove is None else {"expr": new, "stmt_to_remove": stmt_to_remove}
813
+ )
812
814
  replaced = True
813
815
  else:
814
816
  prop_count = 0
@@ -90,6 +90,7 @@ class VariableManagerInternal(Serializable):
90
90
  self._atom_to_variable: Dict[
91
91
  Union[Tuple[int, int], Tuple[int, int, int]], Dict[int, Set[Tuple[SimVariable, int]]]
92
92
  ] = defaultdict(_defaultdict_set)
93
+ self._ident_to_variable: Dict[str, SimVariable] = {}
93
94
  self._variable_counters = {
94
95
  "register": count(),
95
96
  "stack": count(),
@@ -109,6 +110,9 @@ class VariableManagerInternal(Serializable):
109
110
  self.variable_to_types: Dict[SimVariable, SimType] = {}
110
111
  self.variables_with_manual_types = set()
111
112
 
113
+ # optimization
114
+ self._variables_without_writes = set()
115
+
112
116
  self.ret_val_size = None
113
117
 
114
118
  #
@@ -241,6 +245,7 @@ class VariableManagerInternal(Serializable):
241
245
  model._phi_variables[var] = set()
242
246
  else:
243
247
  model._variables.add(var)
248
+ model._ident_to_variable[var.ident] = var
244
249
 
245
250
  # variable accesses
246
251
  for varaccess_pb2 in cmsg.accesses:
@@ -314,6 +319,8 @@ class VariableManagerInternal(Serializable):
314
319
 
315
320
  region.add_variable(offset, var)
316
321
 
322
+ model._variables_without_writes = model.get_variables_without_writes()
323
+
317
324
  return model
318
325
 
319
326
  #
@@ -338,7 +345,7 @@ class VariableManagerInternal(Serializable):
338
345
  ident = "i%s_%d" % (prefix, next(self._variable_counters[sort]))
339
346
  return ident
340
347
 
341
- def add_variable(self, sort, start, variable):
348
+ def add_variable(self, sort, start, variable: SimVariable):
342
349
  if sort == "stack":
343
350
  region = self._stack_region
344
351
  elif sort == "register":
@@ -347,17 +354,17 @@ class VariableManagerInternal(Serializable):
347
354
  region = self._global_region
348
355
  else:
349
356
  raise ValueError("Unsupported sort %s in add_variable()." % sort)
350
- existing = [x for x in region.get_variables_by_offset(start) if x.ident == variable.ident]
351
- if len(existing) == 1:
352
- var = existing[0]
353
- if var.name is not None and not variable.renamed:
354
- variable.name = var.name
355
- variable.renamed = var.renamed
356
- else:
357
- # implicitly overwrite or add I guess
358
- pass
357
+
358
+ # find if there is already an existing variable with the same identifier
359
+ if variable.ident in self._ident_to_variable:
360
+ existing_var = self._ident_to_variable[variable.ident]
361
+ if existing_var.name is not None and not variable.renamed:
362
+ variable.name = existing_var.name
363
+ variable.renamed = existing_var.renamed
364
+ self._ident_to_variable[variable.ident] = variable
359
365
  region.add_variable(start, variable)
360
366
  self._variables.add(variable)
367
+ self._variables_without_writes.add(variable)
361
368
 
362
369
  def set_variable(self, sort, start, variable: SimVariable):
363
370
  if sort == "stack":
@@ -368,17 +375,15 @@ class VariableManagerInternal(Serializable):
368
375
  region = self._global_region
369
376
  else:
370
377
  raise ValueError("Unsupported sort %s in set_variable()." % sort)
371
- existing = [x for x in region.get_variables_by_offset(start) if x.ident == variable.ident]
372
- if len(existing) == 1:
373
- var = existing[0]
374
- if var.name is not None and not variable.renamed:
375
- variable.name = var.name
376
- variable.renamed = var.renamed
377
- else:
378
- # implicitly overwrite or add I guess
379
- pass
378
+ # find if there is already an existing variable with the same identifier
379
+ if variable.ident in self._ident_to_variable:
380
+ existing_var = self._ident_to_variable[variable.ident]
381
+ if existing_var.name is not None and not variable.renamed:
382
+ variable.name = existing_var.name
383
+ variable.renamed = existing_var.renamed
380
384
  region.set_variable(start, variable)
381
385
  self._variables.add(variable)
386
+ self._variables_without_writes.add(variable)
382
387
 
383
388
  def write_to(self, variable, offset, location, overwrite=False, atom=None):
384
389
  self._record_variable_access(
@@ -404,17 +409,19 @@ class VariableManagerInternal(Serializable):
404
409
  overwrite=False,
405
410
  atom=None,
406
411
  ):
407
- # TODO can this line be removed, should we be only adding to _variables in add_variable?
408
- self._variables.add(variable)
409
412
  atom_hash = (hash(atom) & 0xFFFF_FFFF) if atom is not None else None
410
413
  if overwrite:
411
414
  self._variable_accesses[variable] = {VariableAccess(variable, sort, location, offset, atom_hash=atom_hash)}
412
415
  else:
413
416
  self._variable_accesses[variable].add(VariableAccess(variable, sort, location, offset, atom_hash=atom_hash))
414
417
  self.record_variable(location, variable, offset, overwrite=overwrite, atom=atom)
418
+ if sort == VariableAccessSort.WRITE and variable in self._variables_without_writes:
419
+ self._variables_without_writes.discard(variable)
415
420
 
416
421
  def record_variable(self, location: "CodeLocation", variable, offset, overwrite=False, atom=None):
417
- self._variables.add(variable)
422
+ if variable.ident not in self._ident_to_variable:
423
+ self._ident_to_variable[variable.ident] = variable
424
+ self._variables.add(variable)
418
425
  var_and_offset = variable, offset
419
426
  atom_hash = (hash(atom) & 0xFFFF_FFFF) if atom is not None else None
420
427
  key = (
@@ -693,7 +700,7 @@ class VariableManagerInternal(Serializable):
693
700
  variables[phi] = self._phi_variables[phi]
694
701
  return variables
695
702
 
696
- def input_variables(self, exclude_specials=True):
703
+ def get_variables_without_writes(self) -> List[SimVariable]:
697
704
  """
698
705
  Get all variables that have never been written to.
699
706
 
@@ -703,16 +710,35 @@ class VariableManagerInternal(Serializable):
703
710
  def has_write_access(accesses):
704
711
  return any(acc for acc in accesses if acc.access_type == VariableAccessSort.WRITE)
705
712
 
713
+ input_variables = []
714
+
715
+ for variable, accesses in self._variable_accesses.items():
716
+ if variable in self._phi_variables:
717
+ # a phi variable is definitely not an input variable
718
+ continue
719
+ if not has_write_access(accesses):
720
+ input_variables.append(variable)
721
+
722
+ return input_variables
723
+
724
+ def input_variables(self, exclude_specials: bool = True):
725
+ """
726
+ Get all variables that have never been written to.
727
+
728
+ :return: A list of variables that are never written to.
729
+ """
730
+
706
731
  def has_read_access(accesses):
707
732
  return any(acc for acc in accesses if acc.access_type == VariableAccessSort.READ)
708
733
 
709
734
  input_variables = []
710
735
 
711
- for variable, accesses in self._variable_accesses.items():
736
+ for variable in self._variables_without_writes:
712
737
  if variable in self._phi_variables:
713
738
  # a phi variable is definitely not an input variable
714
739
  continue
715
- if not has_write_access(accesses) and has_read_access(accesses):
740
+ accesses = self._variable_accesses[variable]
741
+ if has_read_access(accesses):
716
742
  if not exclude_specials or not variable.category:
717
743
  input_variables.append(variable)
718
744
 
angr/misc/bug_report.py CHANGED
@@ -1,4 +1,4 @@
1
- import imp
1
+ import importlib
2
2
  import os
3
3
  import sys
4
4
  import datetime
@@ -41,7 +41,7 @@ def print_versions():
41
41
  for m in angr_modules:
42
42
  print("######## %s #########" % m)
43
43
  try:
44
- _, python_filename, _ = imp.find_module(m)
44
+ python_filename = importlib.util.find_spec(m).origin
45
45
  except ImportError:
46
46
  print("Python could not find " + m)
47
47
  continue
angr/sim_type.py CHANGED
@@ -498,6 +498,52 @@ class SimTypeChar(SimTypeReg):
498
498
  return self.__class__(signed=self.signed, label=self.label)
499
499
 
500
500
 
501
+ class SimTypeWideChar(SimTypeReg):
502
+ """
503
+ SimTypeWideChar is a type that specifies a wide character (a UTF-16 character).
504
+ """
505
+
506
+ _base_name = "char"
507
+
508
+ def __init__(self, signed=True, label=None):
509
+ """
510
+ :param label: the type label.
511
+ """
512
+ SimTypeReg.__init__(self, 16, label=label)
513
+ self.signed = signed
514
+
515
+ def __repr__(self):
516
+ return "wchar"
517
+
518
+ def store(self, state, addr, value):
519
+ self._size = state.arch.byte_width
520
+ try:
521
+ super().store(state, addr, value)
522
+ except TypeError:
523
+ if isinstance(value, bytes) and len(value) == 2:
524
+ value = state.solver.BVV(value[0], state.arch.byte_width)
525
+ super().store(state, addr, value)
526
+ else:
527
+ raise
528
+
529
+ def extract(self, state, addr, concrete=False):
530
+ self._size = state.arch.byte_width
531
+
532
+ out = super().extract(state, addr, concrete)
533
+ if concrete:
534
+ return bytes([out])
535
+ return out
536
+
537
+ def _init_str(self):
538
+ return "{}({})".format(
539
+ self.__class__.__name__,
540
+ ('label="%s"' % self.label) if self.label is not None else "",
541
+ )
542
+
543
+ def copy(self):
544
+ return self.__class__(signed=self.signed, label=self.label)
545
+
546
+
501
547
  class SimTypeBool(SimTypeChar):
502
548
  _base_name = "bool"
503
549
 
@@ -1,4 +1,4 @@
1
- # pylint:disable=abstract-method
1
+ # pylint:disable=abstract-method,wrong-import-position,unused-argument,missing-class-docstring,arguments-differ
2
2
  from typing import Iterable, Tuple, Dict, Any, Optional
3
3
 
4
4
  import claripy
@@ -114,7 +114,6 @@ class MemoryMixin(SimStatePlugin):
114
114
 
115
115
  The ``inspect``, ``events``, and ``key`` parameters are for ``state.solver.Unconstrained``, if it is used.
116
116
  """
117
- pass
118
117
 
119
118
  def _merge_values(self, values: Iterable[Tuple[Any, Any]], merged_size: int, **kwargs) -> Optional[Any]:
120
119
  """
@@ -187,6 +186,7 @@ from .paged_memory.paged_memory_mixin import (
187
186
  )
188
187
  from .paged_memory.privileged_mixin import PrivilegedPagingMixin
189
188
  from .paged_memory.stack_allocation_mixin import StackAllocationMixin
189
+ from .paged_memory.paged_memory_multivalue_mixin import PagedMemoryMultiValueMixin
190
190
  from .paged_memory.pages import *
191
191
 
192
192
  from .slotted_memory import SlottedMemoryMixin
@@ -353,6 +353,7 @@ class MultiValuedMemory(
353
353
  DefaultFillerMixin,
354
354
  MultiValueMergerMixin,
355
355
  PagedMemoryMixin,
356
+ PagedMemoryMultiValueMixin,
356
357
  ):
357
358
  def _default_value(self, addr, size, **kwargs):
358
359
  # TODO: Make _default_value() a separate Mixin
@@ -0,0 +1,63 @@
1
+ from .. import MemoryMixin
2
+
3
+
4
+ class PagedMemoryMultiValueMixin(MemoryMixin):
5
+ """
6
+ Implement optimizations and fast accessors for the MultiValues-variant of Paged Memory.
7
+ """
8
+
9
+ def load_annotations(self, addr: int, size: int, **kwargs):
10
+ if not isinstance(size, int):
11
+ raise TypeError("Need size to be resolved to an int by this point")
12
+
13
+ if not isinstance(addr, int):
14
+ raise TypeError("Need addr to be resolved to an int by this point")
15
+
16
+ pageno, pageoff = self._divide_addr(addr)
17
+
18
+ annotations = set()
19
+
20
+ # fasttrack basic case
21
+ if pageoff + size <= self.page_size:
22
+ page = self._get_page(pageno, False, **kwargs)
23
+ loaded = page.load(
24
+ pageoff,
25
+ size=size,
26
+ page_addr=pageno * self.page_size,
27
+ memory=self,
28
+ cooperate=True,
29
+ **kwargs,
30
+ )
31
+ for _, mos in loaded:
32
+ if isinstance(mos, set):
33
+ for mo in mos:
34
+ annotations.update(mo.object.annotations)
35
+ else:
36
+ annotations.update(mos.object.annotations)
37
+
38
+ else:
39
+ max_pageno = (1 << self.state.arch.bits) // self.page_size
40
+ bytes_done = 0
41
+ while bytes_done < size:
42
+ page = self._get_page(pageno, False, **kwargs)
43
+ sub_size = min(self.page_size - pageoff, size - bytes_done)
44
+ loaded = page.load(
45
+ pageoff,
46
+ size=sub_size,
47
+ page_addr=pageno * self.page_size,
48
+ memory=self,
49
+ cooperate=True,
50
+ **kwargs,
51
+ )
52
+ for _, mos in loaded:
53
+ if isinstance(mos, set):
54
+ for mo in mos:
55
+ annotations.update(mo.object.annotations)
56
+ else:
57
+ annotations.update(mos.object.annotations)
58
+
59
+ bytes_done += sub_size
60
+ pageno = (pageno + 1) % max_pageno
61
+ pageoff = 0
62
+
63
+ return annotations
@@ -275,6 +275,11 @@ class MVListPage(
275
275
 
276
276
  def changed_bytes(self, other: "MVListPage", page_addr: int = None):
277
277
  candidates: Set[int] = super().changed_bytes(other)
278
+ if candidates is not None:
279
+ # using the result from the history tracking mixin as an approximation
280
+ return candidates
281
+
282
+ # slower path
278
283
  if candidates is None:
279
284
  candidates: Set[int] = set()
280
285
  # resort to the slower solution
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: angr
3
- Version: 9.2.75
3
+ Version: 9.2.77
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  Home-page: https://github.com/angr/angr
6
6
  License: BSD-2-Clause
@@ -17,13 +17,13 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: CppHeaderParser
19
19
  Requires-Dist: GitPython
20
- Requires-Dist: ailment ==9.2.75
21
- Requires-Dist: archinfo ==9.2.75
20
+ Requires-Dist: ailment ==9.2.77
21
+ Requires-Dist: archinfo ==9.2.77
22
22
  Requires-Dist: cachetools
23
23
  Requires-Dist: capstone ==5.0.0.post1
24
24
  Requires-Dist: cffi >=1.14.0
25
- Requires-Dist: claripy ==9.2.75
26
- Requires-Dist: cle ==9.2.75
25
+ Requires-Dist: claripy ==9.2.77
26
+ Requires-Dist: cle ==9.2.77
27
27
  Requires-Dist: dpkt
28
28
  Requires-Dist: itanium-demangler
29
29
  Requires-Dist: mulpyplexer
@@ -32,7 +32,7 @@ Requires-Dist: networkx !=2.8.1,>=2.0
32
32
  Requires-Dist: protobuf >=3.19.0
33
33
  Requires-Dist: psutil
34
34
  Requires-Dist: pycparser >=2.18
35
- Requires-Dist: pyvex ==9.2.75
35
+ Requires-Dist: pyvex ==9.2.77
36
36
  Requires-Dist: rich >=13.1.0
37
37
  Requires-Dist: rpyc
38
38
  Requires-Dist: sortedcontainers